Process FastCGI header fields

This commit is contained in:
2020-12-28 13:18:38 +01:00
parent 156c7d6621
commit 7cb4f40d22
4 changed files with 129 additions and 38 deletions

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;

View File

@ -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);