Skip to content

Commit

Permalink
feat(additional headers): Adding additional http headers to request a…
Browse files Browse the repository at this point in the history
…nd response closes #23
  • Loading branch information
martinopresnik authored and jkuri committed Jun 1, 2018
1 parent 8756a51 commit f4e2c70
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 78 deletions.
1 change: 1 addition & 0 deletions bproxy.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"src/http.c",
"src/cJSON.c",
"src/http_link.c",
"src/common.c",
"src/bproxy.c"
]
}]
Expand Down
8 changes: 8 additions & 0 deletions include/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef COMMON_H
#define COMMON_H

#include "string.h"

char *strnstr(char *s, size_t n, char *find);

#endif
2 changes: 1 addition & 1 deletion include/gzip.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ typedef struct gzip_state_t
char *chunk_body;
} gzip_state_t;

int gzip_init_state(gzip_state_t *state);
int gzip_init_state(gzip_state_t *state, char *http_header);
void gzip_free_state(gzip_state_t *state);
int gzip_compress(gzip_state_t *state);
void gzip_chunk_compress(gzip_state_t *state);
Expand Down
10 changes: 8 additions & 2 deletions include/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ typedef struct http_request_s
enum header_element last_header_element;
int num_headers;
char headers[MAX_HEADERS][2][MAX_ELEMENT_SIZE];
char http_header[MAX_HEADERS * 2 * (MAX_ELEMENT_SIZE + 2) + 256];
int http_header_len;
boolean enable_compression;
http_parser parser;
int content_length;
Expand All @@ -76,6 +78,8 @@ typedef struct http_response_s
enum header_element last_header_element;
int num_headers;
char headers[MAX_HEADERS][2][MAX_ELEMENT_SIZE];
char http_header[MAX_HEADERS * 2 * (MAX_ELEMENT_SIZE + 2) + 256];
int http_header_len;
char status_line[256];
boolean enable_compression;
gzip_state_t *gzip_state;
Expand All @@ -86,15 +90,16 @@ typedef struct http_link_context_s
http_request_t request;
http_response_t response;
config_t *server_config; // TODO: Move this out, and use only part of configuration needed
bool https;
enum
{
TYPE_REQUEST,
TYPE_WEBSOCKET
} type;
bool initial_reply;
char peer_ip[45];

// Data for logging
char peer_ip[45];
uint64_t request_time;
time_t request_timestamp;
} http_link_context_t;
Expand All @@ -118,7 +123,8 @@ void insert_substring(char *a, char *b, int position);
char *substring(char *string, int position, int length);
void http_404_response(char *resp);

void gzip_init_headers(http_response_t *response);
void http_init_response_headers(http_response_t *response, bool compressed);
void http_init_request_headers(http_link_context_t *context);

// clang-format off
static http_parser_settings parser_settings =
Expand Down
15 changes: 9 additions & 6 deletions src/bproxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ void conn_init(uv_stream_t *handle)
memset(conn, 0, sizeof *conn);
conn->handle = handle;

CHECK(uv_link_source_init(&conn->source, (uv_stream_t *)conn->handle));
conn->source.data = conn;

CHECK(uv_link_observer_init(&conn->observer));
CHECK(uv_link_init(&conn->http_link, &http_link_methods));
http_link_init(&conn->http_link, &conn->http_link_context, server->config);

// Get remote address
struct sockaddr_storage addr = {0};
int alen = sizeof addr;
Expand All @@ -134,12 +141,7 @@ void conn_init(uv_stream_t *handle)
ssl_conn = ntohs(((const struct sockaddr_in6 *)&addr)->sin6_port) == server->config->secure_port;
}

CHECK(uv_link_source_init(&conn->source, (uv_stream_t *)conn->handle));
conn->source.data = conn;

CHECK(uv_link_observer_init(&conn->observer));
CHECK(uv_link_init(&conn->http_link, &http_link_methods));
http_link_init(&conn->http_link, &conn->http_link_context, server->config);
conn->http_link_context.https = ssl_conn;

if (ssl_conn)
{
Expand Down Expand Up @@ -257,6 +259,7 @@ void proxy_read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
{
log_error("could not read from socket! (%s)", uv_strerror(nread));
}
// TODO: Fix premature closing of client connection (in case of pending writes)
conn_close(conn);
}
if (nread <= 0)
Expand Down
31 changes: 31 additions & 0 deletions src/common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "common.h"

/*
* n represents size of string s. size of find is determinate by strlen
*/
char *strnstr(char *s, size_t n, char *find)
{
size_t find_len = strlen(find);
if (find_len == 0)
{
return s;
}
if (n < find_len)
{
return NULL;
}
char *s_end = &s[n - find_len + 1];
while (1)
{
while ((*s) != (*find) && s != s_end)
++s;
if (s == s_end)
{
return NULL;
}
if (strncmp(s++, find, find_len) == 0)
{
return --s;
}
}
}
7 changes: 2 additions & 5 deletions src/gzip.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <string.h>
#include "stdint.h"

int gzip_init_state(gzip_state_t *state)
int gzip_init_state(gzip_state_t *state, char *http_header)
{
int ret_status = 0;

Expand All @@ -25,9 +25,7 @@ int gzip_init_state(gzip_state_t *state)
state->raw_body = NULL;
state->gzip_body = malloc(buf_sizes);
state->chunk_body = malloc(buf_sizes);
state->http_header = malloc(buf_sizes);

memset(state->http_header, 0, buf_sizes);
state->http_header = http_header;

state->current_size_buf_out = buf_sizes;

Expand All @@ -46,7 +44,6 @@ void gzip_free_state(gzip_state_t *state)
deflateEnd(&state->strm);
free(state->gzip_body);
free(state->chunk_body);
free(state->http_header);
}
}

Expand Down
100 changes: 66 additions & 34 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

int message_begin_cb(http_parser *p)
{
http_request_t *request = p->data;
http_link_context_t *context = p->data;
http_request_t *request = &context->request;
for (int i = 0; i < MAX_HEADERS; i++)
{
request->headers[i][0][0] = 0;
Expand All @@ -24,7 +25,8 @@ int message_begin_cb(http_parser *p)

int url_cb(http_parser *p, const char *buf, size_t len)
{
http_request_t *request = p->data;
http_link_context_t *context = p->data;
http_request_t *request = &context->request;
free(request->url);
request->url = malloc((len + 1) * sizeof(char));
memcpy(request->url, buf, len);
Expand All @@ -34,7 +36,8 @@ int url_cb(http_parser *p, const char *buf, size_t len)

int headers_field_cb(http_parser *p, const char *buf, size_t len)
{
http_request_t *request = p->data;
http_link_context_t *context = p->data;
http_request_t *request = &context->request;
if (request->last_header_element != FIELD)
{
request->num_headers++;
Expand All @@ -46,42 +49,49 @@ int headers_field_cb(http_parser *p, const char *buf, size_t len)

int headers_value_cb(http_parser *p, const char *buf, size_t len)
{
http_request_t *request = p->data;
http_link_context_t *context = p->data;
http_request_t *request = &context->request;
strncat(request->headers[request->num_headers - 1][1], buf, len);
request->last_header_element = VALUE;
return 0;
}

int headers_complete_cb(http_parser *p)
{
http_request_t *req = (http_request_t *)p->data;
req->keepalive = http_should_keep_alive(p);
req->http_major = p->http_major;
req->http_minor = p->http_minor;
req->method = p->method;
req->upgrade = p->upgrade;
req->content_length = p->content_length;
http_link_context_t *context = p->data;
http_request_t *request = &context->request;
request->keepalive = http_should_keep_alive(p);
request->http_major = p->http_major;
request->http_minor = p->http_minor;
request->method = p->method;
request->upgrade = p->upgrade;
request->content_length = p->content_length;

req->enable_compression = false;
request->enable_compression = false;

for (int i = 0; i < req->num_headers; i++)
for (int i = 0; i < request->num_headers; i++)
{
if (strcasecmp(req->headers[i][0], "Host") == 0)
if (strcasecmp(request->headers[i][0], "Host") == 0)
{
int nob = strlen(req->headers[i][1]);
memcpy(req->host, req->headers[i][1], nob);
req->host[nob] = '\0';
parse_requested_host(req);
int nob = strlen(request->headers[i][1]);
memcpy(request->host, request->headers[i][1], nob);
request->host[nob] = '\0';
parse_requested_host(request);
}
else if (strcasecmp(req->headers[i][0], "Accept-Encoding") == 0)
else if (strcasecmp(request->headers[i][0], "Accept-Encoding") == 0)
{
if (strstr(req->headers[i][1], "gzip"))
if (strstr(request->headers[i][1], "gzip"))
{
req->enable_compression = true;
request->enable_compression = true;
}
}
}

// Forwarded: by=<identifier>; for=<identifier>; host=<host>; proto=<http|https>
char *proto = context->https ? "https" : "http";
strcpy(request->headers[request->num_headers][0], "Forwarded");
sprintf(request->headers[request->num_headers][1], "by=%s; for=%s; host=%s; proto=%s\r\n", "bproxy", context->peer_ip, request->host, proto);
++request->num_headers;
return 0;
}

Expand Down Expand Up @@ -262,27 +272,49 @@ int response_headers_complete_cb(http_parser *p)
return 0;
}

void gzip_init_headers(http_response_t *response)
void http_init_response_headers(http_response_t *response, bool compressed)
{
gzip_state_t *state = response->gzip_state;
strcat(state->http_header, response->status_line);
strcat(state->http_header, "\r\n");
memset(response->http_header, 0, sizeof response->http_header);
strcat(response->http_header, response->status_line);
strcat(response->http_header, "\r\n");
for (int i = 0; i < response->num_headers; ++i)
{
// Skip responses of non compressed headers
if (strcasecmp(response->headers[i][0], "Content-Length") == 0 || strcasecmp(response->headers[i][0], "Accept-Ranges") == 0)
if (compressed && (strcasecmp(response->headers[i][0], "Content-Length") == 0 || strcasecmp(response->headers[i][0], "Accept-Ranges") == 0))
{
continue;
}

strcat(state->http_header, response->headers[i][0]);
strcat(state->http_header, ": ");
strcat(state->http_header, response->headers[i][1]);
strcat(state->http_header, "\r\n");
strcat(response->http_header, response->headers[i][0]);
strcat(response->http_header, ": ");
strcat(response->http_header, response->headers[i][1]);
strcat(response->http_header, "\r\n");
}
if (compressed)
{
// Add gzip headers
strcat(response->http_header, "Transfer-Encoding: chunked\r\n");
strcat(response->http_header, "Content-Encoding: gzip\r\n");
}
strcat(response->http_header, "Via: bproxy\r\n");
strcat(response->http_header, "\r\n");
response->http_header_len = strlen(response->http_header);
}

void http_init_request_headers(http_link_context_t *context)
{
http_request_t *request = &context->request;
memset(request->http_header, 0, sizeof request->http_header);
strcat(request->http_header, request->status_line);
strcat(request->http_header, "\r\n");
for (int i = 0; i < request->num_headers; ++i)
{
strcat(request->http_header, request->headers[i][0]);
strcat(request->http_header, ": ");
strcat(request->http_header, request->headers[i][1]);
strcat(request->http_header, "\r\n");
}
// Add gzip headers
strcat(state->http_header, "Transfer-Encoding: chunked\r\n");
strcat(state->http_header, "Content-Encoding: gzip\r\n");

strcat(state->http_header, "\r\n");
strcat(request->http_header, "\r\n");
request->http_header_len = strlen(request->http_header);
}
Loading

0 comments on commit f4e2c70

Please sign in to comment.