You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -162,11 +162,11 @@ A struct `xps_http_req_s` is introduced, which stores the information retrieved
162
162
-`header_len`: Stores the length of the headers section.
163
163
-`body_len`: Stores the length of the body, if any.
164
164
165
-
The HTTP requset to be parsed would be present in a buffer. The start and end fields for each component stores pointers marking the beginning and ending of that component in this buffer. For eg: `request_line_start` and `request_line_end` are pointers marking the start and end of the request line in the buffer.
165
+
The HTTP request to be parsed will be present in the corresponding pipe. It is then copied into a user space buffer (and later cleared from the pipe) by the session module. This buffer is then passed onto `xps_http_req` module for parsing the request. From this module, we then invoke the functions in `xps_http` module to set the start and end fields of each component of the request (such as `request_line_start` and `request_line_end`) in the `xps_http_req_s` struct. For eg: `request_line_start` and `request_line_end` are pointers marking the start and end of the request line in the user space buffer.
166
166
167
-
By maintaining specific pointers to different sections of the HTTP request (like the start and end of the method, URI, and headers), the structure allows efficient access and manipulation of the request data without needing to copy or modify the raw input buffer unnecessarily.
167
+
By maintaining specific pointers to different sections of the HTTP request (like the start and end of the method, URI, and headers), the struct `xps_http_req_s` allows efficient access and manipulation of the request data without needing to copy or modify the raw input buffer unnecessarily.
168
168
169
-
We would be completing this module after implementation of the parsing functions, thus now we would be looking into the `xps_http` module.
169
+
We would be completing `xps_http_req` module after implementation of the parsing functions present in the `xps_http` module discussed below.
Following enumerations are available in the above header file:
282
282
283
283
-`xps_http_method_t`: defines the supported HTTP methods(eg: GET, POST, etc)
284
-
-`xps_http_status_code_t`: \*\*\*\*defines various HTTP status codes that the server can respond with.
284
+
-`xps_http_status_code_t`: defines various HTTP status codes that the server can respond with.
285
285
-`xps_http_parser_state_t`: defines the different states of the HTTP request parsing process, split into two main sections: request line states and header states. Each of these states would be explained in detail while implementing the parsing functions.
286
286
287
287
### `xps_http.c`
@@ -305,13 +305,13 @@ Let us go through each of the parsing functions separately.
305
305
306
306
-**`xps_http_parse_request_line()`**
307
307
308
-
Parses a single HTTP request line from a buffer, extracting various components such as the HTTP method, URI, host, port, and HTTP version. It also verifies the request line is of a valid format(i.e follows RFC conventions). `http_req` is a pointer to a structure where parsed information will be stored. `buff` is a pointer to a buffer containing the request data to be parsed. Let us take an example for demonstrating request line parsing. Consider a request line:
308
+
Parses a single HTTP request line from the user buffer (copied from pipe), extracting various components such as the HTTP method, URI, host, port, and HTTP version. It also verifies the request line is of a valid format(i.e follows RFC conventions). `http_req` is a pointer to a structure where parsed information will be stored. `buff` is a pointer to the user space buffer onto which data is copied from pipe. Let us take an example for demonstrating request line parsing. Consider a request line:
309
309
310
310
```
311
311
GET http://localhost:8080/path/to/resource HTTP/1.1
312
312
```
313
313
314
-
At the end of the parsing, the start and end pointers for each of the components in the `buff` would be assigned, thus enabling us to make following inferences:
314
+
At the end of the parsing, the start and end pointers for each of the component in `buff` would be set in `xps_http_req_s` struct, thus enabling us to make following inferences:
315
315
316
316
```
317
317
Method: GET
@@ -553,11 +553,77 @@ GET http://example.com/index.html HTTP/1.1
553
553
- Similarly, try tracing the states for two request line examples provided earlier.
554
554
:::
555
555
556
-
Once the request line parsing is done, we would start the request headers pasring.
556
+
557
+
**Example** - Consider the following HTTP request:
558
+
559
+
```
560
+
GET /index.html HTTP/1.1
561
+
Host: example.com
562
+
Content-Type: text/html
563
+
Content-Length: 123
564
+
```
565
+
566
+
Once the request line parsing is done, the structure would take the following form:
567
+
568
+
Deserialized structure:
569
+
570
+
```c
571
+
xps_http_req_s http_req = {
572
+
method: "GET"
573
+
uri: "/index.html"
574
+
schema: "HTTP"
575
+
version: "1.1"
576
+
headers: [
577
+
/* To be filled when header parsing is done */
578
+
]
579
+
}
580
+
```
581
+
From here, we move on to populate the headers part of the structure.
557
582
558
583
-**`xps_http_parse_header_line()`**
559
584
560
-
Parse a single line of an HTTP header from a buffer. It also verifies the header is of a valid format. `http_req` holds the current state of the HTTP request parsing, such as the parser state. The start and end of parsed header key and value are to be stored in this struct. `buff` is a pointer to an the buffer with the HTTP header data which has to be parsed.
585
+
A single invocation of this function would populate the header part of the structure as shown below.
586
+
587
+
```c
588
+
xps_http_req_s http_req = {
589
+
method: "GET"
590
+
uri: "/index.html"
591
+
schema: "HTTP"
592
+
version: "1.1"
593
+
headers: [
594
+
{
595
+
key: "Host"
596
+
value: "example.com"
597
+
},
598
+
]
599
+
}
600
+
```
601
+
602
+
For the above example, three invocations of this function would be required to populate the header section of the structure to the final form as shown below.
603
+
604
+
```c
605
+
xps_http_req_s http_req = {
606
+
method: "GET"
607
+
uri: "/index.html"
608
+
schema: "HTTP"
609
+
version: "1.1"
610
+
headers: [
611
+
{
612
+
key: "Host"
613
+
value: "example.com"
614
+
},
615
+
{
616
+
key: "Content-Type"
617
+
value: "text/html"
618
+
},
619
+
{
620
+
key: "Content-Length"
621
+
value: "123"
622
+
}
623
+
]
624
+
}
625
+
```
626
+
**`xps_http_parse_header_line()`** parses a single line of an HTTP header from a buffer and populates the header section of the `xps_http_req_s` struct. It also verifies the header is of a valid format. `http_req` holds the current state of the HTTP request parsing, such as the parser state. The start and end of parsed header key and value are to be stored in this struct. `buff` is a pointer to an the buffer with the HTTP header data which has to be parsed.
561
627
562
628
Similar to request line parsing, here also the function goes through the buffer character by character and uses a state machine to determine how to process each character based on the current parsing state.
563
629
@@ -650,7 +716,16 @@ Let us look into the states in header parsing:
650
716
651
717
:::
652
718
653
-
Let us walk through an example, the headers be as given below:
719
+
Let us walk through another example, consider the following HTTP request.
- Try to do a case insensitivecomparison of key in the above function.
788
+
- HTTP is case insensitive. Modify the code such that the comparison handles input key in a case insensitive way.
714
789
:::
715
790
716
791
- **`xps_http_serialize_headers()`**
717
792
718
-
Serialize a list of HTTP headers(key-value pairs) into a buffer. The serialized headers will be formatted as a string, where each header is in the format - key: value\n. The function `sprintf` is used to format and store a string into a character buffer. For header size, along with size of key and value, a +5 is added to account for the colon (`:`), space ( ``), newline (`\n`), and null terminator (`\0`).
793
+
Serialize a list of HTTP headers(key-value pairs) into a buffer. The serialized headers will be formatted as a string, where each header is in the format - key: value\n. The function `sprintf` is used to format and store a string into a character buffer.
794
+
For each key value pair (eg. given below), an additional size of +5 characters are added to account for the colon (`:`), space (` `), newline (`\r\n`), and null terminator (`\0`).
795
+
796
+
For example consider the HTTP Request
797
+
798
+
```
799
+
GET /index.html HTTP/1.1
800
+
Host: example.com
801
+
Content-Type: text/html
802
+
Content-Length: 123
803
+
```
804
+
805
+
Deserialized structure:
806
+
807
+
```c
808
+
xps_http_req_s http_req = {
809
+
method: "GET"
810
+
uri: "/index.html"
811
+
schema: "HTTP"
812
+
version: "1.1"
813
+
headers: [
814
+
{
815
+
key: "Host"
816
+
value: "example.com"
817
+
},
818
+
{
819
+
key: "Content-Type"
820
+
value: "text/html"
821
+
},
822
+
{
823
+
key: "Content-Length"
824
+
value: "123"
825
+
}
826
+
]
827
+
}
828
+
```
829
+
830
+
831
+
The above key-value pair of headers can be serialized as follows:
We could have copied the request from the original buffer instead of serializing the de-serialized struct. But we are serializing the de-serialized structure so that when we send a header from client to upstream we have full control (are able to do our own modification) of the request that get passed.
743
-
859
+
The functions `xps_http_parse_request_line()` and `xps_http_parse_header_line()` convert the HTTP request line and headers to de-serialized form and store the contents in the `xps_http_req_s` structure. Subsequently,
860
+
the `xps_http_serialize_headers()` function extracts the data from this structure and serializes it back to a single string. The reason for doing such a complicated process is that we will need to make changes to the HTTP request received from the client before forwarding it to the upstream sever. (This will be discussed in subsequent stages.) The required modifications are done on the de-serialized `xps_http_req_s` structure before serializing the modified request back into a string and forwarding the request to the upstream server.
744
861
:::
745
862
746
863
Now we would be completing the `xps_http_req` module.
Creates a new HTTP request object, processes the request line and headers, and sets up the request structure. The initial parser state is `RL_START`, indicating the starting of request line parsing. `buff` is the input buffer holding the HTTP request data which has to be parsed.
967
+
Reads the raw HTTP request data from `buff`, creates an `xps_http_req_t` structure to hold the deserialized data, populates it by processing the request line and headers as discussed above, and returns the structure. The parser state is initialized to `RL_START` before processing begins.
851
968
852
969
```c
853
970
xps_http_req_t *xps_http_req_create(xps_core_t *core, xps_buffer_t *buff, int *error) {
Now we have implemented the modules required for parsing HTTP request. We have to make changes in `xps_session` module as the server now acts only as a file server and upstream functionality is not implemented in the present stage as discussed earlier.
1003
+
Now we have implemented the modules required for parsing HTTP request. We have to make changes in `xps_session` module as the server now acts only as a file server, and upstream functionality is not implemented in the present stage as discussed earlier.
0 commit comments