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) { |         } else if (ret == 2) { | ||||||
|             sprintf(err_msg, "Unable to parse header: Invalid method."); |             sprintf(err_msg, "Unable to parse header: Invalid method."); | ||||||
|         } else if (ret == 3) { |         } 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) { |         } 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); |         res.status = http_get_status(400); | ||||||
|         goto respond; |         goto respond; | ||||||
| @@ -235,6 +237,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|             if (ret != 0) { |             if (ret != 0) { | ||||||
|                 if (ret < 0) { |                 if (ret < 0) { | ||||||
|                     goto abort; |                     goto abort; | ||||||
|  |                 } else { | ||||||
|  |                     sprintf(err_msg, "Unable to communicate with PHP-FPM."); | ||||||
|                 } |                 } | ||||||
|                 res.status = http_get_status(502); |                 res.status = http_get_status(502); | ||||||
|                 goto respond; |                 goto respond; | ||||||
| @@ -243,15 +247,32 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|         fastcgi_end: |         fastcgi_end: | ||||||
|         fastcgi_close_stdin(&php_fpm); |         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"); |         char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding"); | ||||||
|         if (accept_encoding != NULL && strstr(accept_encoding, "deflate") != NULL) { |         if (accept_encoding != NULL && strstr(accept_encoding, "deflate") != NULL) { | ||||||
|             http_add_header_field(&res.hdr, "Content-Encoding", "deflate"); |             http_add_header_field(&res.hdr, "Content-Encoding", "deflate"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (fastcgi_header(&php_fpm, &res, err_msg) != 0) { |  | ||||||
|             goto respond; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         content_length = -1; |         content_length = -1; | ||||||
|         use_fastcgi = 1; |         use_fastcgi = 1; | ||||||
|         if (http_get_header_field(&res.hdr, "Content-Length") == NULL) { |         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_len = content_len; | ||||||
|     conn->out_off = (unsigned short) (strstr(content, "\r\n\r\n") - content + 4); |     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; |     return 0; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										92
									
								
								src/http.c
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								src/http.c
									
									
									
									
									
								
							| @@ -9,14 +9,14 @@ | |||||||
| #include "utils.h" | #include "utils.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| void http_to_camel_case(char *str, int strict) { | void http_to_camel_case(char *str, int mode) { | ||||||
|     char last = '-'; |     char last = '-'; | ||||||
|     char ch; |     char ch; | ||||||
|     for (int i = 0; i < strlen(str); i++) { |     for (int i = 0; i < strlen(str); i++) { | ||||||
|         ch = 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); |             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); |             str[i] = (char) ((int) ch | 0x20); | ||||||
|         } |         } | ||||||
|         last = str[i]; |         last = str[i]; | ||||||
| @@ -41,8 +41,33 @@ void http_free_res(http_res *res) { | |||||||
|     http_free_hdr(&res->hdr); |     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) { | 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 *ptr, *pos0, *pos1, *pos2; | ||||||
|     char buf[CLIENT_MAX_HEADER_SIZE]; |     char buf[CLIENT_MAX_HEADER_SIZE]; | ||||||
|     memset(buf, 0, sizeof(buf)); |     memset(buf, 0, sizeof(buf)); | ||||||
| @@ -71,7 +96,13 @@ int http_receive_request(sock *client, http_req *req) { | |||||||
|             return -1; |             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) { |             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); |                 print(ERR_STR "Unable to parse header: Header contains illegal characters" CLR_STR); | ||||||
|                 return 4; |                 return 4; | ||||||
| @@ -79,9 +110,9 @@ int http_receive_request(sock *client, http_req *req) { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         ptr = buf; |         ptr = buf; | ||||||
|         while (rcv_len != (ptr - buf)) { |         while (header_len != (ptr - buf)) { | ||||||
|             pos0 = memchr(ptr, '\r', rcv_len - (ptr - buf)); |             pos0 = strstr(ptr, "\r\n"); | ||||||
|             if (pos0 == NULL || pos0[1] != '\n') { |             if (pos0 == NULL) { | ||||||
|                 print(ERR_STR "Unable to parse header: Invalid header format" CLR_STR); |                 print(ERR_STR "Unable to parse header: Invalid header format" CLR_STR); | ||||||
|                 return 1; |                 return 1; | ||||||
|             } |             } | ||||||
| @@ -127,26 +158,8 @@ int http_receive_request(sock *client, http_req *req) { | |||||||
|                 sprintf(req->uri, "%.*s", (int) len, pos1); |                 sprintf(req->uri, "%.*s", (int) len, pos1); | ||||||
|                 sprintf(req->version, "%.3s", pos2 + 5); |                 sprintf(req->version, "%.3s", pos2 + 5); | ||||||
|             } else { |             } else { | ||||||
|                 pos1 = memchr(ptr, ':', pos0 - ptr); |                 int ret = http_parse_header_field(&req->hdr, ptr, pos0); | ||||||
|                 if (pos1 == NULL) { |                 if (ret != 0) return ret; | ||||||
|                     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++; |  | ||||||
|             } |             } | ||||||
|             if (pos0[2] == '\r' && pos0[3] == '\n') { |             if (pos0[2] == '\r' && pos0[3] == '\n') { | ||||||
|                 return 0; |                 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); |     char *_field_value = malloc(len_value + 1); | ||||||
|     strcpy(_field_name, field_name); |     strcpy(_field_name, field_name); | ||||||
|     strcpy(_field_value, field_value); |     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][0] = _field_name; | ||||||
|     hdr->fields[hdr->field_num][1] = _field_value; |     hdr->fields[hdr->field_num][1] = _field_value; | ||||||
|     hdr->field_num++; |     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) { | int http_send_response(sock *client, http_res *res) { | ||||||
|     char buf[CLIENT_MAX_HEADER_SIZE]; |     char buf[CLIENT_MAX_HEADER_SIZE]; | ||||||
|     int len = 0; |     int len = 0; | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								src/http.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/http.h
									
									
									
									
									
								
							| @@ -8,8 +8,12 @@ | |||||||
| #ifndef NECRONDA_SERVER_HTTP_H | #ifndef NECRONDA_SERVER_HTTP_H | ||||||
| #define NECRONDA_SERVER_HTTP_H | #define NECRONDA_SERVER_HTTP_H | ||||||
|  |  | ||||||
|  | #define HTTP_PRESERVE 0 | ||||||
| #define HTTP_LOWER 1 | #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 { | typedef struct { | ||||||
|     unsigned short code; |     unsigned short code; | ||||||
| @@ -154,7 +158,7 @@ const char *http_error_icon = | |||||||
|         "eTonQXJpYWwnLHNhbnMtc2VyaWYiPjooPC90ZXh0Pjwvc3ZnPgo=\"/>\n"; |         "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); | 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_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); | 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_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); | int http_send_response(sock *client, http_res *res); | ||||||
|  |  | ||||||
| http_status *http_get_status(unsigned short status_code); | http_status *http_get_status(unsigned short status_code); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user