Parsing HTTP header
This commit is contained in:
22
src/client.c
22
src/client.c
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
int keep_alive = 1;
|
int keep_alive = 1;
|
||||||
char *client_addr_str, *client_addr_str_ptr, *server_addr_str, *server_addr_str_ptr,
|
char *client_addr_str, *client_addr_str_ptr, *server_addr_str, *server_addr_str_ptr,
|
||||||
*log_conn_prefix, *log_req_prefix;
|
*log_client_prefix, *log_conn_prefix, *log_req_prefix;
|
||||||
|
|
||||||
struct timeval client_timeout = {.tv_sec = CLIENT_TIMEOUT, .tv_usec = 0};
|
struct timeval client_timeout = {.tv_sec = CLIENT_TIMEOUT, .tv_usec = 0};
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ int client_request_handler(sock *client, int req_num) {
|
|||||||
struct timespec begin, end;
|
struct timespec begin, end;
|
||||||
int ret;
|
int ret;
|
||||||
char buf[16];
|
char buf[16];
|
||||||
|
char *host;
|
||||||
char *msg = "HTTP/1.1 501 Not Implemented\r\n"
|
char *msg = "HTTP/1.1 501 Not Implemented\r\n"
|
||||||
"Connection: keep-alive\r\n"
|
"Connection: keep-alive\r\n"
|
||||||
"Keep-Alive: timeout=3600, max=100\r\n"
|
"Keep-Alive: timeout=3600, max=100\r\n"
|
||||||
@ -58,6 +59,13 @@ int client_request_handler(sock *client, int req_num) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
host = http_get_header_field(&req.hdr, "Host");
|
||||||
|
sprintf(log_req_prefix, "[%s%24s%s]%s ", (host != NULL) ? BLD_STR : "", (host != NULL) ? host : server_addr_str,
|
||||||
|
(host != NULL) ? CLR_STR : "", log_client_prefix);
|
||||||
|
log_prefix = log_req_prefix;
|
||||||
|
|
||||||
|
print(BLD_STR "%s %s" CLR_STR, req.method, req.uri);
|
||||||
|
|
||||||
if (client->enc) {
|
if (client->enc) {
|
||||||
SSL_write(client->ssl, msg, (int) strlen(msg));
|
SSL_write(client->ssl, msg, (int) strlen(msg));
|
||||||
} else {
|
} else {
|
||||||
@ -68,6 +76,7 @@ int client_request_handler(sock *client, int req_num) {
|
|||||||
unsigned long micros = (end.tv_nsec - begin.tv_nsec) / 1000 + (end.tv_sec - begin.tv_sec) * 1000000;
|
unsigned long micros = (end.tv_nsec - begin.tv_nsec) / 1000 + (end.tv_sec - begin.tv_sec) * 1000000;
|
||||||
print(ERR_STR "501 Not Implemented (%s)" CLR_STR, format_duration(micros, buf));
|
print(ERR_STR "501 Not Implemented (%s)" CLR_STR, format_duration(micros, buf));
|
||||||
|
|
||||||
|
http_free_req(&req);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,10 +160,14 @@ int client_handler(sock *client, long client_num, struct sockaddr_in6 *client_ad
|
|||||||
server_addr_str = server_addr_str_ptr;
|
server_addr_str = server_addr_str_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_req_prefix = malloc(256);
|
||||||
|
log_client_prefix = malloc(256);
|
||||||
|
sprintf(log_client_prefix, "[%s%4i%s]%s[%*s][%5i]%s", client->enc ? HTTPS_STR : HTTP_STR,
|
||||||
|
ntohs(server_addr->sin6_port), CLR_STR, color_table[client_num % 6], INET_ADDRSTRLEN, client_addr_str,
|
||||||
|
ntohs(client_addr->sin6_port), CLR_STR);
|
||||||
|
|
||||||
log_conn_prefix = malloc(256);
|
log_conn_prefix = malloc(256);
|
||||||
sprintf(log_conn_prefix, "[%24s][%s%4i%s]%s[%*s][%5i]%s ",
|
sprintf(log_conn_prefix, "[%24s]%s ", server_addr_str, log_client_prefix);
|
||||||
server_addr_str, client->enc ? HTTPS_STR : HTTP_STR, ntohs(server_addr->sin6_port), CLR_STR,
|
|
||||||
color_table[client_num % 6], INET_ADDRSTRLEN, client_addr_str, ntohs(client_addr->sin6_port), CLR_STR);
|
|
||||||
log_prefix = log_conn_prefix;
|
log_prefix = log_conn_prefix;
|
||||||
|
|
||||||
ret = client_connection_handler(client);
|
ret = client_connection_handler(client);
|
||||||
@ -162,5 +175,6 @@ int client_handler(sock *client, long client_num, struct sockaddr_in6 *client_ad
|
|||||||
free(server_addr_str_ptr);
|
free(server_addr_str_ptr);
|
||||||
free(log_conn_prefix);
|
free(log_conn_prefix);
|
||||||
free(log_req_prefix);
|
free(log_req_prefix);
|
||||||
|
free(log_client_prefix);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#define ERR_STR "\x1B[1;31m"
|
#define ERR_STR "\x1B[1;31m"
|
||||||
#define CLR_STR "\x1B[0m"
|
#define CLR_STR "\x1B[0m"
|
||||||
|
#define BLD_STR "\x1B[1m"
|
||||||
#define HTTP_STR "\x1B[1;31m"
|
#define HTTP_STR "\x1B[1;31m"
|
||||||
#define HTTPS_STR "\x1B[1;32m"
|
#define HTTPS_STR "\x1B[1;32m"
|
||||||
|
|
||||||
|
144
src/net/http.c
144
src/net/http.c
@ -9,27 +9,151 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
void http_to_camel_case(char *str) {
|
||||||
|
char last = '-';
|
||||||
|
char ch;
|
||||||
|
for (int i = 0; i < strlen(str); i++) {
|
||||||
|
ch = str[i];
|
||||||
|
if (last == '-' && ch >= 'a' && ch <= 'z') {
|
||||||
|
str[i] = (char) ((int) ch & 0x5F);
|
||||||
|
} else if (last != '-' && ch >= 'A' && ch <= 'Z') {
|
||||||
|
str[i] = (char) ((int) ch | 0x20);
|
||||||
|
}
|
||||||
|
last = str[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void http_free_hdr(http_hdr *hdr) {
|
||||||
|
for (int i = 0; i < hdr->field_num; i++) {
|
||||||
|
free(hdr->fields[i][0]);
|
||||||
|
free(hdr->fields[i][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_free_req(http_req *req) {
|
||||||
|
free(req->uri);
|
||||||
|
http_free_hdr(&req->hdr);
|
||||||
|
}
|
||||||
|
|
||||||
int http_receive_request(sock *client, http_req *req) {
|
int http_receive_request(sock *client, http_req *req) {
|
||||||
|
ssize_t rcv_len, len;
|
||||||
|
char *ptr, *pos0, *pos1, *pos2;
|
||||||
char *buf = malloc(CLIENT_MAX_HEADER_SIZE);
|
char *buf = malloc(CLIENT_MAX_HEADER_SIZE);
|
||||||
ssize_t len;
|
memset(buf, 0, sizeof(&buf));
|
||||||
memset(buf, 0, CLIENT_MAX_HEADER_SIZE);
|
memset(req->method, 0, sizeof(req->method));
|
||||||
|
memset(req->version, 0, sizeof(req->version));
|
||||||
|
req->uri = NULL;
|
||||||
|
req->hdr.field_num = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (client->enc) {
|
if (client->enc) {
|
||||||
len = SSL_read(client->ssl, buf, CLIENT_MAX_HEADER_SIZE);
|
rcv_len = SSL_read(client->ssl, buf, CLIENT_MAX_HEADER_SIZE);
|
||||||
if (len < 0) {
|
if (rcv_len < 0) {
|
||||||
print(ERR_STR "Unable to receive: %s" CLR_STR, ssl_get_error(client->ssl, len));
|
print(ERR_STR "Unable to receive: %s" CLR_STR, ssl_get_error(client->ssl, rcv_len));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
len = recv(client->socket, buf, CLIENT_MAX_HEADER_SIZE, 0);
|
rcv_len = recv(client->socket, buf, CLIENT_MAX_HEADER_SIZE, 0);
|
||||||
if (len < 0) {
|
if (rcv_len < 0) {
|
||||||
print(ERR_STR "Unable to receive: %s" CLR_STR, strerror(errno));
|
print(ERR_STR "Unable to receive: %s" CLR_STR, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
ptr = buf;
|
||||||
|
while (1) {
|
||||||
|
pos0 = memchr(ptr, '\r', rcv_len - (ptr - buf));
|
||||||
|
if (pos0 == NULL || pos0[1] != '\n') {
|
||||||
|
print(ERR_STR "Unable to parse header: Invalid header format" CLR_STR);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
} else if (pos0[2] == '\r' && pos0[3] == '\n') {
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr == buf) {
|
||||||
|
if (memcmp(ptr, "GET ", 4) == 0) {
|
||||||
|
sprintf(req->method, "GET");
|
||||||
|
} else if (memcmp(ptr, "HEAD ", 5) == 0) {
|
||||||
|
sprintf(req->method, "HEAD");
|
||||||
|
} else if (memcmp(ptr, "POST ", 5) == 0) {
|
||||||
|
sprintf(req->method, "POST");
|
||||||
|
} else if (memcmp(ptr, "PUT ", 4) == 0) {
|
||||||
|
sprintf(req->method, "PUT");
|
||||||
|
} else if (memcmp(ptr, "DELETE ", 7) == 0) {
|
||||||
|
sprintf(req->method, "DELETE");
|
||||||
|
} else if (memcmp(ptr, "CONNECT ", 7) == 0) {
|
||||||
|
sprintf(req->method, "CONNECT");
|
||||||
|
} else if (memcmp(ptr, "OPTIONS ", 7) == 0) {
|
||||||
|
sprintf(req->method, "OPTIONS");
|
||||||
|
} else if (memcmp(ptr, "TRACE ", 6) == 0) {
|
||||||
|
sprintf(req->method, "TRACE");
|
||||||
|
} else {
|
||||||
|
print(ERR_STR "Unable to parse header: Invalid method" CLR_STR);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos1 = memchr(ptr, ' ', rcv_len - (ptr - buf)) + 1;
|
||||||
|
if (pos1 == NULL) goto err_hdr_fmt;
|
||||||
|
pos2 = memchr(pos1, ' ', rcv_len - (pos1 - buf)) + 1;
|
||||||
|
if (pos2 == NULL) {
|
||||||
|
err_hdr_fmt:
|
||||||
|
print(ERR_STR "Unable to parse header: Invalid header format" CLR_STR);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(pos2, "HTTP/", 5) != 0 || memcmp(pos2 + 8, "\r\n", 2) != 0) {
|
||||||
|
print(ERR_STR "Unable to parse header: Invalid version" CLR_STR);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = pos2 - pos1 - 1;
|
||||||
|
req->uri = malloc(len + 1);
|
||||||
|
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);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = pos0 + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *http_get_header_field(http_hdr *hdr, const char *field_name) {
|
||||||
|
size_t len = strlen(field_name);
|
||||||
|
char *_field_name = malloc(len + 1);
|
||||||
|
sprintf(_field_name, "%s", field_name);
|
||||||
|
http_to_camel_case(_field_name);
|
||||||
|
for (int i = 0; i < hdr->field_num; i++) {
|
||||||
|
if (strncmp(hdr->fields[i][0], _field_name, len) == 0) {
|
||||||
|
return hdr->fields[i][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,16 @@
|
|||||||
#ifndef NECRONDA_SERVER_HTTP_H
|
#ifndef NECRONDA_SERVER_HTTP_H
|
||||||
#define NECRONDA_SERVER_HTTP_H
|
#define NECRONDA_SERVER_HTTP_H
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char field_num;
|
||||||
|
char *fields[64][2];
|
||||||
|
} http_hdr;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char method[8];
|
char method[8];
|
||||||
char *uri;
|
char *uri;
|
||||||
char version[3];
|
char version[3];
|
||||||
char field_num;
|
http_hdr hdr;
|
||||||
char *fields[64][2];
|
|
||||||
} http_req;
|
} http_req;
|
||||||
|
|
||||||
int http_receive_request(sock *client, http_req *req);
|
int http_receive_request(sock *client, http_req *req);
|
||||||
|
Reference in New Issue
Block a user