Preparing for transfer encoding compression

This commit is contained in:
2021-05-05 20:40:23 +02:00
parent c42f27e961
commit 45c5f20345
6 changed files with 104 additions and 41 deletions

View File

@ -13,6 +13,7 @@
#include "lib/fastcgi.h" #include "lib/fastcgi.h"
#include "lib/cache.h" #include "lib/cache.h"
#include "lib/geoip.h" #include "lib/geoip.h"
#include "lib/compress.h"
#include <string.h> #include <string.h>
#include <sys/select.h> #include <sys/select.h>
@ -407,18 +408,12 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
content_length = -1; content_length = -1;
use_fastcgi = 1; use_fastcgi = 1;
char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding"); int http_comp = http_get_compression(&req, &res);
char *content_type = http_get_header_field(&res.hdr, "Content-Type"); if (http_comp & COMPRESS_BR) {
char *content_encoding = http_get_header_field(&res.hdr, "Content-Encoding");
if (mime_is_compressible(content_type) && content_encoding == NULL && accept_encoding != NULL) {
if (strstr(accept_encoding, "br") != NULL) {
http_add_header_field(&res.hdr, "Content-Encoding", "br");
use_fastcgi |= FASTCGI_COMPRESS_BR; use_fastcgi |= FASTCGI_COMPRESS_BR;
} else if (strstr(accept_encoding, "gzip") != NULL) { } else if (http_comp & COMPRESS_GZ) {
http_add_header_field(&res.hdr, "Content-Encoding", "gzip");
use_fastcgi |= FASTCGI_COMPRESS_GZ; use_fastcgi |= FASTCGI_COMPRESS_GZ;
} }
}
if (http_get_header_field(&res.hdr, "Content-Length") == NULL) { if (http_get_header_field(&res.hdr, "Content-Length") == NULL) {
http_add_header_field(&res.hdr, "Transfer-Encoding", "chunked"); http_add_header_field(&res.hdr, "Transfer-Encoding", "chunked");
@ -428,8 +423,31 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
print("Reverse proxy for " BLD_STR "%s:%i" CLR_STR, conf->rev_proxy.hostname, conf->rev_proxy.port); print("Reverse proxy for " BLD_STR "%s:%i" CLR_STR, conf->rev_proxy.hostname, conf->rev_proxy.port);
http_remove_header_field(&res.hdr, "Date", HTTP_REMOVE_ALL); http_remove_header_field(&res.hdr, "Date", HTTP_REMOVE_ALL);
http_remove_header_field(&res.hdr, "Server", HTTP_REMOVE_ALL); http_remove_header_field(&res.hdr, "Server", HTTP_REMOVE_ALL);
ret = rev_proxy_init(&req, &res, conf, client, &custom_status, err_msg); ret = rev_proxy_init(&req, &res, conf, client, &custom_status, err_msg);
use_rev_proxy = ret == 0; use_rev_proxy = (ret == 0);
char *transfer_encoding = http_get_header_field(&res.hdr, "Transfer-Encoding");
if (use_rev_proxy && transfer_encoding == NULL) {
int http_comp = http_get_compression(&req, &res);
if (http_comp & COMPRESS_BR) {
//use_rev_proxy |= REV_PROXY_COMPRESS_BR;
} else if (http_comp & COMPRESS_GZ) {
//use_rev_proxy |= REV_PROXY_COMPRESS_GZ;
}
}
int chunked = transfer_encoding != NULL && strcmp(transfer_encoding, "chunked") == 0;
http_remove_header_field(&res.hdr, "Transfer-Encoding", HTTP_REMOVE_ALL);
printf("%i\n", use_rev_proxy);
ret = sprintf(buf0, "%s%s%s",
(use_rev_proxy & REV_PROXY_COMPRESS_BR) ? "br" :
((use_rev_proxy & REV_PROXY_COMPRESS_GZ) ? "gzip" : ""),
((use_rev_proxy & REV_PROXY_COMPRESS) && chunked) ? ", " : "",
chunked ? "chunked" : "");
if (ret > 0) {
http_add_header_field(&res.hdr, "Transfer-Encoding", buf0);
}
} else { } else {
print(ERR_STR "Unknown host type: %i" CLR_STR, conf->type); print(ERR_STR "Unknown host type: %i" CLR_STR, conf->type);
res.status = http_get_status(501); res.status = http_get_status(501);
@ -515,17 +533,21 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
} else if (use_fastcgi) { } else if (use_fastcgi) {
char *transfer_encoding = http_get_header_field(&res.hdr, "Transfer-Encoding"); 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); int flags = (chunked ? FASTCGI_CHUNKED : 0) | (use_fastcgi & FASTCGI_COMPRESS);
fastcgi_send(&php_fpm, client, flags); fastcgi_send(&php_fpm, client, flags);
} else if (use_rev_proxy) { } else if (use_rev_proxy) {
char *transfer_encoding = http_get_header_field(&res.hdr, "Transfer-Encoding"); 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;
char *content_len = http_get_header_field(&res.hdr, "Content-Length"); 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);
} }
rev_proxy_send(client, chunked, len_to_send);
int flags = (chunked ? REV_PROXY_CHUNKED : 0) | (use_rev_proxy & REV_PROXY_COMPRESS);
rev_proxy_send(client, len_to_send, flags);
} }
} }

View File

@ -7,6 +7,7 @@
#include "http.h" #include "http.h"
#include "utils.h" #include "utils.h"
#include "compress.h"
#include "../necronda-server.h" #include "../necronda-server.h"
#include <string.h> #include <string.h>
@ -312,3 +313,17 @@ const http_doc_info *http_get_status_info(const http_status *status) {
} }
return NULL; return NULL;
} }
int http_get_compression(const http_req *req, const http_res *res) {
char *accept_encoding = http_get_header_field(&req->hdr, "Accept-Encoding");
char *content_type = http_get_header_field(&res->hdr, "Content-Type");
char *content_encoding = http_get_header_field(&res->hdr, "Content-Encoding");
if (mime_is_compressible(content_type) && content_encoding == NULL && accept_encoding != NULL) {
if (strstr(accept_encoding, "br") != NULL) {
return COMPRESS_BR;
} else if (strstr(accept_encoding, "gzip") != NULL) {
return COMPRESS_GZ;
}
}
return 0;
}

View File

@ -122,4 +122,6 @@ char *http_get_date(char *buf, size_t size);
const http_doc_info *http_get_status_info(const http_status *status); const http_doc_info *http_get_status_info(const http_status *status);
int http_get_compression(const http_req *req, const http_res *res);
#endif //NECRONDA_SERVER_HTTP_H #endif //NECRONDA_SERVER_HTTP_H

View File

@ -7,6 +7,7 @@
#include "rev_proxy.h" #include "rev_proxy.h"
#include "utils.h" #include "utils.h"
#include "compress.h"
#include "../necronda-server.h" #include "../necronda-server.h"
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <string.h> #include <string.h>
@ -377,14 +378,29 @@ int rev_proxy_init(http_req *req, http_res *res, host_config *conf, sock *client
return -1; return -1;
} }
int rev_proxy_send(sock *client, int chunked, unsigned long len_to_send) { int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) {
// TODO handle websockets
long ret; long ret;
char buffer[CHUNK_SIZE]; char buffer[CHUNK_SIZE];
long len, snd_len; long len, snd_len;
// TODO handle websockets
// TODO compress -> Transfer-Encoding: br/gzip compress_ctx comp_ctx;
if (flags & REV_PROXY_COMPRESS_BR) {
flags &= ~REV_PROXY_COMPRESS_GZ;
if (compress_init(&comp_ctx, COMPRESS_BR) != 0) {
print(ERR_STR "Unable to init brotli: %s" CLR_STR, strerror(errno));
flags &= ~REV_PROXY_COMPRESS_BR;
}
} else if (flags & REV_PROXY_COMPRESS_GZ) {
flags &= ~REV_PROXY_COMPRESS_BR;
if (compress_init(&comp_ctx, COMPRESS_BR) != 0) {
print(ERR_STR "Unable to init gzip: %s" CLR_STR, strerror(errno));
flags &= ~REV_PROXY_COMPRESS_GZ;
}
}
do { do {
if (chunked) { if (flags & REV_PROXY_CHUNKED) {
ret = sock_recv(&rev_proxy, buffer, 16, MSG_PEEK); ret = sock_recv(&rev_proxy, buffer, 16, MSG_PEEK);
if (ret <= 0) { if (ret <= 0) {
print("Unable to receive: %s", sock_strerror(&rev_proxy)); print("Unable to receive: %s", sock_strerror(&rev_proxy));
@ -395,7 +411,6 @@ int rev_proxy_send(sock *client, int chunked, unsigned long len_to_send) {
char *pos = strstr(buffer, "\r\n"); char *pos = strstr(buffer, "\r\n");
len = pos - buffer + 2; len = pos - buffer + 2;
ret = sock_send(client, buffer, len, 0); ret = sock_send(client, buffer, len, 0);
sock_recv(&rev_proxy, buffer, len, 0); sock_recv(&rev_proxy, buffer, len, 0);
if (ret <= 0) break; if (ret <= 0) break;
} }
@ -410,7 +425,7 @@ int rev_proxy_send(sock *client, int chunked, unsigned long len_to_send) {
snd_len += ret; snd_len += ret;
} }
if (ret <= 0) break; if (ret <= 0) break;
if (chunked) { if (flags & REV_PROXY_CHUNKED) {
sock_recv(&rev_proxy, buffer, 2, 0); sock_recv(&rev_proxy, buffer, 2, 0);
ret = sock_send(client, "\r\n", 2, 0); ret = sock_send(client, "\r\n", 2, 0);
if (ret <= 0) { if (ret <= 0) {
@ -418,6 +433,6 @@ int rev_proxy_send(sock *client, int chunked, unsigned long len_to_send) {
break; break;
} }
} }
} while (chunked && len_to_send > 0); } while ((flags & REV_PROXY_CHUNKED) && len_to_send > 0);
return 0; return 0;
} }

View File

@ -8,6 +8,11 @@
#ifndef NECRONDA_SERVER_REV_PROXY_H #ifndef NECRONDA_SERVER_REV_PROXY_H
#define NECRONDA_SERVER_REV_PROXY_H #define NECRONDA_SERVER_REV_PROXY_H
#define REV_PROXY_CHUNKED 1
#define REV_PROXY_COMPRESS_GZ 2
#define REV_PROXY_COMPRESS_BR 4
#define REV_PROXY_COMPRESS 6
#include "http.h" #include "http.h"
#include "config.h" #include "config.h"
@ -22,6 +27,6 @@ int rev_proxy_response_header(http_req *req, http_res *res);
int rev_proxy_init(http_req *req, http_res *res, host_config *conf, sock *client, http_status *custom_status, int rev_proxy_init(http_req *req, http_res *res, host_config *conf, sock *client, http_status *custom_status,
char *err_msg); char *err_msg);
int rev_proxy_send(sock *client, int chunked, unsigned long len_to_send); int rev_proxy_send(sock *client, unsigned long len_to_send, int flags);
#endif //NECRONDA_SERVER_REV_PROXY_H #endif //NECRONDA_SERVER_REV_PROXY_H

View File

@ -104,25 +104,29 @@ int url_decode(const char *str, char *dec, long *size) {
} }
int mime_is_compressible(const char *type) { int mime_is_compressible(const char *type) {
char type_parsed[64];
strncpy(type_parsed, type, sizeof(type_parsed));
char *pos = strchr(type_parsed, ';');
if (pos != NULL) pos[0] = 0;
return return
strncmp(type, "text/", 5) == 0 || strncmp(type_parsed, "text/", 5) == 0 ||
strncmp(type, "message/", 7) == 0 || strncmp(type_parsed, "message/", 7) == 0 ||
strstr(type, "+xml") != NULL || strstr(type_parsed, "+xml") != NULL ||
strstr(type, "+json") != NULL || strstr(type_parsed, "+json") != NULL ||
strcmp(type, "application/javascript") == 0 || strcmp(type_parsed, "application/javascript") == 0 ||
strcmp(type, "application/json") == 0 || strcmp(type_parsed, "application/json") == 0 ||
strcmp(type, "application/xml") == 0 || strcmp(type_parsed, "application/xml") == 0 ||
strcmp(type, "application/x-www-form-urlencoded") == 0 || strcmp(type_parsed, "application/x-www-form-urlencoded") == 0 ||
strcmp(type, "application/x-tex") == 0 || strcmp(type_parsed, "application/x-tex") == 0 ||
strcmp(type, "application/x-httpd-php") == 0 || strcmp(type_parsed, "application/x-httpd-php") == 0 ||
strcmp(type, "application/x-latex") == 0 || strcmp(type_parsed, "application/x-latex") == 0 ||
strcmp(type, "application/vnd.ms-fontobject") == 0 || strcmp(type_parsed, "application/vnd.ms-fontobject") == 0 ||
strcmp(type, "application/x-font-ttf") == 0 || strcmp(type_parsed, "application/x-font-ttf") == 0 ||
strcmp(type, "application/x-javascript") == 0 || strcmp(type_parsed, "application/x-javascript") == 0 ||
strcmp(type, "application/x-web-app-manifest+json") == 0 || strcmp(type_parsed, "application/x-web-app-manifest+json") == 0 ||
strcmp(type, "font/eot") == 0 || strcmp(type_parsed, "font/eot") == 0 ||
strcmp(type, "font/opentype") == 0 || strcmp(type_parsed, "font/opentype") == 0 ||
strcmp(type, "image/bmp") == 0 || strcmp(type_parsed, "image/bmp") == 0 ||
strcmp(type, "image/vnd.microsoft.icon") == 0 || strcmp(type_parsed, "image/vnd.microsoft.icon") == 0 ||
strcmp(type, "image/x-icon") == 0; strcmp(type_parsed, "image/x-icon") == 0;
} }