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