Skip to content

Commit

Permalink
feat(gzip): added gzip to compress server responses.
Browse files Browse the repository at this point in the history
  • Loading branch information
martinopresnik authored and jkuri committed Mar 28, 2018
1 parent 4feb6dc commit 90125a0
Show file tree
Hide file tree
Showing 8 changed files with 367 additions and 28 deletions.
11 changes: 7 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
TARGET = build/bproxy
CC = clang
CFLAGS = -Wall -Iinclude -O3
DEPS = build/obj/jsmn.o build/obj/http_parser.o build/obj/http.o build/obj/config.o
LIBS = -luv -lpthread -ldl
DEPS = build/obj/jsmn.o build/obj/http_parser.o build/obj/http.o build/obj/config.o build/obj/gzip.o
LIBS = -luv -lpthread -ldl -lz

.PHONY: all bproxy checkdir clean

Expand All @@ -13,10 +13,10 @@ recompile: clean checkdir bproxy
install:
cp build/bproxy /usr/local/bin/bproxy

bproxy: jsmn.o http_parser.o http.o config.o
bproxy: jsmn.o http_parser.o http.o config.o gzip.o
$(CC) $(CFLAGS) $(DEPS) -o $(TARGET) src/bproxy.c $(LIBS)

bproxy_static: jsmn.o http_parser.o http.o config.o
bproxy_static: jsmn.o http_parser.o http.o config.o gzip.o
$(CC) -Wall -Iinclude -O3 -static -pthread -ldl $(DEPS) -o $(TARGET) src/bproxy.c /usr/lib/x86_64-linux-gnu/libuv.a

http_parser.o: checkdir
Expand All @@ -31,6 +31,9 @@ config.o: checkdir
jsmn.o: checkdir
$(CC) $(CFLAGS) -c src/jsmn.c -o build/obj/jsmn.o

gzip.o: checkdir
$(CC) $(CFLAGS) -c src/gzip.c -o build/obj/gzip.o

checkdir:
@mkdir -p build/obj

Expand Down
3 changes: 3 additions & 0 deletions include/bproxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "http.h"
#include "config.h"
#include "version.h"
#include "gzip.h"

typedef struct
{
Expand All @@ -45,6 +46,8 @@ typedef struct proxy_t
uv_connect_t connect_req;
uv_shutdown_t shutdown_req;
uv_write_t write_req;
gzip_state_t *gzip_state;
http_response_t response;
} proxy_t;

typedef struct proxy_ip_port
Expand Down
31 changes: 31 additions & 0 deletions include/gzip.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef GZIP_H
#define GZIP_H

#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>

#include "zlib.h"
#include "http.h"

typedef struct gzip_state_t
{
z_stream strm;
int current_size_in;
int current_size_out;
int current_size_buf_out;
boolean first_chunk;
boolean last_chunk;
char *http_header;
unsigned char *raw_body;
unsigned char *gzip_body;
char *chunk_body;
} gzip_state_t;

int gzip_init_state(gzip_state_t *state);
void gzip_free_state(gzip_state_t *state);
int gzip_compress(gzip_state_t *state);
void gzip_chunk_compress(gzip_state_t *state);
void gzip_init_headers(gzip_state_t *state, http_response_t *response);

#endif
52 changes: 38 additions & 14 deletions include/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

#include "uv.h"
#include "http_parser.h"
Expand All @@ -20,10 +21,14 @@
#define MAX_HEADERS 20
#define MAX_ELEMENT_SIZE 500

typedef enum {
true = 1,
false = 0
} boolean;
typedef bool boolean;

enum header_element
{
NONE = 0,
FIELD,
VALUE
};

typedef struct http_request_t
{
Expand All @@ -37,17 +42,29 @@ typedef struct http_request_t
uint8_t http_minor;
uint8_t keepalive;
uint8_t upgrade;
enum
{
NONE = 0,
FIELD,
VALUE
} last_header_element;
enum header_element last_header_element;
int num_headers;
char headers[MAX_HEADERS][2][MAX_ELEMENT_SIZE];
boolean enable_compression;
} http_request_t;

typedef struct http_response_t
{
http_parser parser;
char *raw_body;

int expected_data_len;
int processed_data_len;

size_t body_size;

enum header_element last_header_element;
int num_headers;
char headers[MAX_HEADERS][2][MAX_ELEMENT_SIZE];
char status_line[256];
boolean enable_compression;
} http_response_t;

typedef struct conn_t
{
int fd;
Expand All @@ -66,6 +83,11 @@ int headers_value_cb(http_parser *p, const char *buf, size_t length);
int body_cb(http_parser *p, const char *buf, size_t length);
int message_complete_cb(http_parser *p);

int response_message_begin_cb(http_parser *p);
int response_headers_complete_cb(http_parser *p);
int response_headers_field_cb(http_parser *p, const char *buf, size_t length);
int response_headers_value_cb(http_parser *p, const char *buf, size_t length);

void parse_requested_host(http_request_t *request);
int insert_header(char *src, char *resp);
void insert_substring(char *a, char *b, int position);
Expand All @@ -80,13 +102,15 @@ static http_parser_settings parser_settings =
.on_header_value = headers_value_cb,
.on_url = url_cb,
.on_headers_complete = headers_complete_cb,
.on_message_complete = message_complete_cb
};
.on_message_complete = message_complete_cb };

static http_parser_settings resp_parser_settings =
{
.on_body = body_cb
};
.on_message_begin = response_message_begin_cb,
.on_header_field = response_headers_field_cb,
.on_header_value = response_headers_value_cb,
.on_headers_complete = response_headers_complete_cb,
.on_body = body_cb };
// clang-format on

#endif // _BPROXY_HTTP_H_
82 changes: 74 additions & 8 deletions src/bproxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://github.com/bleenco/bproxy
*/
#include "bproxy.h"
#include "gzip.h"

void conn_init(uv_stream_t *handle)
{
Expand Down Expand Up @@ -87,27 +88,80 @@ void proxy_close_cb(uv_handle_t *peer)
proxy_t *proxy_conn = peer->data;
if (proxy_conn)
{
if(proxy_conn->gzip_state)
{
gzip_free_state(proxy_conn->gzip_state);
}
free(proxy_conn);
}
}

void compress_data(proxy_t *proxy_conn, char *data, int len)
{
proxy_conn->gzip_state->raw_body = (unsigned char*) data;
proxy_conn->gzip_state->current_size_in = len;

if (proxy_conn->response.processed_data_len > 0)
{
proxy_conn->gzip_state->first_chunk = false;
}

proxy_conn->response.processed_data_len += len;
if (proxy_conn->response.processed_data_len == proxy_conn->response.expected_data_len)
{
proxy_conn->gzip_state->last_chunk = true;
}

gzip_compress(proxy_conn->gzip_state);
gzip_chunk_compress(proxy_conn->gzip_state);
}

void proxy_read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
{
proxy_t *proxy_conn = handle->data;
conn_t *conn = proxy_conn->conn;

if (nread >= 0)
{
char *resp = malloc(nread + 1);
memcpy(resp, buf->base, nread);
resp[nread] = '\0';
char *resp = buf->base;
ssize_t resp_size = nread;

if (conn->request->enable_compression)
{
// enable gzip?
if (proxy_conn->gzip_state == NULL)
{
http_parser_execute(&proxy_conn->response.parser,
&resp_parser_settings, resp, nread);
if (proxy_conn->response.enable_compression)
{
// Parse status line
int status_line_len = strchr(resp, '\r') - resp;
memcpy(proxy_conn->response.status_line, resp, status_line_len);

proxy_conn->gzip_state = malloc(sizeof *proxy_conn->gzip_state);
gzip_init_state(proxy_conn->gzip_state);
gzip_init_headers(proxy_conn->gzip_state, &proxy_conn->response);

compress_data(proxy_conn, proxy_conn->response.raw_body,
proxy_conn->response.body_size);
resp = proxy_conn->gzip_state->chunk_body;
resp_size = proxy_conn->gzip_state->current_size_out;
}
else
{
conn->request->enable_compression = false;
}
}
else // Gzip initialized
{
compress_data(proxy_conn, resp, nread);
resp = proxy_conn->gzip_state->chunk_body;
resp_size = proxy_conn->gzip_state->current_size_out;
}
}

write_buf(conn->handle, resp, nread);
write_buf(conn->handle, resp, resp_size);
}
else
{
Expand All @@ -134,8 +188,12 @@ void proxy_connect_cb(uv_connect_t *req, int status)
proxy_conn->conn->proxy_handle = req->handle;
}

http_parser_init(&proxy_conn->response.parser, HTTP_RESPONSE);
proxy_conn->response.parser.data = &proxy_conn->response;

uv_read_start(req->handle, alloc_cb, proxy_read_cb);
write_buf(req->handle, proxy_conn->conn->request->raw, strlen(proxy_conn->conn->request->raw));
write_buf(req->handle, proxy_conn->conn->request->raw,
strlen(proxy_conn->conn->request->raw));
}

void proxy_http_request(char *ip, unsigned short port, conn_t *conn)
Expand All @@ -146,6 +204,8 @@ void proxy_http_request(char *ip, unsigned short port, conn_t *conn)
proxy_t *proxy_conn = malloc(sizeof(proxy_t));
proxy_conn->conn = conn;
proxy_conn->tcp.data = proxy_conn;
proxy_conn->gzip_state = NULL;
proxy_conn->response.processed_data_len = 0;

if (conn->request->upgrade)
{
Expand All @@ -154,7 +214,8 @@ void proxy_http_request(char *ip, unsigned short port, conn_t *conn)

uv_tcp_init(server->loop, &proxy_conn->tcp);
uv_tcp_keepalive(&proxy_conn->tcp, 1, 60);
uv_tcp_connect(&proxy_conn->connect_req, &proxy_conn->tcp, (const struct sockaddr *)&dest, proxy_connect_cb);
uv_tcp_connect(&proxy_conn->connect_req, &proxy_conn->tcp,
(const struct sockaddr *)&dest, proxy_connect_cb);
}

void read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
Expand All @@ -169,7 +230,8 @@ void read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
memcpy(conn->request->raw, buf->base, nread);
conn->request->raw[nread] = '\0';

size_t np = http_parser_execute(conn->parser, &parser_settings, buf->base, nread);
size_t np = http_parser_execute(conn->parser, &parser_settings, buf->base,
nread);
if (np != nread)
{
uv_shutdown_t *req;
Expand Down Expand Up @@ -251,7 +313,8 @@ void connection_cb(uv_stream_t *s, int status)

proxy_ip_port find_proxy_config(char *hostname)
{
proxy_ip_port ip_port = {.ip = NULL, .port = 0};
proxy_ip_port ip_port =
{.ip = NULL, .port = 0};

for (int i = 0; i < server->config->num_proxies; i++)
{
Expand Down Expand Up @@ -368,6 +431,9 @@ void usage()

int main(int argc, char **argv)
{
//test();
//return 0;

server = malloc(sizeof(server_t));
server->config = malloc(sizeof(config_t));
parse_args(argc, argv);
Expand Down
4 changes: 4 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,9 @@ void parse_config(const char *json_string, config_t *config)
free(proxy_str);
return;
}
else if (jsoneq(json_string, &t[i], "gzip-types") == 0)
{
printf("yeey");
}
}
}
Loading

0 comments on commit 90125a0

Please sign in to comment.