otarza / serv-cst

CST web III porject
6 stars 0 forks source link

Request Line Parsing #8

Closed ioseb closed 11 years ago

ioseb commented 11 years ago

მიღებული HTTP მოთხოვნის საწყისი სტრიქონის(Request Line: იხ. http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21#section-3.1.1) წაკითხვა.

სავარაუდო ტესტები:

"GET /test HTTP/1.1\r\n"
"GET /favicon.ico HTTP/1.1\r\n"
"GET /dumbfuck HTTP/1.1\r\n"
"GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n"
"GET /get_no_headers_no_body/world HTTP/1.1\r\n"
"GET /get_one_header_no_body HTTP/1.1\r\n"
"GET /get_funky_content_length_body_hello HTTP/1.0\r\n"
"POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n"
"POST /post_chunked_all_your_base HTTP/1.1\r\n"
"POST /two_chunks_mult_zero_end HTTP/1.1\r\n"
"POST /chunked_w_trailing_headers HTTP/1.1\r\n"
"POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
"GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n"
"GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n"
"\r\nGET /test HTTP/1.1\r\n\r\n"
"CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
"REPORT /test HTTP/1.1\r\n"
"M-SEARCH * HTTP/1.1\r\n"
"GET / HTTP/1.1\r\n"
"PATCH /file.txt HTTP/1.1\r\n"
"CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
"GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
"CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"

ყველა ზემოთ ჩამოთვლილი მოთხოვნის სტრიქონის წაკითხვის შემდეგ უნდა შეიქმნას შემდეგი კლასის ობიექტი:

package edu.cst.webserver.http;

import edu.cst.webserver.http.HttpMethod.Type;

public class HttpRequestLine {
    private HttpMethod.Type method;
    private String requestUri;
    private String path;
    private String queryString;
    private String fragment;
    private String httpVersion;

    public Type getMethod() {
        return method;
    }

    public void setMethod(HttpMethod.Type method) {
        this.method = method;
    }

    public String getRequestUri() {
        return requestUri;
    }

    public void setRequestUri(String requestUri) {
        this.requestUri = requestUri;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getQueryString() {
        return queryString;
    }

    public void setQueryString(String queryString) {
        this.queryString = queryString;
    }

    public String getFragment() {
        return fragment;
    }

    public void setFragment(String fragment) {
        this.fragment = fragment;
    }

    public String getHttpVersion() {
        return httpVersion;
    }

    public void setHttpVersion(String httpVersion) {
        this.httpVersion = httpVersion;
    }
}

საწყისი სტრიქონის წაკითხვის დროს, მეთოდის ამოკითხვის დასრულების შემდეგ:

პარსერის კლასი რომელმაც უნდა დააბრუნოს ზემოთ ნაჩვენები კლასის ობიექტი:

package edu.cst.webserver.http;

public class HttpRequestLineParser {
    // Restrict direct parser instantiation
    private HttpRequestLineParser() { }

    // TODO implement request line parsing logic
    public HttpRequestLine parse(String requestLine) {
        return null;
    }

    public static HttpRequestLineParser newInstance() {
        return new HttpRequestLineParser();
    }
}

გამოყენების ნიმუში:

HttpRequestLineParser parser = HttpRequestLineParser.newInstance();
HttpRequestLine requestLine = parser.parse("GET /path/to/resource?param=value HTTP/1.1");
ioseb commented 11 years ago

@revazi რა ხდება? როდის აპირებ საქმის დაწყებას? თუ მე დაგიწერო?

revazi commented 11 years ago

@ioseb დღეს დავიწყებ

ioseb commented 11 years ago

@revazi

revazi commented 11 years ago

@ioseb ოკ

ioseb commented 11 years ago

@revazi გვაგვიანებ უკვე.

revazi commented 11 years ago

@ioseb ვცდილობ გავერკვე და იმედია მალე გავაკეთებ

ioseb commented 11 years ago

@revazi Maven პროექტი თუ გამართე?

revazi commented 11 years ago

@ioseb კიი. კოდზე ვფიქრობ

ioseb commented 11 years ago

@revazi

ასე მივუდგეთ საკითხს. ზედმეტი დრო რომ არ დაიხარჯოს მე დაგისვამ შეკითხვებს და შენ დამიფიქსირე რა გესმის და როგორ გესმის და რა არ გემის:

ამ შეკითხვებიდან რომელიმეზე თუ არ გაქვს პასუხი კოდის წერაზე ფიქრი ნაადრევია.

revazi commented 11 years ago

@ioseb 1) გასაგებია public class HttpRequestLine ეს კლასი თავისი მეთდებით აკეთებს Request - ის ნაწილების ცალ-ცალკე setter & getter მეთოდების აღწერას სადაც set-პრეფიქსით დაწყებულ მეთოდებს ჩვენ უნდა გადავცეთ წინასწარ დამუშავებული Request-ის ნაწილები მაგ. Path, Query, MethodType... 2) ამის უკეთ განმარტება მჭირდება ალბათ. 3) მოთხოვნის სტრიქონებში კანონქომიერება ის არის რომ მოთხოვნის ტიპი გამოყოფილია მოთხოვნისგან space-ით შემდეგ მოთხოვნაა ყველგან და შემდეგ ისევ space-ით გამოყოფილი HTTP-ის ვერსია თუმცა "\r\nGET /test HTTP/1.1\r\n\r\n" ამაზე ორი სიტყვით მითხარი. 4) წავიკითხე და გავიგე რომ მოთხოვნის სტრიქონის შემდეგ შაბლონს იყენებს request-line = method SP request-target SP HTTP-version CRLF

ioseb commented 11 years ago

@revazi

  1. ამას ვგულისხმობდი "GET /test HTTP/1.1\r\n" ანუ ნიმუშებს ზოგადად;
  2. დავაზუსტოთ: ა) HTTP მეთოდის სახელი; ბ) path(მარშრუტი) გ) HTTP ვერსია. მნიშვნელოვანია რომ ყველაფერს სწორად დაარქვა სახელი. "\r\n" ნიშნავს ახალი ხაზის სიმბოლოს ანუ CRLF(Carriage Return & Line Feed).
  3. SP(space, ჰარი) შეგიძლია ჩათვალო რომ 1..N რაოდენობის არის.

ალგორითმი მარტივად რომ ვთქვათ ასეთია:

გასაგებია ეს ყველაფერი?

ioseb commented 11 years ago

@revazi

დასაწყისისთვის გთავაზობ ასეთ რამეს:

package edu.cst.webserver.http;

import junit.framework.Assert;
import org.junit.Test;

public class HttpRequestLineParserTest {
    private static final String HTTP_VERSION = "HTTP/1.1";
    @Test
    public void testRequestLine0() {
        HttpRequestLineParser parser = HttpRequestLineParser.newInstance();
        String requestLineString = "GET /test HTTP/1.1\\r\\n";
        HttpRequestLine requestLine = parser.parse(requestLineString);

        Assert.assertEquals(HttpMethod.METHOD_GET, requestLine.getMethodName());
        Assert.assertEquals("/test", requestLine.getPath());
        Assert.assertEquals(HTTP_VERSION, requestLine.getHttpVersion());
    }
}

რომელიც გაშვების შემდეგ თავისთავად ცხადია ტესტირების შეცდომებს გამოიწვევს. შეეცადე .parse() მეთოდი მიიყვანო იქამდე რომ მხოლოდ ეს ერთი ტესტი გაიაროს. როდესაც ამას მიაღწევ დაამატე ახალი ტესტები ჩემს პირველ პოსტში მოყვანილი ყველა მოთხოვნის სტრიქონისთვის და გატესტე სხვადასხვა ნაწილები.

@reflooding @demonno მიეხმარეთ უნიტ ტესტინგში.

ioseb commented 11 years ago

@revazi

ეს ამოცანა რომ გავამარტივოთ:

ესე გასაგებია?

demonno commented 11 years ago

კონფიგურაციის კლასის გამოყენება ძალიან მარტივია

მაგალითისთვის რომ შევამოწმოთ მხარდაჭერილია თუ არა GET მეთოდი , უნდა დავწეროთ შემდეგი :

ServerConfig config = ServerConfig.getInstance();
config.isSupportedMethod("GET");

დადებითი პასუხის შემტხვევაში დაგვიბრუნდება ბულის ტიპის მნიშვნელობა true , უარყოფითის შემთხვევაში ბულის ტიპის მნიშვნელობა false

revazi commented 11 years ago

@ioseb გასაგებია. წავყვები ყველაფერს რაც დამიწერე და გავაკეთებ

ioseb commented 11 years ago

@revazi ვნახე შენი კომიტი. ჯერ ძალიან ნედლია მაგრამ სტილისტური შენიშვნა მაქვს. გამხსნელი ფიგურული ფრჩხილები აიტანე იმავე ხაზზე სადაც იწყება ბლოკი. სხვების კოდსაც შეხედე.

არასწორია:

if (condition)
{
  // code here...
}

სწორია:

if (condition) {
  // code here...
}
revazi commented 11 years ago

@ioseb გავითვალისწინებ, შევასწორებ და ამაღამ კოდსაც დავამატებ კიდევ.

ioseb commented 11 years ago

@revazi აქ კომენტარები რომ დაგიწერე არ გამოგრჩეს: https://github.com/reflooding/serv-cst/commit/cb8052f81ee7b7aaa8494e89fc4b3c5e0c4dbb64

revazi commented 11 years ago

@ioseb ვნახე და მივხედავ

ioseb commented 11 years ago

@revazi არის რამე პროგრესი?

revazi commented 11 years ago

@ioseb HttpRequestLineParser() - ში მიმითითე რა უნდა გავაკეთო.

ioseb commented 11 years ago

@revazi მეტი რა უნდა მიგითოთ? ამ თიქეთში უამრავი რამე დავწერე და კოდში კომენტარებიც დაგიწერე. კონკრეტულად რა გაინტერესებს?

ioseb commented 11 years ago

@revazi თუ არ გამოგდის და არ გცალია თქვი და სხვას გადავულოცავ ამ დავალებას. არ არის ეს საქმე როდესაც მოლოდინი მაქვს რომ გააკეთებ რაღაცას დღეების მანძილზე არ ჩანხარ და ისეთ კოდს ტოვებ რეპოში რომელიც არათუ არ მუშაობს, არც კი კომპილირდება. ელ.ფოსტა ხშირად გადაამოწმე და მოწერილს უპასუხე.

revazi commented 11 years ago

@ioseb ვცდილობ რომ გავარჩიო და ვცდილობ გავერკვე regex-ის გამოყენებაში java-ში. private HttpRequestLineParser() { } ამაზე მაინტერესებდა parse - მეთოდის დასრულების მერე როგორ უნდა გამომეყენებინა.

ioseb commented 11 years ago

@revazi არ გეწყინოს მაგრამ ან მეკაიფები ან არ კითხულობ რას ვწერ. ამონარიდები პირველი პოსტიდან:

აი ასეთია გამოყენება:

HttpRequestLineParser parser = HttpRequestLineParser.newInstance();
HttpRequestLine requestLine = parser.parse("GET /path/to/resource?param=value HTTP/1.1");
  1. დავაზუსტოთ: ა) HTTP მეთოდის სახელი; ბ) path(მარშრუტი) გ) HTTP ვერსია. მნიშვნელოვანია რომ ყველაფერს სწორად დაარქვა სახელი. "\r\n" ნიშნავს ახალი ხაზის სიმბოლოს ანუ CRLF(Carriage Return & Line Feed).
  2. SP(space, ჰარი) შეგიძლია ჩათვალო რომ 1..N რაოდენობის არის.

ალგორითმი მარტივად რომ ვთქვათ ასეთია:

გასაგებია ეს ყველაფერი?

ის რეგულარული გამოსახულება რაც მანდ დაგჭირდება თავი ბოლო ეს არის:

String[] tokens = requestLine.trim().split("\\s+");

თუმცა ვისურვებდი რომ ცოტა უფრო კრეატიული ყოფილიყავი და რეგულარული გამოსახულების გარეშე დაგეძლია ეს ამოცანა. დანარჩენი რაც კოდის კომენტარებში დავწერე ისიც გადაიკითხე.

არაფერი არსებითი გასარკვევი არ გაქვს. და იმის ნაცვლად რომ დრო ხარჯო და შეგვაფერხო უმჯობესი იქნება თუ:

revazi commented 11 years ago

@ioseb ok Sorry.

HTTP - ს რაც შეეხება ვერ ვნახე isSupportedMethod მსგავსი მეთოდი HTTP - ის ვერსიისთვის

ioseb commented 11 years ago

@revazi "Sorry" არ მიიღება. თუ ვერ ნახე:

if (!httpMethod.equals("HTTP/1.1")) {
    // rest of code here...
}

სადაც httpMethod არის შენი ცვლადი.

ასე ვერ იზამდი?

revazi commented 11 years ago

ვიზამდი მაგრამ მეგონა რომ სხვას უნდა დაეწერა.

ioseb commented 11 years ago

@revazi თავს იმართლებ და თან ძალიან არაეფექტურად :D :D :D საქმეს მიხედე, თუ არ გცალია თქვი. რომ "გეგონა" ვერ თქვი მერე? ან ვისზეც გეგონა რატომ არ შეახსენე?

revazi commented 11 years ago

@ioseb ოხ არ ვიმართლებ თავს. სხვის კოდებში ხელები არ აფათუროთო და რაღაცები და მგონია რომ მარტო ჩემათ რაც არის ნათქვამი იმაში უნდა ვწერო.

ioseb commented 11 years ago

@revazi

  1. ვინმე(ან რამე) თუ გაფერხებს უნდა თქვა;
  2. თუ არ იცი ვინ გაფერხებს მომმართე მე;
  3. თუ რამე არ არის კოდში შეგიძლია დროებით გააკეთო შენი ლოკალიზებული რეალიზაცია და დააწერო კომენტარი რომ მოგვიანებით ჩავანაცვლებთ ამითი და ამითი და ა.შ.

საქმეს მივხედოთ, ვფერხდებით აშკარად.

revazi commented 11 years ago

@ioseb ხო. ახლა გასაგებია

ioseb commented 11 years ago

@revazi დაგიმატე დავალება და შენვე ჩაამატე #19

revazi commented 11 years ago

@ioseb დავამატე და ტესტებიც დავუწერე. Recipients of an invalid request-line SHOULD respond with either a 400 (Bad Request) error შეკითხვა: შევამოწმო URI Whitespace-ებზე?

ioseb commented 11 years ago

@revazi ძალიან კარგი. არა, URI შენ არ უნდა შეამოწმო მაგაზე(ჯერ). ანუ როდესაც იმ სტრიქონს გახლიჩავ უნდა მიიღო 3 ნაწილი. თუ მეტი/ან ნაკლები მიიღე თავისთავად არასწორია უკვე. იმ შემთხვევაში თუ მაინც 3 ნაწილი მიიღე და პირველი ორი ნაწილი სწორია, მესამე ნაწილი არ გამოვა სწორი და შეცდომაა(ანუ exception უნდა ისროლო) და თუ სამივე ნაწილი სწორია ესე იგი ყველაფერი კარგად არის.

ioseb commented 11 years ago

@revazi

Recipients of an invalid request-line SHOULD respond with either a 400 (Bad Request) error

ამ შემთხვევაში შენ უბრალოდ აკეთებ ასეთ რამეს:

throw new HttpRequestException(HttpStatus.Code.BAD_REQUEST)

მეტი არაფერი გევალება.

revazi commented 11 years ago

ეგ მიწერია მაშინ როცა request-line_ის space-ებით გამოყოფილი ნაწილების რაოდენობა არ უდრის 3ს. parts = requestLineString.split("\s+"); if (parts.length != 3){ throw new HttpRequestException(HttpStatus.Code.BAD_REQUEST); }

ioseb commented 11 years ago

შესაბამისად აღარ არის საჭირო URI - ს შემოწმება. გარდა ამისა მნიშვნელოვანი რაოდენობის უნიტ ტესტები გაქვს დასაწერი(იხ. დისკუსიის პირველი პოსტი) და გამოვავლნეთ ხარვეზებს როგორმე.

On Sunday, March 3, 2013 at 7:41 PM, Revaz wrote:

ეგ მიწერია მაშინ როცა request-line_ის space-ებით გამოყოფილი ნაწილების რაოდენობა არ უდრის 3ს. parts = requestLineString.split("\s+"); if (parts.length != 3){ throw new HttpRequestException(HttpStatus.Code.BAD_REQUEST); }

— Reply to this email directly or view it on GitHub (https://github.com/reflooding/serv-cst/issues/8#issuecomment-14348641).

revazi commented 11 years ago

ახლა ვიწყებ ტესტებზე მუშაობას უბრალოდ ერთი რაც მინდოდა კიდევ HttpRequestLine requestLine = parser.parse("GET /path/to/resource?param=value HTTP/1.1"); <<< ამაზე მიწერს incompetible types და parse მეთოდიდან String-ი არ უნდა დავაბრუნო. როგორ დავაბრუნო parse მეთდიდან HttpRequestLine ტიპის ობიექტი?

ioseb commented 11 years ago

@revazi სტრიქონი არ უნდა დააბურნო.

HttpRequestLine requestLine = new HttpRequestLine();
requestLine.setHttpVersion(httpVersion);
requestLine.setQueryString(queryString);
requestLine.setFragment(fragment);
requestLine.setPath(path);
requestLine.setMethod(HttpMethod.getHttpMethodByname(methodName));

return requestLine;

სადაც: httpVersion, path, queryString, fragment, methodName შენი ცვლადებია. ამ ცვლადებიდან:

როდესაც უკვე გაქვს URI სტრიქონი უნდა გააკეთო ასე:

makes sense?

revazi commented 11 years ago

აქედან მარტო ეს მინდოდა: HttpRequestLine requestLine = new HttpRequestLine(); requestLine. setHttpVersion(httpVersion); requestLine.setQueryString(queryString); requestLine.setFragment(fragment); requestLine.setPath(path); requestLine.setMethod(HttpMethod.getHttpMethodByname(methodName));

return requestLine;

დანარჩენი ვეცადე ისე გამეკეთებინა და რაღაც კოდი უკვე დავწერე. ვვარაუდობდი ასე მაგრამ ვერ გავავწყვიტე set-მეთოდების ამბავი. ახლა გასაგებია.

ioseb commented 11 years ago

ოკეი, ველოდები რეზულტატს.

revazi commented 11 years ago

we don't have Httpmethod.getHttpMethodByname();

ioseb commented 11 years ago

yes we have. https://github.com/reflooding/serv-cst/blob/master/src/main/java/edu/cst/webserver/http/HttpMethod.java

it's name is: getMethodByName(). source is available and please do not be so lazy and look sometimes inside others work.

On Sunday, March 3, 2013 at 8:14 PM, Revaz wrote:

we don't have
Httpmethod.getHttpMethodByname();

— Reply to this email directly or view it on GitHub (https://github.com/reflooding/serv-cst/issues/8#issuecomment-14349157).

revazi commented 11 years ago

ჩავიხედე რა უხ.

ioseb commented 11 years ago

ნუ ღელავ და საქმეს მიხედე :P თუ ჩაიხედე რატომ ვერ იპოვე?

On Sunday, March 3, 2013 at 8:18 PM, Revaz wrote:

ჩავიხედე რა უხ.

— Reply to this email directly or view it on GitHub (https://github.com/reflooding/serv-cst/issues/8#issuecomment-14349229).

revazi commented 11 years ago

რავიცი ნორმალურად არ ჩავიხედე. My fault.

ioseb commented 11 years ago

კარგია :D შედეგი დაიდოს ხარისხიანი!

revazi commented 11 years ago

ცოტაც მაცადე Boss

ioseb commented 11 years ago

მთავარია დამანახეთ რომ მუშაობთ, სხვაგან მე არსად არ მეჩქარება.

On Sunday, March 3, 2013 at 8:22 PM, Revaz wrote:

ცოტაც მაცადე Boss

— Reply to this email directly or view it on GitHub (https://github.com/reflooding/serv-cst/issues/8#issuecomment-14349316).