Skip to content

Commit 3875e97

Browse files
authored
Merge pull request #31 from Shibin-Ez/master
changes to stage14
2 parents 809a24d + 101366e commit 3875e97

2 files changed

Lines changed: 145 additions & 17 deletions

File tree

docs/roadmap/phase-1/stage-10.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,19 @@ void xps_connection_destroy(xps_connection_t *connection) {
619619
...
620620
}
621621
622+
void connection_source_handler(void *ptr) {
623+
...
624+
625+
/* update the recv() function parameter to limit the data read upto pipe threshold limit*/
626+
/* hint: use minimum of current buffer size and diffrence between DEFAULT_PIPE_BUFF_THRESH and pipe's current size */
627+
int read_n = recv(connection->sock_fd, buff->data, /*fill this*/, 0);
628+
buff->len = read_n;
629+
630+
...
631+
}
632+
622633
void connection_loop_read_handler(void *ptr) {
623-
..
634+
...
624635
/*ready flag of source*/ = true;
625636
}
626637

docs/roadmap/phase-2/stage-14.md

Lines changed: 133 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ A struct `xps_http_req_s` is introduced, which stores the information retrieved
162162
- `header_len`: Stores the length of the headers section.
163163
- `body_len`: Stores the length of the body, if any.
164164

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.
166166

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.
168168

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.
170170

171171
## `xps_http` Module
172172

@@ -281,7 +281,7 @@ xps_buffer_t *xps_http_serialize_headers(vec_void_t *headers);
281281
Following enumerations are available in the above header file:
282282

283283
- `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.
285285
- `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.
286286

287287
### `xps_http.c`
@@ -305,13 +305,13 @@ Let us go through each of the parsing functions separately.
305305

306306
- **`xps_http_parse_request_line()`**
307307

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:
309309

310310
```
311311
GET http://localhost:8080/path/to/resource HTTP/1.1
312312
```
313313

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:
315315

316316
```
317317
Method: GET
@@ -553,11 +553,77 @@ GET http://example.com/index.html HTTP/1.1
553553
- Similarly, try tracing the states for two request line examples provided earlier.
554554
:::
555555
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.
557582

558583
- **`xps_http_parse_header_line()`**
559584

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.
561627

562628
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.
563629

@@ -650,7 +716,16 @@ Let us look into the states in header parsing:
650716
651717
:::
652718
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.
720+
721+
```c
722+
GET /index.html HTTP/1.1
723+
Host: example.com
724+
Content-Type: text/html
725+
Content-Length: 123
726+
```
727+
728+
The headers are as given below:
654729

655730
```c
656731
Host: example.com
@@ -710,19 +785,61 @@ const char *xps_http_get_header(vec_void_t *headers, const char *key) {
710785
711786
::: tip TRY
712787
713-
- Try to do a case insensitive comparison 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.
714789
:::
715790
716791
- **`xps_http_serialize_headers()`**
717792
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:
832+
833+
```json
834+
Host: example.com\r\nContent-Type: text/html\r\nContent-Length: 123\r\n
835+
```
719836

720837
```c
721838
xps_buffer_t *xps_http_serialize_headers(vec_void_t *headers) {
722839
/*assert*/
723840
/*create a buffer and initialize first byte to null terminator*/
724841
for (/*traverse through headers*/) {
725-
/*get required length to store a header*/
842+
/*get required length to store a header*/
726843
char header_str[header_str_len];
727844
sprintf(header_str, "%s: %s\n", header->key, header->val);
728845
if ((buff->size - buff->len) < header_str_len) { //buffer is small
@@ -739,8 +856,8 @@ xps_buffer_t *xps_http_serialize_headers(vec_void_t *headers) {
739856
740857
:::tip NOTE
741858
742-
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.
744861
:::
745862
746863
Now we would be completing the `xps_http_req` module.
@@ -847,7 +964,7 @@ xps_buffer_t *xps_http_req_serialize(xps_http_req_t *http_req) {
847964
848965
- **`xps_http_req_create()`**
849966
850-
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.
851968
852969
```c
853970
xps_http_req_t *xps_http_req_create(xps_core_t *core, xps_buffer_t *buff, int *error) {
@@ -883,7 +1000,7 @@ void xps_http_req_destroy(xps_core_t *core, xps_http_req_t *http_req) {
8831000
}
8841001
```
8851002
886-
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.
8871004
8881005
## `xps_session` Module - Modifications
8891006

0 commit comments

Comments
 (0)