Update http header parser
This commit is contained in:
6
Makefile
6
Makefile
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-std=gnu11 -Wall
|
CFLAGS=-std=gnu11 -Wall -Wno-unused-but-set-variable
|
||||||
LIBS=-lssl -lcrypto -lmagic -lz -lmaxminddb -lbrotlienc
|
LIBS=-lssl -lcrypto -lmagic -lz -lmaxminddb -lbrotlienc
|
||||||
|
|
||||||
DEBIAN_OPTS=-D CACHE_MAGIC_FILE="\"/usr/share/file/magic.mgc\"" -D PHP_FPM_SOCKET="\"/var/run/php/php7.4-fpm.sock\""
|
DEBIAN_OPTS=-D CACHE_MAGIC_FILE="\"/usr/share/file/magic.mgc\"" -D PHP_FPM_SOCKET="\"/var/run/php/php7.4-fpm.sock\""
|
||||||
@ -16,11 +16,11 @@ permit:
|
|||||||
compile:
|
compile:
|
||||||
@mkdir -p bin
|
@mkdir -p bin
|
||||||
$(CC) src/lib/*.c -o bin/libnecrondaserver.so --shared -fPIC $(CFLAGS) $(LIBS)
|
$(CC) src/lib/*.c -o bin/libnecrondaserver.so --shared -fPIC $(CFLAGS) $(LIBS)
|
||||||
$(CC) src/necronda-server.c -o bin/necronda-server $(CFLAGS) $(LIBS) \
|
$(CC) src/necronda-server.c src/client.c -o bin/necronda-server $(CFLAGS) $(LIBS) \
|
||||||
-Lbin -lnecrondaserver -Wl,-rpath=$(shell pwd)/bin
|
-Lbin -lnecrondaserver -Wl,-rpath=$(shell pwd)/bin
|
||||||
|
|
||||||
compile-prod:
|
compile-prod:
|
||||||
@mkdir -p bin
|
@mkdir -p bin
|
||||||
$(CC) src/lib/*.c -o bin/libnecrondaserver.so --shared -fPIC $(CFLAGS) $(LIBS) $(DEBIAN_OPTS) -O3
|
$(CC) src/lib/*.c -o bin/libnecrondaserver.so --shared -fPIC $(CFLAGS) $(LIBS) $(DEBIAN_OPTS) -O3
|
||||||
$(CC) src/necronda-server.c -o bin/necronda-server $(CFLAGS) $(LIBS) $(DEBIAN_OPTS) -O3 \
|
$(CC) src/necronda-server.c src/client.c -o bin/necronda-server $(CFLAGS) $(LIBS) $(DEBIAN_OPTS) -O3 \
|
||||||
-Lbin -lnecrondaserver -Wl,-rpath=$(shell pwd)/bin
|
-Lbin -lnecrondaserver -Wl,-rpath=$(shell pwd)/bin
|
||||||
|
36
src/client.c
36
src/client.c
@ -5,6 +5,10 @@
|
|||||||
* Lorenz Stechauner, 2020-12-03
|
* Lorenz Stechauner, 2020-12-03
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
#include "necronda.h"
|
||||||
|
#include "necronda-server.h"
|
||||||
|
|
||||||
#include "lib/utils.h"
|
#include "lib/utils.h"
|
||||||
#include "lib/config.h"
|
#include "lib/config.h"
|
||||||
#include "lib/sock.h"
|
#include "lib/sock.h"
|
||||||
@ -63,7 +67,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
char msg_buf[8192], msg_pre_buf_1[4096], msg_pre_buf_2[4096], err_msg[256];
|
char msg_buf[8192], msg_pre_buf_1[4096], msg_pre_buf_2[4096], err_msg[256];
|
||||||
char msg_content[1024];
|
char msg_content[1024];
|
||||||
char buffer[CHUNK_SIZE];
|
char buffer[CHUNK_SIZE];
|
||||||
char host[256], *host_ptr, *hdr_connection;
|
char host[256];
|
||||||
|
const char *host_ptr, *hdr_connection;
|
||||||
|
|
||||||
msg_buf[0] = 0;
|
msg_buf[0] = 0;
|
||||||
err_msg[0] = 0;
|
err_msg[0] = 0;
|
||||||
@ -81,7 +86,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
fastcgi_conn fcgi_conn = {.socket = 0, .req_id = 0};
|
fastcgi_conn fcgi_conn = {.socket = 0, .req_id = 0};
|
||||||
http_status custom_status;
|
http_status custom_status;
|
||||||
|
|
||||||
http_res res = {.version = "1.1", .status = http_get_status(501), .hdr.field_num = 0};
|
http_res res = {.version = "1.1", .status = http_get_status(501), .hdr.field_num = 0, .hdr.last_field_num = -1};
|
||||||
http_status_ctx ctx = {.status = 0, .origin = NONE};
|
http_status_ctx ctx = {.status = 0, .origin = NONE};
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &begin);
|
clock_gettime(CLOCK_MONOTONIC, &begin);
|
||||||
@ -218,7 +223,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
|
|
||||||
content_length = snprintf(msg_buf, sizeof(msg_buf) - content_length, "%s %s HTTP/%s\r\n", req.method, req.uri, req.version);
|
content_length = snprintf(msg_buf, sizeof(msg_buf) - content_length, "%s %s HTTP/%s\r\n", req.method, req.uri, req.version);
|
||||||
for (int i = 0; i < req.hdr.field_num; i++) {
|
for (int i = 0; i < req.hdr.field_num; i++) {
|
||||||
content_length += snprintf(msg_buf + content_length, sizeof(msg_buf) - content_length, "%s: %s\r\n", req.hdr.fields[i][0], req.hdr.fields[i][1]);
|
const http_field *f = &req.hdr.fields[i];
|
||||||
|
content_length += snprintf(msg_buf + content_length, sizeof(msg_buf) - content_length, "%s: %s\r\n", http_field_get_name(f), http_field_get_value(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
goto respond;
|
goto respond;
|
||||||
@ -269,13 +275,13 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
sprintf(err_msg, "Unable to communicate with internal file cache.");
|
sprintf(err_msg, "Unable to communicate with internal file cache.");
|
||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
char *last_modified = http_format_date(uri.meta->stat.st_mtime, buf0, sizeof(buf0));
|
const char *last_modified = http_format_date(uri.meta->stat.st_mtime, buf0, sizeof(buf0));
|
||||||
http_add_header_field(&res.hdr, "Last-Modified", last_modified);
|
http_add_header_field(&res.hdr, "Last-Modified", last_modified);
|
||||||
sprintf(buf1, "%s; charset=%s", uri.meta->type, uri.meta->charset);
|
sprintf(buf1, "%s; charset=%s", uri.meta->type, uri.meta->charset);
|
||||||
http_add_header_field(&res.hdr, "Content-Type", buf1);
|
http_add_header_field(&res.hdr, "Content-Type", buf1);
|
||||||
|
|
||||||
|
|
||||||
char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding");
|
const char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding");
|
||||||
int enc = 0;
|
int enc = 0;
|
||||||
if (accept_encoding != NULL) {
|
if (accept_encoding != NULL) {
|
||||||
if (uri.meta->filename_comp_br[0] != 0 && strstr(accept_encoding, "br") != NULL) {
|
if (uri.meta->filename_comp_br[0] != 0 && strstr(accept_encoding, "br") != NULL) {
|
||||||
@ -315,8 +321,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
http_add_header_field(&res.hdr, "Cache-Control", "public, max-age=86400");
|
http_add_header_field(&res.hdr, "Cache-Control", "public, max-age=86400");
|
||||||
}
|
}
|
||||||
|
|
||||||
char *if_modified_since = http_get_header_field(&req.hdr, "If-Modified-Since");
|
const char *if_modified_since = http_get_header_field(&req.hdr, "If-Modified-Since");
|
||||||
char *if_none_match = http_get_header_field(&req.hdr, "If-None-Match");
|
const char *if_none_match = http_get_header_field(&req.hdr, "If-None-Match");
|
||||||
if ((if_none_match != NULL && strstr(if_none_match, uri.meta->etag) == NULL) ||
|
if ((if_none_match != NULL && strstr(if_none_match, uri.meta->etag) == NULL) ||
|
||||||
(accept_if_modified_since && if_modified_since != NULL && strcmp(if_modified_since, last_modified) == 0))
|
(accept_if_modified_since && if_modified_since != NULL && strcmp(if_modified_since, last_modified) == 0))
|
||||||
{
|
{
|
||||||
@ -324,7 +330,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *range = http_get_header_field(&req.hdr, "Range");
|
const char *range = http_get_header_field(&req.hdr, "Range");
|
||||||
if (range != NULL) {
|
if (range != NULL) {
|
||||||
if (strlen(range) <= 6 || strncmp(range, "bytes=", 6) != 0) {
|
if (strlen(range) <= 6 || strncmp(range, "bytes=", 6) != 0) {
|
||||||
res.status = http_get_status(416);
|
res.status = http_get_status(416);
|
||||||
@ -399,7 +405,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *client_content_length = http_get_header_field(&req.hdr, "Content-Length");
|
const char *client_content_length = http_get_header_field(&req.hdr, "Content-Length");
|
||||||
if (client_content_length != NULL) {
|
if (client_content_length != NULL) {
|
||||||
unsigned long client_content_len = strtoul(client_content_length, NULL, 10);
|
unsigned long client_content_len = strtoul(client_content_length, NULL, 10);
|
||||||
ret = fastcgi_receive(&fcgi_conn, client, client_content_len);
|
ret = fastcgi_receive(&fcgi_conn, client, client_content_len);
|
||||||
@ -421,7 +427,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *status = http_get_header_field(&res.hdr, "Status");
|
const char *status = http_get_header_field(&res.hdr, "Status");
|
||||||
if (status != NULL) {
|
if (status != NULL) {
|
||||||
int status_code = (int) strtoul(status, NULL, 10);
|
int status_code = (int) strtoul(status, NULL, 10);
|
||||||
res.status = http_get_status(status_code);
|
res.status = http_get_status(status_code);
|
||||||
@ -605,7 +611,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *conn = http_get_header_field(&res.hdr, "Connection");
|
const char *conn = http_get_header_field(&res.hdr, "Connection");
|
||||||
int close_proxy = (conn == NULL || (strcmp(conn, "keep-alive") != 0 && strcmp(conn, "Keep-Alive") != 0));
|
int close_proxy = (conn == NULL || (strcmp(conn, "keep-alive") != 0 && strcmp(conn, "Keep-Alive") != 0));
|
||||||
http_remove_header_field(&res.hdr, "Connection", HTTP_REMOVE_ALL);
|
http_remove_header_field(&res.hdr, "Connection", HTTP_REMOVE_ALL);
|
||||||
http_remove_header_field(&res.hdr, "Keep-Alive", HTTP_REMOVE_ALL);
|
http_remove_header_field(&res.hdr, "Keep-Alive", HTTP_REMOVE_ALL);
|
||||||
@ -619,7 +625,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
|
|
||||||
http_send_response(client, &res);
|
http_send_response(client, &res);
|
||||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||||
char *location = http_get_header_field(&res.hdr, "Location");
|
const char *location = http_get_header_field(&res.hdr, "Location");
|
||||||
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("%s%s%03i %s%s%s (%s)%s", http_get_status_color(res.status), use_rev_proxy ? "-> " : "", res.status->code,
|
print("%s%s%03i %s%s%s (%s)%s", http_get_status_color(res.status), use_rev_proxy ? "-> " : "", res.status->code,
|
||||||
res.status->msg, location != NULL ? " -> " : "", location != NULL ? location : "",
|
res.status->msg, location != NULL ? " -> " : "", location != NULL ? location : "",
|
||||||
@ -650,16 +656,16 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
snd_len += ret;
|
snd_len += ret;
|
||||||
}
|
}
|
||||||
} else if (use_fastcgi) {
|
} else if (use_fastcgi) {
|
||||||
char *transfer_encoding = http_get_header_field(&res.hdr, "Transfer-Encoding");
|
const char *transfer_encoding = http_get_header_field(&res.hdr, "Transfer-Encoding");
|
||||||
int chunked = (transfer_encoding != NULL && strcmp(transfer_encoding, "chunked") == 0);
|
int chunked = (transfer_encoding != NULL && strcmp(transfer_encoding, "chunked") == 0);
|
||||||
|
|
||||||
int flags = (chunked ? FASTCGI_CHUNKED : 0) | (use_fastcgi & (FASTCGI_COMPRESS | FASTCGI_COMPRESS_HOLD));
|
int flags = (chunked ? FASTCGI_CHUNKED : 0) | (use_fastcgi & (FASTCGI_COMPRESS | FASTCGI_COMPRESS_HOLD));
|
||||||
ret = fastcgi_send(&fcgi_conn, client, flags);
|
ret = fastcgi_send(&fcgi_conn, client, flags);
|
||||||
} else if (use_rev_proxy) {
|
} else if (use_rev_proxy) {
|
||||||
char *transfer_encoding = http_get_header_field(&res.hdr, "Transfer-Encoding");
|
const char *transfer_encoding = http_get_header_field(&res.hdr, "Transfer-Encoding");
|
||||||
int chunked = transfer_encoding != NULL && strstr(transfer_encoding, "chunked") != NULL;
|
int chunked = transfer_encoding != NULL && strstr(transfer_encoding, "chunked") != NULL;
|
||||||
|
|
||||||
char *content_len = http_get_header_field(&res.hdr, "Content-Length");
|
const char *content_len = http_get_header_field(&res.hdr, "Content-Length");
|
||||||
unsigned long len_to_send = 0;
|
unsigned long len_to_send = 0;
|
||||||
if (content_len != NULL) {
|
if (content_len != NULL) {
|
||||||
len_to_send = strtol(content_len, NULL, 10);
|
len_to_send = strtol(content_len, NULL, 10);
|
||||||
|
20
src/client.h
Normal file
20
src/client.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Necronda Web Server
|
||||||
|
* Client connection and request handlers
|
||||||
|
* src/client.h
|
||||||
|
* Lorenz Stechauner, 2022-08-16
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NECRONDA_SERVER_NECRONDA_CLIENT_H
|
||||||
|
#define NECRONDA_SERVER_NECRONDA_CLIENT_H
|
||||||
|
|
||||||
|
#include "lib/config.h"
|
||||||
|
#include "lib/sock.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
host_config *get_host_config(const char *host);
|
||||||
|
|
||||||
|
int client_handler(sock *client, unsigned long client_num, struct sockaddr_in6 *client_addr);
|
||||||
|
|
||||||
|
#endif //NECRONDA_SERVER_NECRONDA_CLIENT_H
|
@ -41,9 +41,9 @@ char *fastcgi_add_param(char *buf, const char *key, const char *value) {
|
|||||||
ptr += 4;
|
ptr += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(ptr, key, key_len);
|
strcpy(ptr, key);
|
||||||
ptr += key_len;
|
ptr += key_len;
|
||||||
memcpy(ptr, value, val_len);
|
strcpy(ptr, value);
|
||||||
ptr += val_len;
|
ptr += val_len;
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
@ -149,19 +149,21 @@ int fastcgi_init(fastcgi_conn *conn, int mode, unsigned int client_num, unsigned
|
|||||||
param_ptr = fastcgi_add_param(param_ptr, "PATH_INFO", buf0);
|
param_ptr = fastcgi_add_param(param_ptr, "PATH_INFO", buf0);
|
||||||
|
|
||||||
//param_ptr = fastcgi_add_param(param_ptr, "AUTH_TYPE", "");
|
//param_ptr = fastcgi_add_param(param_ptr, "AUTH_TYPE", "");
|
||||||
char *content_length = http_get_header_field(&req->hdr, "Content-Length");
|
const char *content_length = http_get_header_field(&req->hdr, "Content-Length");
|
||||||
param_ptr = fastcgi_add_param(param_ptr, "CONTENT_LENGTH", content_length != NULL ? content_length : "");
|
param_ptr = fastcgi_add_param(param_ptr, "CONTENT_LENGTH", content_length != NULL ? content_length : "");
|
||||||
char *content_type = http_get_header_field(&req->hdr, "Content-Type");
|
const char *content_type = http_get_header_field(&req->hdr, "Content-Type");
|
||||||
param_ptr = fastcgi_add_param(param_ptr, "CONTENT_TYPE", content_type != NULL ? content_type : "");
|
param_ptr = fastcgi_add_param(param_ptr, "CONTENT_TYPE", content_type != NULL ? content_type : "");
|
||||||
if (client_geoip != NULL) {
|
if (client_geoip != NULL) {
|
||||||
param_ptr = fastcgi_add_param(param_ptr, "REMOTE_INFO", client_geoip);
|
param_ptr = fastcgi_add_param(param_ptr, "REMOTE_INFO", client_geoip);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < req->hdr.field_num; i++) {
|
for (int i = 0; i < req->hdr.field_num; i++) {
|
||||||
|
const http_field *f = &req->hdr.fields[i];
|
||||||
|
const char *name = http_field_get_name(f);
|
||||||
char *ptr = buf0;
|
char *ptr = buf0;
|
||||||
ptr += sprintf(ptr, "HTTP_");
|
ptr += sprintf(ptr, "HTTP_");
|
||||||
for (int j = 0; j < strlen(req->hdr.fields[i][0]); j++, ptr++) {
|
for (int j = 0; j < strlen(name); j++, ptr++) {
|
||||||
char ch = req->hdr.fields[i][0][j];
|
char ch = name[j];
|
||||||
if ((ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) {
|
if ((ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) {
|
||||||
ch = ch;
|
ch = ch;
|
||||||
} else if (ch >= 'a' && ch <= 'z') {
|
} else if (ch >= 'a' && ch <= 'z') {
|
||||||
@ -172,7 +174,7 @@ int fastcgi_init(fastcgi_conn *conn, int mode, unsigned int client_num, unsigned
|
|||||||
ptr[0] = ch;
|
ptr[0] = ch;
|
||||||
ptr[1] = 0;
|
ptr[1] = 0;
|
||||||
}
|
}
|
||||||
param_ptr = fastcgi_add_param(param_ptr, buf0, req->hdr.fields[i][1]);
|
param_ptr = fastcgi_add_param(param_ptr, buf0, http_field_get_value(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short param_len = param_ptr - param_buf - sizeof(header);
|
unsigned short param_len = param_ptr - param_buf - sizeof(header);
|
||||||
|
218
src/lib/http.c
218
src/lib/http.c
@ -11,8 +11,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void http_to_camel_case(char *str, int mode) {
|
void http_to_camel_case(char *str, int mode) {
|
||||||
char last = '-';
|
if (mode == HTTP_PRESERVE)
|
||||||
char ch;
|
return;
|
||||||
|
|
||||||
|
char ch, last = '-';
|
||||||
for (int i = 0; i < strlen(str); i++) {
|
for (int i = 0; i < strlen(str); i++) {
|
||||||
ch = str[i];
|
ch = str[i];
|
||||||
if (mode == HTTP_CAMEL && last == '-' && ch >= 'a' && ch <= 'z') {
|
if (mode == HTTP_CAMEL && last == '-' && ch >= 'a' && ch <= 'z') {
|
||||||
@ -24,12 +26,47 @@ void http_to_camel_case(char *str, int mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *http_field_get_name(const http_field *field) {
|
||||||
|
if (field->type == HTTP_FIELD_NORMAL) {
|
||||||
|
return field->normal.name;
|
||||||
|
} else if (field->type == HTTP_FIELD_EX_VALUE) {
|
||||||
|
return field->ex_value.name;
|
||||||
|
} else if (field->type == HTTP_FIELD_EX_NAME) {
|
||||||
|
return field->ex_name.name;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *http_field_get_value(const http_field *field) {
|
||||||
|
if (field->type == HTTP_FIELD_NORMAL) {
|
||||||
|
return field->normal.value;
|
||||||
|
} else if (field->type == HTTP_FIELD_EX_VALUE) {
|
||||||
|
return field->ex_value.value;
|
||||||
|
} else if (field->type == HTTP_FIELD_EX_NAME) {
|
||||||
|
return field->ex_name.value;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void http_free_hdr(http_hdr *hdr) {
|
void http_free_hdr(http_hdr *hdr) {
|
||||||
for (int i = 0; i < hdr->field_num; i++) {
|
for (int i = 0; i < hdr->field_num; i++) {
|
||||||
free(hdr->fields[i][0]);
|
http_field *f = &hdr->fields[i];
|
||||||
free(hdr->fields[i][1]);
|
if (f->type == HTTP_FIELD_NORMAL) {
|
||||||
|
f->normal.name[0] = 0;
|
||||||
|
f->normal.value[0] = 0;
|
||||||
|
} else if (f->type == HTTP_FIELD_EX_VALUE) {
|
||||||
|
f->ex_value.name[0] = 0;
|
||||||
|
free(f->ex_value.value);
|
||||||
|
f->ex_value.value = NULL;
|
||||||
|
} else if (f->type == HTTP_FIELD_EX_NAME) {
|
||||||
|
free(f->ex_name.name);
|
||||||
|
free(f->ex_name.value);
|
||||||
|
f->ex_name.name = NULL;
|
||||||
|
f->ex_name.value = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hdr->field_num = 0;
|
hdr->field_num = 0;
|
||||||
|
hdr->last_field_num = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_free_req(http_req *req) {
|
void http_free_req(http_req *req) {
|
||||||
@ -43,44 +80,63 @@ void http_free_res(http_res *res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr) {
|
int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr) {
|
||||||
char *pos1 = memchr(buf, ':', end_ptr - buf);
|
if (hdr->last_field_num > hdr->field_num) {
|
||||||
char *pos2;
|
print(ERR_STR "Unable to parse header: Invalid state" CLR_STR);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pos1 = (char *) buf, *pos2 = (char *) end_ptr;
|
||||||
|
if (buf[0] == ' ' || buf[0] == '\t') {
|
||||||
|
if (hdr->last_field_num == -1) {
|
||||||
|
print(ERR_STR "Unable to parse header" CLR_STR);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
http_field *f = &hdr->fields[(int) hdr->last_field_num];
|
||||||
|
|
||||||
|
str_trim_lws(&pos1, &pos2);
|
||||||
|
http_append_to_header_field(f, pos1, pos2 - pos1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos1 = memchr(buf, ':', end_ptr - buf);
|
||||||
if (pos1 == NULL) {
|
if (pos1 == NULL) {
|
||||||
print(ERR_STR "Unable to parse header" CLR_STR);
|
print(ERR_STR "Unable to parse header" CLR_STR);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
long len1 = pos1 - buf - 1;
|
||||||
long len = pos1 - buf;
|
|
||||||
hdr->fields[(int) hdr->field_num][0] = malloc(len + 1);
|
|
||||||
sprintf(hdr->fields[(int) hdr->field_num][0], "%.*s", (int) len, buf);
|
|
||||||
http_to_camel_case(hdr->fields[(int) hdr->field_num][0], HTTP_CAMEL);
|
|
||||||
|
|
||||||
pos1++;
|
pos1++;
|
||||||
pos2 = (char *) end_ptr - 1;
|
str_trim_lws(&pos1, &pos2);
|
||||||
while (pos1[0] == ' ') pos1++;
|
long len2 = pos2 - pos1;
|
||||||
while (pos2[0] == ' ') pos2--;
|
|
||||||
len = pos2 - pos1 + 1;
|
|
||||||
|
|
||||||
if (len <= 0) {
|
char field_num = hdr->field_num;
|
||||||
hdr->fields[(int) hdr->field_num][1] = malloc(1);
|
int found = http_get_header_field_num_len(hdr, buf, len1);
|
||||||
hdr->fields[(int) hdr->field_num][1][0] = 0;
|
if (found == -1) {
|
||||||
} else {
|
if (http_add_header_field_len(hdr, buf, len1, pos1, len2 < 0 ? 0 : len2) != 0) {
|
||||||
hdr->fields[(int) hdr->field_num][1] = malloc(len + 1);
|
print(ERR_STR "Unable to parse header: Too many header fields" CLR_STR);
|
||||||
sprintf(hdr->fields[(int) hdr->field_num][1], "%.*s", (int) len, pos1);
|
return 3;
|
||||||
}
|
}
|
||||||
hdr->field_num++;
|
} else {
|
||||||
|
field_num = (char) found;
|
||||||
|
http_append_to_header_field(&hdr->fields[found], ", ", 2);
|
||||||
|
http_append_to_header_field(&hdr->fields[found], pos1, len2);
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr->last_field_num = (char) field_num;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_receive_request(sock *client, http_req *req) {
|
int http_receive_request(sock *client, http_req *req) {
|
||||||
long rcv_len, len;
|
long rcv_len, len;
|
||||||
char *ptr, *pos0, *pos1, *pos2;
|
|
||||||
char buf[CLIENT_MAX_HEADER_SIZE];
|
char buf[CLIENT_MAX_HEADER_SIZE];
|
||||||
|
char *ptr, *pos0 = buf, *pos1, *pos2;
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
memset(req->method, 0, sizeof(req->method));
|
memset(req->method, 0, sizeof(req->method));
|
||||||
memset(req->version, 0, sizeof(req->version));
|
memset(req->version, 0, sizeof(req->version));
|
||||||
req->uri = NULL;
|
req->uri = NULL;
|
||||||
req->hdr.field_num = 0;
|
req->hdr.field_num = 0;
|
||||||
|
req->hdr.last_field_num = -1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
rcv_len = sock_recv(client, buf, CLIENT_MAX_HEADER_SIZE, 0);
|
rcv_len = sock_recv(client, buf, CLIENT_MAX_HEADER_SIZE, 0);
|
||||||
@ -164,31 +220,85 @@ int http_receive_request(sock *client, http_req *req) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *http_get_header_field(const http_hdr *hdr, const char *field_name) {
|
const char *http_get_header_field(const http_hdr *hdr, const char *field_name) {
|
||||||
char field_name_1[256], field_name_2[256];
|
return http_get_header_field_len(hdr, field_name, strlen(field_name));
|
||||||
strcpy(field_name_1, field_name);
|
}
|
||||||
http_to_camel_case(field_name_1, HTTP_LOWER);
|
|
||||||
for (int i = 0; i < hdr->field_num; i++) {
|
const char *http_get_header_field_len(const http_hdr *hdr, const char *field_name, unsigned long len) {
|
||||||
strcpy(field_name_2, hdr->fields[i][0]);
|
return http_field_get_value(&hdr->fields[http_get_header_field_num_len(hdr, field_name, len)]);
|
||||||
http_to_camel_case(field_name_2, HTTP_LOWER);
|
}
|
||||||
if (strcmp(field_name_1, field_name_2) == 0) {
|
|
||||||
return hdr->fields[i][1];
|
int http_get_header_field_num(const http_hdr *hdr, const char *field_name) {
|
||||||
}
|
return http_get_header_field_num_len(hdr, field_name, strlen(field_name));
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
|
int http_get_header_field_num_len(const http_hdr *hdr, const char *field_name, unsigned long len) {
|
||||||
|
char field_name_1[256], field_name_2[256];
|
||||||
|
memcpy(field_name_1, field_name, len);
|
||||||
|
http_to_camel_case(field_name_1, HTTP_LOWER);
|
||||||
|
for (int i = 0; i < hdr->field_num; i++) {
|
||||||
|
strcpy(field_name_2, http_field_get_name(&hdr->fields[i]));
|
||||||
|
http_to_camel_case(field_name_2, HTTP_LOWER);
|
||||||
|
if (strcmp(field_name_1, field_name_2) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_add_header_field(http_hdr *hdr, const char *field_name, const char *field_value) {
|
||||||
|
return http_add_header_field_len(hdr, field_name, strlen(field_name), field_value, strlen(field_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_add_header_field_len(http_hdr *hdr, const char *name, unsigned long name_len, const char *value, unsigned long value_len) {
|
||||||
|
if (hdr->field_num >= HTTP_MAX_HEADER_FIELD_NUM)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
http_field *f = &hdr->fields[(int) hdr->field_num];
|
||||||
|
|
||||||
|
if (name_len < sizeof(f->normal.name) && value_len < sizeof(f->normal.value)) {
|
||||||
|
f->type = HTTP_FIELD_NORMAL;
|
||||||
|
strncpy(f->normal.name, name, name_len);
|
||||||
|
strncpy(f->normal.value, value, value_len);
|
||||||
|
http_to_camel_case(f->normal.name, HTTP_PRESERVE);
|
||||||
|
} else if (name_len < sizeof(f->ex_value.name)) {
|
||||||
|
f->type = HTTP_FIELD_EX_VALUE;
|
||||||
|
f->ex_value.value = malloc(value_len + 1);
|
||||||
|
strncpy(f->ex_value.name, name, name_len);
|
||||||
|
strncpy(f->ex_value.value, value, value_len);
|
||||||
|
http_to_camel_case(f->ex_value.name, HTTP_PRESERVE);
|
||||||
|
} else {
|
||||||
|
f->type = HTTP_FIELD_EX_NAME;
|
||||||
|
f->ex_name.name = malloc(name_len + 1);
|
||||||
|
f->ex_name.value = malloc(value_len + 1);
|
||||||
|
strncpy(f->ex_name.name, name, name_len);
|
||||||
|
strncpy(f->ex_name.value, value, value_len);
|
||||||
|
http_to_camel_case(f->ex_name.name, HTTP_PRESERVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_add_header_field(http_hdr *hdr, const char *field_name, const char *field_value) {
|
|
||||||
size_t len_name = strlen(field_name);
|
|
||||||
size_t len_value = strlen(field_value);
|
|
||||||
char *_field_name = malloc(len_name + 1);
|
|
||||||
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);
|
|
||||||
hdr->fields[(int) hdr->field_num][0] = _field_name;
|
|
||||||
hdr->fields[(int) hdr->field_num][1] = _field_value;
|
|
||||||
hdr->field_num++;
|
hdr->field_num++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_append_to_header_field(http_field *field, const char *value, unsigned long len) {
|
||||||
|
if (field->type == HTTP_FIELD_NORMAL) {
|
||||||
|
unsigned long total_len = strlen(field->normal.value) + len + 1;
|
||||||
|
if (total_len < sizeof(field->normal.value)) {
|
||||||
|
strncat(field->normal.value, value, len);
|
||||||
|
} else {
|
||||||
|
field->type = HTTP_FIELD_EX_VALUE;
|
||||||
|
char *new = malloc(total_len);
|
||||||
|
strcpy(new, field->normal.value);
|
||||||
|
strncat(new, value, len);
|
||||||
|
field->ex_value.value = new;
|
||||||
|
}
|
||||||
|
} else if (field->type == HTTP_FIELD_EX_VALUE) {
|
||||||
|
field->ex_value.value = realloc(field->ex_value.value, strlen(field->ex_value.value) + len + 1);
|
||||||
|
strncat(field->ex_value.value, value, len);
|
||||||
|
} else if (field->type == HTTP_FIELD_EX_NAME) {
|
||||||
|
field->ex_name.value = realloc(field->ex_name.value, strlen(field->ex_name.value) + len + 1);
|
||||||
|
strncat(field->ex_name.value, value, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_remove_header_field(http_hdr *hdr, const char *field_name, int mode) {
|
void http_remove_header_field(http_hdr *hdr, const char *field_name, int mode) {
|
||||||
@ -203,12 +313,10 @@ void http_remove_header_field(http_hdr *hdr, const char *field_name, int mode) {
|
|||||||
diff = -1;
|
diff = -1;
|
||||||
}
|
}
|
||||||
for (; i < hdr->field_num && i >= 0; i += diff) {
|
for (; i < hdr->field_num && i >= 0; i += diff) {
|
||||||
strcpy(field_name_2, hdr->fields[i][0]);
|
strcpy(field_name_2, http_field_get_name(&hdr->fields[i]));
|
||||||
http_to_camel_case(field_name_2, HTTP_LOWER);
|
http_to_camel_case(field_name_2, HTTP_LOWER);
|
||||||
if (strcmp(field_name_1, field_name_2) == 0) {
|
if (strcmp(field_name_1, field_name_2) == 0) {
|
||||||
for (int j = i; j < hdr->field_num - 1; j++) {
|
memmove(&hdr->fields[i], &hdr->fields[i + 1], sizeof(hdr->fields[0]) * (hdr->field_num - i));
|
||||||
memcpy(hdr->fields[j], hdr->fields[j + 1], sizeof(hdr->fields[0]));
|
|
||||||
}
|
|
||||||
hdr->field_num--;
|
hdr->field_num--;
|
||||||
if (mode == HTTP_REMOVE_ALL) {
|
if (mode == HTTP_REMOVE_ALL) {
|
||||||
i -= diff;
|
i -= diff;
|
||||||
@ -223,7 +331,8 @@ int http_send_response(sock *client, http_res *res) {
|
|||||||
char buf[CLIENT_MAX_HEADER_SIZE];
|
char buf[CLIENT_MAX_HEADER_SIZE];
|
||||||
long off = sprintf(buf, "HTTP/%s %03i %s\r\n", res->version, res->status->code, res->status->msg);
|
long off = sprintf(buf, "HTTP/%s %03i %s\r\n", res->version, res->status->code, res->status->msg);
|
||||||
for (int i = 0; i < res->hdr.field_num; i++) {
|
for (int i = 0; i < res->hdr.field_num; i++) {
|
||||||
off += sprintf(buf + off, "%s: %s\r\n", res->hdr.fields[i][0], res->hdr.fields[i][1]);
|
const http_field *f = &res->hdr.fields[i];
|
||||||
|
off += sprintf(buf + off, "%s: %s\r\n", http_field_get_name(f), http_field_get_value(f));
|
||||||
}
|
}
|
||||||
off += sprintf(buf + off, "\r\n");
|
off += sprintf(buf + off, "\r\n");
|
||||||
if (sock_send(client, buf, off, 0) < 0) {
|
if (sock_send(client, buf, off, 0) < 0) {
|
||||||
@ -236,7 +345,8 @@ int http_send_request(sock *server, http_req *req) {
|
|||||||
char buf[CLIENT_MAX_HEADER_SIZE];
|
char buf[CLIENT_MAX_HEADER_SIZE];
|
||||||
long off = sprintf(buf, "%s %s HTTP/%s\r\n", req->method, req->uri, req->version);
|
long off = sprintf(buf, "%s %s HTTP/%s\r\n", req->method, req->uri, req->version);
|
||||||
for (int i = 0; i < req->hdr.field_num; i++) {
|
for (int i = 0; i < req->hdr.field_num; i++) {
|
||||||
off += sprintf(buf + off, "%s: %s\r\n", req->hdr.fields[i][0], req->hdr.fields[i][1]);
|
const http_field *f = &req->hdr.fields[i];
|
||||||
|
off += sprintf(buf + off, "%s: %s\r\n", http_field_get_name(f), http_field_get_value(f));
|
||||||
}
|
}
|
||||||
off += sprintf(buf + off, "\r\n");
|
off += sprintf(buf + off, "\r\n");
|
||||||
long ret = sock_send(server, buf, off, 0);
|
long ret = sock_send(server, buf, off, 0);
|
||||||
@ -314,9 +424,9 @@ const http_doc_info *http_get_status_info(const http_status *status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int http_get_compression(const http_req *req, const http_res *res) {
|
int http_get_compression(const http_req *req, const http_res *res) {
|
||||||
char *accept_encoding = http_get_header_field(&req->hdr, "Accept-Encoding");
|
const char *accept_encoding = http_get_header_field(&req->hdr, "Accept-Encoding");
|
||||||
char *content_type = http_get_header_field(&res->hdr, "Content-Type");
|
const char *content_type = http_get_header_field(&res->hdr, "Content-Type");
|
||||||
char *content_encoding = http_get_header_field(&res->hdr, "Content-Encoding");
|
const char *content_encoding = http_get_header_field(&res->hdr, "Content-Encoding");
|
||||||
if (mime_is_compressible(content_type) && content_encoding == NULL && accept_encoding != NULL) {
|
if (mime_is_compressible(content_type) && content_encoding == NULL && accept_encoding != NULL) {
|
||||||
if (strstr(accept_encoding, "br") != NULL) {
|
if (strstr(accept_encoding, "br") != NULL) {
|
||||||
return COMPRESS_BR;
|
return COMPRESS_BR;
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
#define HTTP_REMOVE_ALL 1
|
#define HTTP_REMOVE_ALL 1
|
||||||
#define HTTP_REMOVE_LAST 2
|
#define HTTP_REMOVE_LAST 2
|
||||||
|
|
||||||
|
#define HTTP_FIELD_NORMAL 0
|
||||||
|
#define HTTP_FIELD_EX_VALUE 1
|
||||||
|
#define HTTP_FIELD_EX_NAME 2
|
||||||
|
|
||||||
#define HTTP_1XX_STR "\x1B[1;32m"
|
#define HTTP_1XX_STR "\x1B[1;32m"
|
||||||
#define HTTP_2XX_STR "\x1B[1;32m"
|
#define HTTP_2XX_STR "\x1B[1;32m"
|
||||||
#define HTTP_3XX_STR "\x1B[1;33m"
|
#define HTTP_3XX_STR "\x1B[1;33m"
|
||||||
@ -30,6 +34,7 @@
|
|||||||
#define HTTP_COLOR_ERROR "#C00000"
|
#define HTTP_COLOR_ERROR "#C00000"
|
||||||
|
|
||||||
#define CLIENT_MAX_HEADER_SIZE 8192
|
#define CLIENT_MAX_HEADER_SIZE 8192
|
||||||
|
#define HTTP_MAX_HEADER_FIELD_NUM 64
|
||||||
|
|
||||||
#ifndef SERVER_STR
|
#ifndef SERVER_STR
|
||||||
# define SERVER_STR "Necronda"
|
# define SERVER_STR "Necronda"
|
||||||
@ -57,9 +62,28 @@ typedef struct {
|
|||||||
const char *doc;
|
const char *doc;
|
||||||
} http_doc_info;
|
} http_doc_info;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
char name[64];
|
||||||
|
char value[192];
|
||||||
|
} normal;
|
||||||
|
struct {
|
||||||
|
char name[192];
|
||||||
|
char *value;
|
||||||
|
} ex_value;
|
||||||
|
struct {
|
||||||
|
char *name;
|
||||||
|
char *value;
|
||||||
|
} ex_name;
|
||||||
|
};
|
||||||
|
} http_field;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char field_num;
|
char field_num;
|
||||||
char *fields[64][2];
|
char last_field_num;
|
||||||
|
http_field fields[HTTP_MAX_HEADER_FIELD_NUM];
|
||||||
} http_hdr;
|
} http_hdr;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -102,6 +126,10 @@ extern const char http_info_icon[];
|
|||||||
|
|
||||||
void http_to_camel_case(char *str, int mode);
|
void http_to_camel_case(char *str, int mode);
|
||||||
|
|
||||||
|
const char *http_field_get_name(const http_field *field);
|
||||||
|
|
||||||
|
const char *http_field_get_value(const http_field *field);
|
||||||
|
|
||||||
void http_free_hdr(http_hdr *hdr);
|
void http_free_hdr(http_hdr *hdr);
|
||||||
|
|
||||||
void http_free_req(http_req *req);
|
void http_free_req(http_req *req);
|
||||||
@ -112,9 +140,19 @@ int http_receive_request(sock *client, http_req *req);
|
|||||||
|
|
||||||
int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr) ;
|
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);
|
const 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);
|
const char *http_get_header_field_len(const http_hdr *hdr, const char *field_name, unsigned long len);
|
||||||
|
|
||||||
|
int http_get_header_field_num(const http_hdr *hdr, const char *field_name);
|
||||||
|
|
||||||
|
int http_get_header_field_num_len(const http_hdr *hdr, const char *field_name, unsigned long len);
|
||||||
|
|
||||||
|
int http_add_header_field(http_hdr *hdr, const char *field_name, const char *field_value);
|
||||||
|
|
||||||
|
int http_add_header_field_len(http_hdr *hdr, const char *name, unsigned long name_len, const char *value, unsigned long value_len);
|
||||||
|
|
||||||
|
void http_append_to_header_field(http_field *field, const char *value, unsigned long len);
|
||||||
|
|
||||||
void http_remove_header_field(http_hdr *hdr, const char *field_name, int mode);
|
void http_remove_header_field(http_hdr *hdr, const char *field_name, int mode);
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ int rev_proxy_request_header(http_req *req, int enc) {
|
|||||||
http_remove_header_field(&req->hdr, "Connection", HTTP_REMOVE_ALL);
|
http_remove_header_field(&req->hdr, "Connection", HTTP_REMOVE_ALL);
|
||||||
http_add_header_field(&req->hdr, "Connection", "keep-alive");
|
http_add_header_field(&req->hdr, "Connection", "keep-alive");
|
||||||
|
|
||||||
char *via = http_get_header_field(&req->hdr, "Via");
|
const char *via = http_get_header_field(&req->hdr, "Via");
|
||||||
sprintf(buf1, "HTTP/%s %s", req->version, SERVER_NAME);
|
sprintf(buf1, "HTTP/%s %s", req->version, SERVER_NAME);
|
||||||
if (via == NULL) {
|
if (via == NULL) {
|
||||||
http_add_header_field(&req->hdr, "Via", buf1);
|
http_add_header_field(&req->hdr, "Via", buf1);
|
||||||
@ -49,8 +49,8 @@ int rev_proxy_request_header(http_req *req, int enc) {
|
|||||||
http_add_header_field(&req->hdr, "Via", buf2);
|
http_add_header_field(&req->hdr, "Via", buf2);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *host = http_get_header_field(&req->hdr, "Host");
|
const char *host = http_get_header_field(&req->hdr, "Host");
|
||||||
char *forwarded = http_get_header_field(&req->hdr, "Forwarded");
|
const char *forwarded = http_get_header_field(&req->hdr, "Forwarded");
|
||||||
int client_ipv6 = strchr(client_addr_str, ':') != NULL;
|
int client_ipv6 = strchr(client_addr_str, ':') != NULL;
|
||||||
int server_ipv6 = strchr(server_addr_str, ':') != NULL;
|
int server_ipv6 = strchr(server_addr_str, ':') != NULL;
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ int rev_proxy_request_header(http_req *req, int enc) {
|
|||||||
http_add_header_field(&req->hdr, "Forwarded", buf2);
|
http_add_header_field(&req->hdr, "Forwarded", buf2);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *xff = http_get_header_field(&req->hdr, "X-Forwarded-For");
|
const char *xff = http_get_header_field(&req->hdr, "X-Forwarded-For");
|
||||||
if (xff == NULL) {
|
if (xff == NULL) {
|
||||||
http_add_header_field(&req->hdr, "X-Forwarded-For", client_addr_str);
|
http_add_header_field(&req->hdr, "X-Forwarded-For", client_addr_str);
|
||||||
} else {
|
} else {
|
||||||
@ -83,7 +83,7 @@ int rev_proxy_request_header(http_req *req, int enc) {
|
|||||||
http_add_header_field(&req->hdr, "X-Forwarded-For", buf1);
|
http_add_header_field(&req->hdr, "X-Forwarded-For", buf1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *xfh = http_get_header_field(&req->hdr, "X-Forwarded-Host");
|
const char *xfh = http_get_header_field(&req->hdr, "X-Forwarded-Host");
|
||||||
if (xfh == NULL) {
|
if (xfh == NULL) {
|
||||||
if (forwarded == NULL) {
|
if (forwarded == NULL) {
|
||||||
http_add_header_field(&req->hdr, "X-Forwarded-Host", host);
|
http_add_header_field(&req->hdr, "X-Forwarded-Host", host);
|
||||||
@ -104,7 +104,7 @@ int rev_proxy_request_header(http_req *req, int enc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *xfp = http_get_header_field(&req->hdr, "X-Forwarded-Proto");
|
const char *xfp = http_get_header_field(&req->hdr, "X-Forwarded-Proto");
|
||||||
if (xfp == NULL) {
|
if (xfp == NULL) {
|
||||||
if (forwarded == NULL) {
|
if (forwarded == NULL) {
|
||||||
http_add_header_field(&req->hdr, "X-Forwarded-Proto", enc ? "https" : "http");
|
http_add_header_field(&req->hdr, "X-Forwarded-Proto", enc ? "https" : "http");
|
||||||
@ -133,7 +133,7 @@ int rev_proxy_response_header(http_req *req, http_res *res, host_config *conf) {
|
|||||||
char buf2[256];
|
char buf2[256];
|
||||||
int p_len;
|
int p_len;
|
||||||
|
|
||||||
char *via = http_get_header_field(&res->hdr, "Via");
|
const char *via = http_get_header_field(&res->hdr, "Via");
|
||||||
p_len = snprintf(buf1, sizeof(buf1), "HTTP/%s %s", req->version, SERVER_NAME);
|
p_len = snprintf(buf1, sizeof(buf1), "HTTP/%s %s", req->version, SERVER_NAME);
|
||||||
if (p_len < 0 || p_len >= sizeof(buf1)) {
|
if (p_len < 0 || p_len >= sizeof(buf1)) {
|
||||||
print(ERR_STR "Appended part of header field 'Via' too long" CLR_STR);
|
print(ERR_STR "Appended part of header field 'Via' too long" CLR_STR);
|
||||||
@ -151,7 +151,7 @@ int rev_proxy_response_header(http_req *req, http_res *res, host_config *conf) {
|
|||||||
http_add_header_field(&res->hdr, "Via", buf2);
|
http_add_header_field(&res->hdr, "Via", buf2);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *location = http_get_header_field(&res->hdr, "Location");
|
const char *location = http_get_header_field(&res->hdr, "Location");
|
||||||
if (location != NULL) {
|
if (location != NULL) {
|
||||||
char *hostnames[] = {conf->name, conf->rev_proxy.hostname};
|
char *hostnames[] = {conf->name, conf->rev_proxy.hostname};
|
||||||
for (int i = 0; i < sizeof(hostnames) / sizeof(hostnames[0]); i++) {
|
for (int i = 0; i < sizeof(hostnames) / sizeof(hostnames[0]); i++) {
|
||||||
@ -307,7 +307,7 @@ int rev_proxy_init(http_req *req, http_res *res, http_status_ctx *ctx, host_conf
|
|||||||
goto proxy_err;
|
goto proxy_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *content_length = http_get_header_field(&req->hdr, "Content-Length");
|
const char *content_length = http_get_header_field(&req->hdr, "Content-Length");
|
||||||
if (content_length != NULL) {
|
if (content_length != NULL) {
|
||||||
unsigned long content_len = strtoul(content_length, NULL, 10);
|
unsigned long content_len = strtoul(content_length, NULL, 10);
|
||||||
if (client->buf_len - client->buf_off > 0) {
|
if (client->buf_len - client->buf_off > 0) {
|
||||||
@ -455,7 +455,7 @@ int rev_proxy_init(http_req *req, http_res *res, http_status_ctx *ctx, host_conf
|
|||||||
|
|
||||||
int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) {
|
int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) {
|
||||||
// TODO handle websockets
|
// TODO handle websockets
|
||||||
long ret;
|
long ret = 0;
|
||||||
char buffer[CHUNK_SIZE];
|
char buffer[CHUNK_SIZE];
|
||||||
char comp_out[CHUNK_SIZE];
|
char comp_out[CHUNK_SIZE];
|
||||||
char buf[256];
|
char buf[256];
|
||||||
@ -498,6 +498,7 @@ int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) {
|
|||||||
if (len_to_send == 0 && (flags & REV_PROXY_COMPRESS)) {
|
if (len_to_send == 0 && (flags & REV_PROXY_COMPRESS)) {
|
||||||
finish_comp = 1;
|
finish_comp = 1;
|
||||||
len = 0;
|
len = 0;
|
||||||
|
ptr = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
finish:
|
finish:
|
||||||
compress_free(&comp_ctx);
|
compress_free(&comp_ctx);
|
||||||
@ -519,8 +520,7 @@ int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) {
|
|||||||
long buf_len = len;
|
long buf_len = len;
|
||||||
if (flags & REV_PROXY_COMPRESS) {
|
if (flags & REV_PROXY_COMPRESS) {
|
||||||
avail_out = sizeof(comp_out);
|
avail_out = sizeof(comp_out);
|
||||||
compress_compress(&comp_ctx, next_in + len - avail_in, &avail_in, comp_out, &avail_out,
|
compress_compress(&comp_ctx, next_in + len - avail_in, &avail_in, comp_out, &avail_out, finish_comp);
|
||||||
finish_comp);
|
|
||||||
ptr = comp_out;
|
ptr = comp_out;
|
||||||
buf_len = (int) (sizeof(comp_out) - avail_out);
|
buf_len = (int) (sizeof(comp_out) - avail_out);
|
||||||
snd_len += (long) (len - avail_in);
|
snd_len += (long) (len - avail_in);
|
||||||
|
@ -136,10 +136,39 @@ int mime_is_compressible(const char *type) {
|
|||||||
|
|
||||||
int strcpy_rem_webroot(char *dst, const char *src, long len, const char *webroot) {
|
int strcpy_rem_webroot(char *dst, const char *src, long len, const char *webroot) {
|
||||||
strncpy(dst, src, len);
|
strncpy(dst, src, len);
|
||||||
if (webroot == NULL) return 0;
|
if (webroot == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
char *pos;
|
char *pos;
|
||||||
|
const unsigned long webroot_len = strlen(webroot);
|
||||||
|
if (webroot_len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
while ((pos = strstr(dst, webroot)) != NULL) {
|
while ((pos = strstr(dst, webroot)) != NULL) {
|
||||||
strcpy(pos, pos + strlen(webroot));
|
strcpy(pos, pos + webroot_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_trim(char **start, char **end) {
|
||||||
|
if (start == NULL || end == NULL || *start == NULL || *end == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
(*end)--;
|
||||||
|
while (*start[0] == ' ' || *start[0] == '\t' || *start[0] == '\r' || *start[0] == '\n') (*start)++;
|
||||||
|
while (*end[0] == ' ' || *end[0] == '\t' || *end[0] == '\r' || *end[0] == '\n') (*end)--;
|
||||||
|
(*end)++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_trim_lws(char **start, char **end) {
|
||||||
|
if (start == NULL || end == NULL || *start == NULL || *end == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
(*end)--;
|
||||||
|
while (*start[0] == ' ' || *start[0] == '\t') (*start)++;
|
||||||
|
while (*end[0] == ' ' || *end[0] == '\t') (*end)--;
|
||||||
|
(*end)++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -42,4 +42,8 @@ int mime_is_compressible(const char *type);
|
|||||||
|
|
||||||
int strcpy_rem_webroot(char *dst, const char *str, long len, const char *webroot);
|
int strcpy_rem_webroot(char *dst, const char *str, long len, const char *webroot);
|
||||||
|
|
||||||
|
int str_trim(char **start, char **end);
|
||||||
|
|
||||||
|
int str_trim_lws(char **start, char **end);
|
||||||
|
|
||||||
#endif //NECRONDA_SERVER_UTILS_H
|
#endif //NECRONDA_SERVER_UTILS_H
|
||||||
|
@ -9,13 +9,14 @@
|
|||||||
|
|
||||||
#include "necronda.h"
|
#include "necronda.h"
|
||||||
#include "necronda-server.h"
|
#include "necronda-server.h"
|
||||||
#include "client.c"
|
#include "client.h"
|
||||||
|
|
||||||
#include "lib/cache.h"
|
#include "lib/cache.h"
|
||||||
#include "lib/config.h"
|
#include "lib/config.h"
|
||||||
#include "lib/sock.h"
|
#include "lib/sock.h"
|
||||||
#include "lib/rev_proxy.h"
|
#include "lib/rev_proxy.h"
|
||||||
#include "lib/geoip.h"
|
#include "lib/geoip.h"
|
||||||
|
#include "lib/utils.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
Reference in New Issue
Block a user