Process FastCGI header fields
This commit is contained in:
		
							
								
								
									
										33
									
								
								src/client.c
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								src/client.c
									
									
									
									
									
								
							| @@ -87,9 +87,11 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | ||||
|         } else if (ret == 2) { | ||||
|             sprintf(err_msg, "Unable to parse header: Invalid method."); | ||||
|         } else if (ret == 3) { | ||||
|             sprintf(err_msg, "Unable to parse header: Invalid version"); | ||||
|             sprintf(err_msg, "Unable to parse header: Invalid version."); | ||||
|         } else if (ret == 4) { | ||||
|             sprintf(err_msg, "Unable to parse header: Header contains illegal characters"); | ||||
|             sprintf(err_msg, "Unable to parse header: Header contains illegal characters."); | ||||
|         } else if (ret == 5) { | ||||
|             sprintf(err_msg, "Unable to parse header: End of header not found."); | ||||
|         } | ||||
|         res.status = http_get_status(400); | ||||
|         goto respond; | ||||
| @@ -235,6 +237,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | ||||
|             if (ret != 0) { | ||||
|                 if (ret < 0) { | ||||
|                     goto abort; | ||||
|                 } else { | ||||
|                     sprintf(err_msg, "Unable to communicate with PHP-FPM."); | ||||
|                 } | ||||
|                 res.status = http_get_status(502); | ||||
|                 goto respond; | ||||
| @@ -243,15 +247,32 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | ||||
|         fastcgi_end: | ||||
|         fastcgi_close_stdin(&php_fpm); | ||||
|  | ||||
|         ret = fastcgi_header(&php_fpm, &res, err_msg); | ||||
|         if (ret != 0) { | ||||
|             if (ret < 0) { | ||||
|                 goto abort; | ||||
|             } else { | ||||
|                 sprintf(err_msg, "Unable to communicate with PHP-FPM."); | ||||
|             } | ||||
|             res.status = http_get_status(502); | ||||
|             goto respond; | ||||
|         } | ||||
|         char *status = http_get_header_field(&res.hdr, "Status"); | ||||
|         if (status != NULL) { | ||||
|             res.status = http_get_status(strtoul(status, NULL, 10)); | ||||
|             http_remove_header_field(&res.hdr, "Status", HTTP_REMOVE_ALL); | ||||
|             if (res.status == NULL){ | ||||
|                 res.status = http_get_status(500); | ||||
|                 sprintf(err_msg, "The status code was set to an invalid or unknown value."); | ||||
|                 goto respond; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding"); | ||||
|         if (accept_encoding != NULL && strstr(accept_encoding, "deflate") != NULL) { | ||||
|             http_add_header_field(&res.hdr, "Content-Encoding", "deflate"); | ||||
|         } | ||||
|  | ||||
|         if (fastcgi_header(&php_fpm, &res, err_msg) != 0) { | ||||
|             goto respond; | ||||
|         } | ||||
|  | ||||
|         content_length = -1; | ||||
|         use_fastcgi = 1; | ||||
|         if (http_get_header_field(&res.hdr, "Content-Length") == NULL) { | ||||
|   | ||||
| @@ -349,7 +349,35 @@ int fastcgi_header(fastcgi_conn *conn, http_res *res, char *err_msg) { | ||||
|     conn->out_len = content_len; | ||||
|     conn->out_off = (unsigned short) (strstr(content, "\r\n\r\n") - content + 4); | ||||
|  | ||||
|     // TODO process headers and add fields to res | ||||
|     char *buf = content; | ||||
|     unsigned short header_len = conn->out_off; | ||||
|     if (header_len <= 0) { | ||||
|         print(ERR_STR "Unable to parse header: End of header not found" CLR_STR); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < header_len; i++) { | ||||
|         if ((buf[i] >= 0x00 && buf[i] <= 0x1F && buf[i] != '\r' && buf[i] != '\n') || buf[i] == 0x7F) { | ||||
|             print(ERR_STR "Unable to parse header: Header contains illegal characters" CLR_STR); | ||||
|             return 2; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     char *ptr = buf; | ||||
|     while (header_len != (ptr - buf)) { | ||||
|         char *pos0 = strstr(ptr, "\r\n"); | ||||
|         if (pos0 == NULL) { | ||||
|             print(ERR_STR "Unable to parse header: Invalid header format" CLR_STR); | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         ret = http_parse_header_field(&res->hdr, ptr, pos0); | ||||
|         if (ret != 0) return ret; | ||||
|         if (pos0[2] == '\r' && pos0[3] == '\n') { | ||||
|             return 0; | ||||
|         } | ||||
|         ptr = pos0 + 2; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
							
								
								
									
										92
									
								
								src/http.c
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								src/http.c
									
									
									
									
									
								
							| @@ -9,14 +9,14 @@ | ||||
| #include "utils.h" | ||||
|  | ||||
|  | ||||
| void http_to_camel_case(char *str, int strict) { | ||||
| void http_to_camel_case(char *str, int mode) { | ||||
|     char last = '-'; | ||||
|     char ch; | ||||
|     for (int i = 0; i < strlen(str); i++) { | ||||
|         ch = str[i]; | ||||
|         if (last == '-' && ch >= 'a' && ch <= 'z') { | ||||
|         if (mode == HTTP_CAMEL && last == '-' && ch >= 'a' && ch <= 'z') { | ||||
|             str[i] = (char) ((int) ch & 0x5F); | ||||
|         } else if (last != '-' && ch >= 'A' && ch <= 'Z' && strict == HTTP_LOWER) { | ||||
|         } else if (mode == HTTP_LOWER && ch >= 'A' && ch <= 'Z') { | ||||
|             str[i] = (char) ((int) ch | 0x20); | ||||
|         } | ||||
|         last = str[i]; | ||||
| @@ -41,8 +41,33 @@ void http_free_res(http_res *res) { | ||||
|     http_free_hdr(&res->hdr); | ||||
| } | ||||
|  | ||||
| int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr) { | ||||
|     char *pos1 = memchr(buf, ':', end_ptr - buf); | ||||
|     char *pos2; | ||||
|     if (pos1 == NULL) { | ||||
|         print(ERR_STR "Unable to parse header: Invalid version" CLR_STR); | ||||
|         return 3; | ||||
|     } | ||||
|  | ||||
|     unsigned long len = pos1 - buf; | ||||
|     hdr->fields[hdr->field_num][0] = malloc(len + 1); | ||||
|     sprintf(hdr->fields[hdr->field_num][0], "%.*s", (int) len, buf); | ||||
|     http_to_camel_case(hdr->fields[hdr->field_num][0], HTTP_CAMEL); | ||||
|  | ||||
|     pos1++; | ||||
|     pos2 = (char *) end_ptr - 1; | ||||
|     while (pos1[0] == ' ') pos1++; | ||||
|     while (pos2[0] == ' ') pos2--; | ||||
|     len = pos2 - pos1 + 1; | ||||
|     hdr->fields[hdr->field_num][1] = malloc(len + 1); | ||||
|     sprintf(hdr->fields[hdr->field_num][1], "%.*s", (int) len, pos1); | ||||
|     hdr->field_num++; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int http_receive_request(sock *client, http_req *req) { | ||||
|     ssize_t rcv_len, len; | ||||
|     unsigned long rcv_len, len; | ||||
|     char *ptr, *pos0, *pos1, *pos2; | ||||
|     char buf[CLIENT_MAX_HEADER_SIZE]; | ||||
|     memset(buf, 0, sizeof(buf)); | ||||
| @@ -71,7 +96,13 @@ int http_receive_request(sock *client, http_req *req) { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < rcv_len; i++) { | ||||
|         unsigned long header_len = strstr(buf, "\r\n\r\n") - buf + 4; | ||||
|         if (header_len <= 0) { | ||||
|             print(ERR_STR "Unable to parse header: End of header not found" CLR_STR); | ||||
|             return 5; | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < header_len; i++) { | ||||
|             if ((buf[i] >= 0x00 && buf[i] <= 0x1F && buf[i] != '\r' && buf[i] != '\n') || buf[i] == 0x7F) { | ||||
|                 print(ERR_STR "Unable to parse header: Header contains illegal characters" CLR_STR); | ||||
|                 return 4; | ||||
| @@ -79,9 +110,9 @@ int http_receive_request(sock *client, http_req *req) { | ||||
|         } | ||||
|  | ||||
|         ptr = buf; | ||||
|         while (rcv_len != (ptr - buf)) { | ||||
|             pos0 = memchr(ptr, '\r', rcv_len - (ptr - buf)); | ||||
|             if (pos0 == NULL || pos0[1] != '\n') { | ||||
|         while (header_len != (ptr - buf)) { | ||||
|             pos0 = strstr(ptr, "\r\n"); | ||||
|             if (pos0 == NULL) { | ||||
|                 print(ERR_STR "Unable to parse header: Invalid header format" CLR_STR); | ||||
|                 return 1; | ||||
|             } | ||||
| @@ -127,26 +158,8 @@ int http_receive_request(sock *client, http_req *req) { | ||||
|                 sprintf(req->uri, "%.*s", (int) len, pos1); | ||||
|                 sprintf(req->version, "%.3s", pos2 + 5); | ||||
|             } else { | ||||
|                 pos1 = memchr(ptr, ':', pos0 - ptr); | ||||
|                 if (pos1 == NULL) { | ||||
|                     print(ERR_STR "Unable to parse header: Invalid version" CLR_STR); | ||||
|                     return 3; | ||||
|                 } | ||||
|  | ||||
|                 len = pos1 - ptr; | ||||
|                 req->hdr.fields[req->hdr.field_num][0] = malloc(len + 1); | ||||
|                 sprintf(req->hdr.fields[req->hdr.field_num][0], "%.*s", (int) len, ptr); | ||||
|                 http_to_camel_case(req->hdr.fields[req->hdr.field_num][0], HTTP_LOWER); | ||||
|  | ||||
|                 pos1++; | ||||
|                 pos2 = pos0 - 1; | ||||
|                 while (pos1[0] == ' ') pos1++; | ||||
|                 while (pos2[0] == ' ') pos2--; | ||||
|                 len = pos2 - pos1 + 1; | ||||
|                 req->hdr.fields[req->hdr.field_num][1] = malloc(len + 1); | ||||
|                 sprintf(req->hdr.fields[req->hdr.field_num][1], "%.*s", (int) len, pos1); | ||||
|  | ||||
|                 req->hdr.field_num++; | ||||
|                 int ret = http_parse_header_field(&req->hdr, ptr, pos0); | ||||
|                 if (ret != 0) return ret; | ||||
|             } | ||||
|             if (pos0[2] == '\r' && pos0[3] == '\n') { | ||||
|                 return 0; | ||||
| @@ -177,12 +190,33 @@ void http_add_header_field(http_hdr *hdr, const char *field_name, const char *fi | ||||
|     char *_field_value = malloc(len_value + 1); | ||||
|     strcpy(_field_name, field_name); | ||||
|     strcpy(_field_value, field_value); | ||||
|     http_to_camel_case(_field_name, HTTP_PRESERVE_UPPER); | ||||
|     http_to_camel_case(_field_name, HTTP_PRESERVE); | ||||
|     hdr->fields[hdr->field_num][0] = _field_name; | ||||
|     hdr->fields[hdr->field_num][1] = _field_value; | ||||
|     hdr->field_num++; | ||||
| } | ||||
|  | ||||
| void http_remove_header_field(http_hdr *hdr, const char *field_name, int mode) { | ||||
|     char field_name_1[256], field_name_2[256]; | ||||
|     strcpy(field_name_1, field_name); | ||||
|     http_to_camel_case(field_name_1, HTTP_LOWER); | ||||
|     for (int i = 0; i < hdr->field_num; i++) { | ||||
|         strcpy(field_name_2, hdr->fields[i][0]); | ||||
|         http_to_camel_case(field_name_2, HTTP_LOWER); | ||||
|         if (strcmp(field_name_1, field_name_2) == 0) { | ||||
|             for (int j = i; j < hdr->field_num - 1; j++) { | ||||
|                 memcpy(hdr->fields[j], hdr->fields[j + 1], sizeof(hdr->fields[0])); | ||||
|             } | ||||
|             hdr->field_num--; | ||||
|             if (mode == HTTP_REMOVE_ONE) { | ||||
|                 return; | ||||
|             } else if (mode == HTTP_REMOVE_ALL) { | ||||
|                 i--; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| int http_send_response(sock *client, http_res *res) { | ||||
|     char buf[CLIENT_MAX_HEADER_SIZE]; | ||||
|     int len = 0; | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/http.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/http.h
									
									
									
									
									
								
							| @@ -8,8 +8,12 @@ | ||||
| #ifndef NECRONDA_SERVER_HTTP_H | ||||
| #define NECRONDA_SERVER_HTTP_H | ||||
|  | ||||
| #define HTTP_PRESERVE 0 | ||||
| #define HTTP_LOWER 1 | ||||
| #define HTTP_PRESERVE_UPPER 0 | ||||
| #define HTTP_CAMEL 2 | ||||
|  | ||||
| #define HTTP_REMOVE_ONE 0 | ||||
| #define HTTP_REMOVE_ALL 1 | ||||
|  | ||||
| typedef struct { | ||||
|     unsigned short code; | ||||
| @@ -154,7 +158,7 @@ const char *http_error_icon = | ||||
|         "eTonQXJpYWwnLHNhbnMtc2VyaWYiPjooPC90ZXh0Pjwvc3ZnPgo=\"/>\n"; | ||||
|  | ||||
|  | ||||
| void http_to_camel_case(char *str, int strict); | ||||
| void http_to_camel_case(char *str, int mode); | ||||
|  | ||||
| void http_free_hdr(http_hdr *hdr); | ||||
|  | ||||
| @@ -164,10 +168,14 @@ void http_free_res(http_res *res); | ||||
|  | ||||
| int http_receive_request(sock *client, http_req *req); | ||||
|  | ||||
| int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr) ; | ||||
|  | ||||
| char *http_get_header_field(const http_hdr *hdr, const char *field_name); | ||||
|  | ||||
| void http_add_header_field(http_hdr *hdr, const char *field_name, const char *field_value); | ||||
|  | ||||
| void http_remove_header_field(http_hdr *hdr, const char *field_name, int mode); | ||||
|  | ||||
| int http_send_response(sock *client, http_res *res); | ||||
|  | ||||
| http_status *http_get_status(unsigned short status_code); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user