Compare commits
6 Commits
db053121f2
...
0f75aeea7a
Author | SHA1 | Date | |
---|---|---|---|
0f75aeea7a
|
|||
933aac0f09
|
|||
7f1299feb4
|
|||
8435048150
|
|||
206ae3264d
|
|||
5e050512ad
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,6 +3,8 @@
|
|||||||
!src/**
|
!src/**
|
||||||
!doc
|
!doc
|
||||||
!doc/**
|
!doc/**
|
||||||
|
!test
|
||||||
|
!test/**
|
||||||
!Makefile
|
!Makefile
|
||||||
!.gitignore
|
!.gitignore
|
||||||
!README.md
|
!README.md
|
||||||
|
10
Makefile
10
Makefile
@@ -5,7 +5,7 @@ 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\""
|
||||||
|
|
||||||
.PHONY: all prod debug default permit clean
|
.PHONY: all prod debug default permit clean test
|
||||||
all: prod
|
all: prod
|
||||||
default: bin bin/lib bin/libsesimos.so bin/sesimos
|
default: bin bin/lib bin/libsesimos.so bin/sesimos
|
||||||
prod: CFLAGS += -O3
|
prod: CFLAGS += -O3
|
||||||
@@ -14,6 +14,10 @@ debug: default
|
|||||||
debian: CFLAGS += $(DEBIAN_OPTS)
|
debian: CFLAGS += $(DEBIAN_OPTS)
|
||||||
debian: prod
|
debian: prod
|
||||||
|
|
||||||
|
test: CFLAGS += -include test/mock_*.h
|
||||||
|
test: bin bin/test
|
||||||
|
bin/test
|
||||||
|
|
||||||
|
|
||||||
bin:
|
bin:
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
@@ -22,6 +26,10 @@ bin/lib:
|
|||||||
mkdir -p bin/lib
|
mkdir -p bin/lib
|
||||||
|
|
||||||
|
|
||||||
|
bin/test: test/mock_*.c test/test_*.c src/lib/utils.c src/lib/sock.c
|
||||||
|
$(CC) -o $@ $(CFLAGS) $^ -lcriterion
|
||||||
|
|
||||||
|
|
||||||
bin/%.o: src/%.c
|
bin/%.o: src/%.c
|
||||||
$(CC) -c -o $@ $(CFLAGS) $<
|
$(CC) -c -o $@ $(CFLAGS) $<
|
||||||
|
|
||||||
|
@@ -179,8 +179,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
int change_proto = strncmp(uri.uri, "/.well-known/", 13) != 0 && !client->enc;
|
int change_proto = strncmp(uri.uri, "/.well-known/", 13) != 0 && !client->enc;
|
||||||
if (strcmp(uri.uri, buf0) != 0 || change_proto) {
|
if (strcmp(uri.uri, buf0) != 0 || change_proto) {
|
||||||
res.status = http_get_status(308);
|
res.status = http_get_status(308);
|
||||||
size = sizeof(buf0);
|
size = url_encode(uri.uri, strlen(uri.uri), buf0, sizeof(buf0));
|
||||||
url_encode(uri.uri, buf0, &size);
|
|
||||||
if (change_proto) {
|
if (change_proto) {
|
||||||
p_len = snprintf(buf1, sizeof(buf1), "https://%s%s", host, buf0);
|
p_len = snprintf(buf1, sizeof(buf1), "https://%s%s", host, buf0);
|
||||||
if (p_len < 0 || p_len >= sizeof(buf1)) {
|
if (p_len < 0 || p_len >= sizeof(buf1)) {
|
||||||
|
@@ -17,8 +17,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/evp.h>
|
||||||
#include <malloc.h>
|
|
||||||
|
|
||||||
|
|
||||||
int cache_continue = 1;
|
int cache_continue = 1;
|
||||||
@@ -81,14 +80,12 @@ int cache_process(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILE *file;
|
FILE *file;
|
||||||
char *buf = malloc(CACHE_BUF_SIZE);
|
char buf[CACHE_BUF_SIZE], comp_buf[CACHE_BUF_SIZE], filename_comp_gz[256], filename_comp_br[256];
|
||||||
char *comp_buf = malloc(CACHE_BUF_SIZE);
|
|
||||||
char filename_comp_gz[256];
|
|
||||||
char filename_comp_br[256];
|
|
||||||
unsigned long read;
|
unsigned long read;
|
||||||
int compress;
|
int compress;
|
||||||
SHA_CTX ctx;
|
EVP_MD_CTX *ctx;
|
||||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
unsigned char hash[EVP_MAX_MD_SIZE];
|
||||||
|
unsigned int md_len;
|
||||||
int cache_changed = 0;
|
int cache_changed = 0;
|
||||||
int p_len_gz, p_len_br;
|
int p_len_gz, p_len_br;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -97,7 +94,9 @@ int cache_process(void) {
|
|||||||
if (cache[i].filename[0] != 0 && cache[i].meta.etag[0] == 0 && !cache[i].is_updating) {
|
if (cache[i].filename[0] != 0 && cache[i].meta.etag[0] == 0 && !cache[i].is_updating) {
|
||||||
cache[i].is_updating = 1;
|
cache[i].is_updating = 1;
|
||||||
fprintf(stdout, "[cache] Hashing file %s\n", cache[i].filename);
|
fprintf(stdout, "[cache] Hashing file %s\n", cache[i].filename);
|
||||||
SHA1_Init(&ctx);
|
|
||||||
|
ctx = EVP_MD_CTX_new();
|
||||||
|
EVP_DigestInit(ctx, EVP_sha1());
|
||||||
file = fopen(cache[i].filename, "rb");
|
file = fopen(cache[i].filename, "rb");
|
||||||
compress = mime_is_compressible(cache[i].meta.type);
|
compress = mime_is_compressible(cache[i].meta.type);
|
||||||
|
|
||||||
@@ -131,11 +130,8 @@ int cache_process(void) {
|
|||||||
p_len_br = snprintf(filename_comp_br, sizeof(filename_comp_br),
|
p_len_br = snprintf(filename_comp_br, sizeof(filename_comp_br),
|
||||||
"%.*s/.sesimos/cache/%s.br",
|
"%.*s/.sesimos/cache/%s.br",
|
||||||
cache[i].webroot_len, cache[i].filename, buf);
|
cache[i].webroot_len, cache[i].filename, buf);
|
||||||
if (p_len_gz < 0 || p_len_gz >= sizeof(filename_comp_gz) ||
|
if (p_len_gz < 0 || p_len_gz >= sizeof(filename_comp_gz) || p_len_br < 0 || p_len_br >= sizeof(filename_comp_br)) {
|
||||||
p_len_br < 0 || p_len_br >= sizeof(filename_comp_br))
|
fprintf(stderr, ERR_STR "Unable to open cached file: File name for compressed file too long" CLR_STR "\n");
|
||||||
{
|
|
||||||
fprintf(stderr, ERR_STR "Unable to open cached file: "
|
|
||||||
"File name for compressed file too long" CLR_STR "\n");
|
|
||||||
goto comp_err;
|
goto comp_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,21 +155,19 @@ int cache_process(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ((read = fread(buf, 1, CACHE_BUF_SIZE, file)) > 0) {
|
while ((read = fread(buf, 1, CACHE_BUF_SIZE, file)) > 0) {
|
||||||
SHA1_Update(&ctx, buf, read);
|
EVP_DigestUpdate(ctx, buf, read);
|
||||||
if (compress) {
|
if (compress) {
|
||||||
unsigned long avail_in, avail_out;
|
unsigned long avail_in, avail_out;
|
||||||
avail_in = read;
|
avail_in = read;
|
||||||
do {
|
do {
|
||||||
avail_out = CACHE_BUF_SIZE;
|
avail_out = CACHE_BUF_SIZE;
|
||||||
compress_compress_mode(&comp_ctx, COMPRESS_GZ,buf + read - avail_in, &avail_in,
|
compress_compress_mode(&comp_ctx, COMPRESS_GZ,buf + read - avail_in, &avail_in, comp_buf, &avail_out, feof(file));
|
||||||
comp_buf, &avail_out, feof(file));
|
|
||||||
fwrite(comp_buf, 1, CACHE_BUF_SIZE - avail_out, comp_file_gz);
|
fwrite(comp_buf, 1, CACHE_BUF_SIZE - avail_out, comp_file_gz);
|
||||||
} while (avail_in != 0 || avail_out != CACHE_BUF_SIZE);
|
} while (avail_in != 0 || avail_out != CACHE_BUF_SIZE);
|
||||||
avail_in = read;
|
avail_in = read;
|
||||||
do {
|
do {
|
||||||
avail_out = CACHE_BUF_SIZE;
|
avail_out = CACHE_BUF_SIZE;
|
||||||
compress_compress_mode(&comp_ctx, COMPRESS_BR, buf + read - avail_in, &avail_in,
|
compress_compress_mode(&comp_ctx, COMPRESS_BR, buf + read - avail_in, &avail_in, comp_buf, &avail_out, feof(file));
|
||||||
comp_buf, &avail_out, feof(file));
|
|
||||||
fwrite(comp_buf, 1, CACHE_BUF_SIZE - avail_out, comp_file_br);
|
fwrite(comp_buf, 1, CACHE_BUF_SIZE - avail_out, comp_file_br);
|
||||||
} while (avail_in != 0 || avail_out != CACHE_BUF_SIZE);
|
} while (avail_in != 0 || avail_out != CACHE_BUF_SIZE);
|
||||||
}
|
}
|
||||||
@@ -190,9 +184,12 @@ int cache_process(void) {
|
|||||||
memset(cache[i].meta.filename_comp_gz, 0, sizeof(cache[i].meta.filename_comp_gz));
|
memset(cache[i].meta.filename_comp_gz, 0, sizeof(cache[i].meta.filename_comp_gz));
|
||||||
memset(cache[i].meta.filename_comp_br, 0, sizeof(cache[i].meta.filename_comp_br));
|
memset(cache[i].meta.filename_comp_br, 0, sizeof(cache[i].meta.filename_comp_br));
|
||||||
}
|
}
|
||||||
SHA1_Final(hash, &ctx);
|
|
||||||
|
EVP_DigestFinal(ctx, hash, &md_len);
|
||||||
|
EVP_MD_CTX_free(ctx);
|
||||||
|
|
||||||
memset(cache[i].meta.etag, 0, sizeof(cache[i].meta.etag));
|
memset(cache[i].meta.etag, 0, sizeof(cache[i].meta.etag));
|
||||||
for (int j = 0; j < SHA_DIGEST_LENGTH; j++) {
|
for (int j = 0; j < md_len; j++) {
|
||||||
sprintf(cache[i].meta.etag + j * 2, "%02x", hash[j]);
|
sprintf(cache[i].meta.etag + j * 2, "%02x", hash[j]);
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
@@ -207,8 +204,6 @@ int cache_process(void) {
|
|||||||
cache_file = fopen("/var/sesimos/server/cache", "wb");
|
cache_file = fopen("/var/sesimos/server/cache", "wb");
|
||||||
if (cache_file == NULL) {
|
if (cache_file == NULL) {
|
||||||
fprintf(stderr, ERR_STR "Unable to open cache file: %s" CLR_STR "\n", strerror(errno));
|
fprintf(stderr, ERR_STR "Unable to open cache file: %s" CLR_STR "\n", strerror(errno));
|
||||||
free(buf);
|
|
||||||
free(comp_buf);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fwrite(cache, sizeof(cache_entry), CACHE_ENTRIES, cache_file);
|
fwrite(cache, sizeof(cache_entry), CACHE_ENTRIES, cache_file);
|
||||||
@@ -217,8 +212,7 @@ int cache_process(void) {
|
|||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(buf);
|
|
||||||
free(comp_buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -623,35 +623,16 @@ int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len) {
|
|||||||
int fastcgi_receive_chunked(fastcgi_conn *conn, sock *client) {
|
int fastcgi_receive_chunked(fastcgi_conn *conn, sock *client) {
|
||||||
long ret;
|
long ret;
|
||||||
unsigned long next_len;
|
unsigned long next_len;
|
||||||
char tmp[16];
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = sock_recv(client, tmp, sizeof(tmp), MSG_PEEK);
|
ret = sock_get_chunk_header(client);
|
||||||
if (ret < 0) return -2;
|
if (ret < 0) return (int) ret;
|
||||||
else if (ret < 2) continue;
|
|
||||||
|
|
||||||
int len = 0;
|
|
||||||
for (int i = 0; i < ret; i++) {
|
|
||||||
char ch = tmp[i];
|
|
||||||
if (ch == '\r') {
|
|
||||||
continue;
|
|
||||||
} else if (ch == '\n') {
|
|
||||||
len = i + 1;
|
|
||||||
break;
|
|
||||||
} else if (!((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))) {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (len == 0) continue;
|
|
||||||
|
|
||||||
next_len = strtol(tmp, NULL, 16);
|
|
||||||
ret = sock_recv(client, tmp, len, 0);
|
|
||||||
if (ret < 0) return -2;
|
|
||||||
|
|
||||||
|
next_len = ret;
|
||||||
if (next_len <= 0) break;
|
if (next_len <= 0) break;
|
||||||
|
|
||||||
ret = fastcgi_receive(conn, client, next_len);
|
ret = fastcgi_receive(conn, client, next_len);
|
||||||
if (ret < 0) return ret;
|
if (ret < 0) return (int) ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -478,20 +478,18 @@ int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) {
|
|||||||
do {
|
do {
|
||||||
snd_len = 0;
|
snd_len = 0;
|
||||||
if (flags & REV_PROXY_CHUNKED) {
|
if (flags & REV_PROXY_CHUNKED) {
|
||||||
char *pos;
|
ret = sock_get_chunk_header(&rev_proxy);
|
||||||
ret = sock_recv(&rev_proxy, buffer, 16, MSG_PEEK);
|
if (ret < 0) {
|
||||||
if (ret <= 0) goto err0;
|
if (ret == -1) {
|
||||||
|
print("Unable to receive from server: Malformed chunk header");
|
||||||
len_to_send = strtol(buffer, NULL, 16);
|
} else {
|
||||||
pos = strstr(buffer, "\r\n");
|
print("Unable to receive from server: %s", sock_strerror(&rev_proxy));
|
||||||
len = pos - buffer + 2;
|
}
|
||||||
sock_recv(&rev_proxy, buffer, len, 0);
|
|
||||||
if (ret <= 0) {
|
|
||||||
err0:
|
|
||||||
print("Unable to receive from server: %s", sock_strerror(&rev_proxy));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
len_to_send = ret;
|
||||||
|
ret = 1;
|
||||||
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;
|
||||||
@@ -525,11 +523,14 @@ int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) {
|
|||||||
if (buf_len != 0) {
|
if (buf_len != 0) {
|
||||||
len = sprintf(buf, "%lX\r\n", buf_len);
|
len = sprintf(buf, "%lX\r\n", buf_len);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
if (flags & REV_PROXY_CHUNKED) ret = sock_send(client, buf, len, 0);
|
if (flags & REV_PROXY_CHUNKED) ret = sock_send(client, buf, len, 0);
|
||||||
if (ret <= 0) goto err;
|
if (ret <= 0) goto err;
|
||||||
|
|
||||||
ret = sock_send(client, ptr, buf_len, 0);
|
ret = sock_send(client, ptr, buf_len, 0);
|
||||||
if (ret <= 0) goto err;
|
if (ret <= 0) goto err;
|
||||||
if (!(flags & REV_PROXY_COMPRESS)) snd_len += ret;
|
if (!(flags & REV_PROXY_COMPRESS)) snd_len += ret;
|
||||||
|
|
||||||
if (flags & REV_PROXY_CHUNKED) ret = sock_send(client, "\r\n", 2, 0);
|
if (flags & REV_PROXY_CHUNKED) ret = sock_send(client, "\r\n", 2, 0);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
err:
|
err:
|
||||||
@@ -545,7 +546,7 @@ int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) {
|
|||||||
if (flags & REV_PROXY_CHUNKED) sock_recv(&rev_proxy, buffer, 2, 0);
|
if (flags & REV_PROXY_CHUNKED) sock_recv(&rev_proxy, buffer, 2, 0);
|
||||||
} while ((flags & REV_PROXY_CHUNKED) && len_to_send > 0);
|
} while ((flags & REV_PROXY_CHUNKED) && len_to_send > 0);
|
||||||
|
|
||||||
if (ret <= 0) return (int) -1;
|
if (ret <= 0) return -1;
|
||||||
|
|
||||||
if (flags & REV_PROXY_CHUNKED) {
|
if (flags & REV_PROXY_CHUNKED) {
|
||||||
ret = sock_send(client, "0\r\n\r\n", 5, 0);
|
ret = sock_send(client, "0\r\n\r\n", 5, 0);
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
@@ -72,11 +73,8 @@ long sock_send(sock *s, void *buf, unsigned long len, int flags) {
|
|||||||
long sock_recv(sock *s, void *buf, unsigned long len, int flags) {
|
long sock_recv(sock *s, void *buf, unsigned long len, int flags) {
|
||||||
long ret;
|
long ret;
|
||||||
if (s->enc) {
|
if (s->enc) {
|
||||||
if (flags & MSG_PEEK) {
|
int (*func)(SSL*, void*, int) = (flags & MSG_PEEK) ? SSL_peek : SSL_read;
|
||||||
ret = SSL_peek(s->ssl, buf, (int) len);
|
ret = func(s->ssl, buf, (int) len);
|
||||||
} else {
|
|
||||||
ret = SSL_read(s->ssl, buf, (int) len);
|
|
||||||
}
|
|
||||||
s->_ssl_error = ERR_get_error();
|
s->_ssl_error = ERR_get_error();
|
||||||
} else {
|
} else {
|
||||||
ret = recv(s->socket, buf, len, flags);
|
ret = recv(s->socket, buf, len, flags);
|
||||||
@@ -93,7 +91,7 @@ long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigne
|
|||||||
while (send_len < len) {
|
while (send_len < len) {
|
||||||
next_len = (buf_len < (len - send_len)) ? buf_len : (len - send_len);
|
next_len = (buf_len < (len - send_len)) ? buf_len : (len - send_len);
|
||||||
ret = sock_recv(src, buf, next_len, 0);
|
ret = sock_recv(src, buf, next_len, 0);
|
||||||
if (ret < 0) return -2;
|
if (ret <= 0) return -2;
|
||||||
next_len = ret;
|
next_len = ret;
|
||||||
ret = sock_send(dst, buf, next_len, send_len + next_len < len ? MSG_MORE : 0);
|
ret = sock_send(dst, buf, next_len, send_len + next_len < len ? MSG_MORE : 0);
|
||||||
if (ret < 0) return -1;
|
if (ret < 0) return -1;
|
||||||
@@ -107,31 +105,12 @@ long sock_splice_chunked(sock *dst, sock *src, void *buf, unsigned long buf_len)
|
|||||||
long ret;
|
long ret;
|
||||||
unsigned long send_len = 0;
|
unsigned long send_len = 0;
|
||||||
unsigned long next_len;
|
unsigned long next_len;
|
||||||
char tmp[16];
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = sock_recv(src, tmp, sizeof(tmp), MSG_PEEK);
|
ret = sock_get_chunk_header(src);
|
||||||
if (ret < 0) return -2;
|
|
||||||
else if (ret < 2) continue;
|
|
||||||
|
|
||||||
int len = 0;
|
|
||||||
for (int i = 0; i < ret; i++) {
|
|
||||||
char ch = tmp[i];
|
|
||||||
if (ch == '\r') {
|
|
||||||
continue;
|
|
||||||
} else if (ch == '\n') {
|
|
||||||
len = i + 1;
|
|
||||||
break;
|
|
||||||
} else if (!((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))) {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (len == 0) continue;
|
|
||||||
|
|
||||||
next_len = strtol(tmp, NULL, 16);
|
|
||||||
ret = sock_recv(src, tmp, len, 0);
|
|
||||||
if (ret < 0) return -2;
|
if (ret < 0) return -2;
|
||||||
|
|
||||||
|
next_len = ret;
|
||||||
if (next_len <= 0) break;
|
if (next_len <= 0) break;
|
||||||
|
|
||||||
ret = sock_splice(dst, src, buf, buf_len, next_len);
|
ret = sock_splice(dst, src, buf, buf_len, next_len);
|
||||||
@@ -187,3 +166,39 @@ int sock_poll_read(sock *sockets[], sock *readable[], sock *error[], int n_sock,
|
|||||||
int sock_poll_write(sock *sockets[], sock *writable[], sock *error[], int n_sock, int *n_writable, int *n_error, int timeout_ms) {
|
int sock_poll_write(sock *sockets[], sock *writable[], sock *error[], int n_sock, int *n_writable, int *n_error, int timeout_ms) {
|
||||||
return sock_poll(sockets, writable, error, n_sock, n_writable, n_error, POLLOUT, timeout_ms);
|
return sock_poll(sockets, writable, error, n_sock, n_writable, n_error, POLLOUT, timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long sock_parse_chunk_header(const char *buf, long len, long *ret_len) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char ch = buf[i];
|
||||||
|
if (ch == '\r') {
|
||||||
|
continue;
|
||||||
|
} else if (ch == '\n') {
|
||||||
|
if (ret_len != NULL) *ret_len = i + 1;
|
||||||
|
return strtol(buf, NULL, 16);
|
||||||
|
} else if (!((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long sock_get_chunk_header(sock *s) {
|
||||||
|
long ret, len;
|
||||||
|
char buf[16];
|
||||||
|
|
||||||
|
do {
|
||||||
|
print("debug1"); // TODO remove
|
||||||
|
ret = sock_recv(s, buf, sizeof(buf), MSG_PEEK);
|
||||||
|
if (ret <= 0) return -2;
|
||||||
|
else if (ret < 2) continue;
|
||||||
|
|
||||||
|
ret = sock_parse_chunk_header(buf, ret, &len);
|
||||||
|
if (ret == -2) return -1;
|
||||||
|
} while (ret < 0);
|
||||||
|
|
||||||
|
if (sock_recv(s, buf, len, 0) != len)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -44,4 +44,8 @@ int sock_poll_read(sock *sockets[], sock *readable[], sock *error[], int n_sock,
|
|||||||
|
|
||||||
int sock_poll_write(sock *sockets[], sock *writable[], sock *error[], int n_sock, int *n_writable, int *n_error, int timeout_ms);
|
int sock_poll_write(sock *sockets[], sock *writable[], sock *error[], int n_sock, int *n_writable, int *n_error, int timeout_ms);
|
||||||
|
|
||||||
|
long sock_parse_chunk_header(const char *buf, long len, long *ret_len);
|
||||||
|
|
||||||
|
long sock_get_chunk_header(sock *s);
|
||||||
|
|
||||||
#endif //SESIMOS_SOCK_H
|
#endif //SESIMOS_SOCK_H
|
||||||
|
@@ -15,69 +15,77 @@
|
|||||||
|
|
||||||
char *log_prefix;
|
char *log_prefix;
|
||||||
|
|
||||||
|
static const char base64_encode_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
static const int base64_mod_table[3] = {0, 2, 1};
|
||||||
|
|
||||||
|
|
||||||
char *format_duration(unsigned long micros, char *buf) {
|
char *format_duration(unsigned long micros, char *buf) {
|
||||||
if (micros < 10000) {
|
if (micros < 10000) {
|
||||||
sprintf(buf, "%.1f ms", (double) micros / 1000);
|
sprintf(buf, "%.1f ms", (double) micros / 1000);
|
||||||
} else if (micros < 1000000) {
|
} else if (micros < 1000000 - 1000) {
|
||||||
sprintf(buf, "%li ms", micros / 1000);
|
sprintf(buf, "%.0f ms", (double) micros / 1000);
|
||||||
} else if (micros < 60000000) {
|
} else if (micros < 60000000 - 1000000) {
|
||||||
sprintf(buf, "%.1f s", (double) micros / 1000000);
|
sprintf(buf, "%.1f s", (double) micros / 1000000);
|
||||||
} else if (micros < 6000000000) {
|
} else if (micros < 6000000000) {
|
||||||
sprintf(buf, "%.1f min", (double) micros / 1000000 / 60);
|
sprintf(buf, "%.1f min", (double) micros / 1000000 / 60);
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf, "%li min", micros / 1000000 / 60);
|
sprintf(buf, "%.0f min", (double) micros / 1000000 / 60);
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int url_encode_component(const char *str, char *enc, long *size) {
|
int url_encode_component(const void *in, size_t size_in, char *out, size_t size_out) {
|
||||||
char *ptr = enc;
|
int size = 0;
|
||||||
char ch;
|
|
||||||
memset(enc, 0, *size);
|
// Encode control characters
|
||||||
for (int i = 0; i < strlen(str); i++, ptr++) {
|
for (int i = 0; i < size_in; i++) {
|
||||||
if ((ptr - enc) >= *size) {
|
unsigned char ch = ((unsigned char *) in)[i];
|
||||||
return -1;
|
if (ch == ' ') {
|
||||||
|
ch = '+';
|
||||||
|
} else if (
|
||||||
|
ch <= 0x20 || ch >= 0x7F ||
|
||||||
|
!((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') ||
|
||||||
|
ch == '-' || ch == '_' || ch == '.' || ch == '!' || ch == '~' || ch == '*' || ch == '\'' ||
|
||||||
|
ch == '(' || ch == ')')
|
||||||
|
) {
|
||||||
|
size += 3;
|
||||||
|
if (size < size_out) sprintf(out + size - 3, "%%%02X", ch);
|
||||||
|
ch = 0;
|
||||||
}
|
}
|
||||||
ch = str[i];
|
|
||||||
if (ch == ':' || ch == '/' || ch == '?' || ch == '#' || ch == '[' || ch == ']' || ch == '@' || ch == '!' ||
|
if (ch != 0) {
|
||||||
ch == '$' || ch == '&' || ch == '\'' || ch == '(' || ch == ')' || ch == '*' || ch == '+' || ch == ',' ||
|
size++;
|
||||||
ch == ';' || ch == '=' || ch < ' ' || ch > '~') {
|
if (size < size_out) out[size - 1] = (char) ch;
|
||||||
if ((ptr - enc + 2) >= *size) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sprintf(ptr, "%%%02X", ch);
|
|
||||||
ptr += 2;
|
|
||||||
} else if (ch == ' ') {
|
|
||||||
ptr[0] = '+';
|
|
||||||
} else {
|
|
||||||
ptr[0] = ch;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*size = ptr - enc;
|
|
||||||
return 0;
|
// Set terminating null byte
|
||||||
|
if (size_out > 0) out[size < size_out ? size : size_out - 1] = 0;
|
||||||
|
|
||||||
|
// Return theoretical size
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int url_encode(const char *str, char *enc, long *size) {
|
int url_encode(const void *in, size_t size_in, char *out, size_t size_out) {
|
||||||
char *ptr = enc;
|
int size = 0;
|
||||||
unsigned char ch;
|
|
||||||
memset(enc, 0, *size);
|
// Encode control characters
|
||||||
for (int i = 0; i < strlen(str); i++, ptr++) {
|
for (int i = 0; i < size_in; i++) {
|
||||||
if ((ptr - enc) >= *size) {
|
unsigned char ch = ((unsigned char *) in)[i];
|
||||||
return -1;
|
if (ch <= 0x20 || ch >= 0x7F) {
|
||||||
}
|
size += 3;
|
||||||
ch = str[i];
|
if (size < size_out) sprintf(out + size - 3, "%%%02X", ch);
|
||||||
if (ch > 0x7F || ch == ' ') {
|
|
||||||
if ((ptr - enc + 2) >= *size) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sprintf(ptr, "%%%02X", ch);
|
|
||||||
ptr += 2;
|
|
||||||
} else {
|
} else {
|
||||||
ptr[0] = (char) ch;
|
size++;
|
||||||
|
if (size < size_out) out[size - 1] = (char) ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*size = ptr - enc;
|
|
||||||
return 0;
|
// Set terminating null byte
|
||||||
|
if (size_out > 0) out[size < size_out ? size : size_out - 1] = 0;
|
||||||
|
|
||||||
|
// Return theoretical size
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int url_decode(const char *str, char *dec, long *size) {
|
int url_decode(const char *str, char *dec, long *size) {
|
||||||
|
@@ -21,9 +21,6 @@
|
|||||||
|
|
||||||
extern char *log_prefix;
|
extern char *log_prefix;
|
||||||
|
|
||||||
static const char base64_encode_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
static const int base64_mod_table[3] = {0, 2, 1};
|
|
||||||
|
|
||||||
|
|
||||||
#define out_1(fmt) fprintf(stdout, "%s" fmt "\n", log_prefix)
|
#define out_1(fmt) fprintf(stdout, "%s" fmt "\n", log_prefix)
|
||||||
#define out_2(fmt, args...) fprintf(stdout, "%s" fmt "\n", log_prefix, args)
|
#define out_2(fmt, args...) fprintf(stdout, "%s" fmt "\n", log_prefix, args)
|
||||||
@@ -37,9 +34,9 @@ static const int base64_mod_table[3] = {0, 2, 1};
|
|||||||
|
|
||||||
char *format_duration(unsigned long micros, char *buf);
|
char *format_duration(unsigned long micros, char *buf);
|
||||||
|
|
||||||
int url_encode_component(const char *str, char *enc, long *size);
|
int url_encode_component(const void *in, size_t size_in, char *out, size_t size_out);
|
||||||
|
|
||||||
int url_encode(const char *str, char *enc, long *size);
|
int url_encode(const void *in, size_t size_in, char *out, size_t size_out);
|
||||||
|
|
||||||
int url_decode(const char *str, char *dec, long *size);
|
int url_decode(const char *str, char *dec, long *size);
|
||||||
|
|
||||||
|
28
test/mock_socket.c
Normal file
28
test/mock_socket.c
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "mock_socket.h"
|
||||||
|
|
||||||
|
int mock_socket_send_mode;
|
||||||
|
|
||||||
|
static int sockets[256] = {0};
|
||||||
|
static int n_sockets = 0;
|
||||||
|
|
||||||
|
int mock_socket(int domain, int type, int protocol) {
|
||||||
|
printf("SOCKET\n");
|
||||||
|
return (n_sockets++) + 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t mock_send(int fd, const void *buf, size_t n, int flags) {
|
||||||
|
printf("SEND\n");
|
||||||
|
if (mock_socket_send_mode == MOCK_SOCKET_MODE_EINTR) {
|
||||||
|
errno = EINTR;
|
||||||
|
return rand() % ((ssize_t) n) - 1;
|
||||||
|
} else if (mock_socket_send_mode == MOCK_SOCKET_MODE_CLOSED) {
|
||||||
|
errno = 0; // TODO
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ssize_t) n;
|
||||||
|
}
|
20
test/mock_socket.h
Normal file
20
test/mock_socket.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
#ifndef SESIMOS_MOCK_SOCKET_H
|
||||||
|
#define SESIMOS_MOCK_SOCKET_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MOCK_SOCKET_MODE_SUCCESS 0
|
||||||
|
#define MOCK_SOCKET_MODE_EINTR 1
|
||||||
|
#define MOCK_SOCKET_MODE_CLOSED 2
|
||||||
|
|
||||||
|
#define socket(args...) mock_socket(args)
|
||||||
|
#define send(args...) mock_send(args)
|
||||||
|
|
||||||
|
extern int mock_socket_send_mode;
|
||||||
|
|
||||||
|
int mock_socket(int domain, int type, int protocol);
|
||||||
|
|
||||||
|
ssize_t mock_send(int fd, const void *buf, size_t n, int flags);
|
||||||
|
|
||||||
|
#endif //SESIMOS_MOCK_SOCKET_H
|
33
test/mock_ssl.c
Normal file
33
test/mock_ssl.c
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
|
||||||
|
|
||||||
|
int SSL_write(SSL *ssl, const void *buf, int num) {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSL_read(SSL *ssl, void *buf, int num) {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSL_peek(SSL *ssl, void *buf, int num) {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSL_get_error(const SSL *s, int ret_code) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ERR_reason_error_string(unsigned long e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSL_shutdown(SSL *s) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSL_free(SSL *ssl) {}
|
||||||
|
|
||||||
|
unsigned long ERR_get_error(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
15
test/test_sock.c
Normal file
15
test/test_sock.c
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#include <criterion/criterion.h>
|
||||||
|
#include "mock_socket.h"
|
||||||
|
#include "../src/lib/sock.h"
|
||||||
|
|
||||||
|
|
||||||
|
Test(sock, sock_send_1) {
|
||||||
|
int fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
|
sock s;
|
||||||
|
s.enc = 0;
|
||||||
|
s.socket = fd;
|
||||||
|
|
||||||
|
long ret = sock_send(&s, "Hello", 5, 0);
|
||||||
|
cr_assert_eq(ret, 5);
|
||||||
|
}
|
86
test/test_utils.c
Normal file
86
test/test_utils.c
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
#include <criterion/criterion.h>
|
||||||
|
#include <criterion/parameterized.h>
|
||||||
|
|
||||||
|
#include "../src/lib/utils.h"
|
||||||
|
|
||||||
|
struct url_encode_t {
|
||||||
|
long in_size;
|
||||||
|
char in[256];
|
||||||
|
long exp_size;
|
||||||
|
char exp[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct format_duration_t {
|
||||||
|
unsigned long micros;
|
||||||
|
char exp[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
ParameterizedTestParameters(utils, url_encode) {
|
||||||
|
static struct url_encode_t params[] = {
|
||||||
|
{0, "", 0, ""},
|
||||||
|
{9, "Test Text", 11, "Test%20Text"},
|
||||||
|
{21, "Text\0with\0null\0bytes\0", 29, "Text%00with%00null%00bytes%00"},
|
||||||
|
{59, "Text&with+some/strange_symbols-or#something?I%don't|know...", 59, "Text&with+some/strange_symbols-or#something?I%don't|know..."},
|
||||||
|
{33, "Data\x12With\x13Some" "\xFF" "Control" "\xFE" "Characters", 41, "Data%12With%13Some%FFControl%FECharacters"}
|
||||||
|
};
|
||||||
|
return cr_make_param_array(struct url_encode_t, params, sizeof(params) / sizeof(struct url_encode_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterizedTest(struct url_encode_t *param, utils, url_encode) {
|
||||||
|
char out[256];
|
||||||
|
cr_assert_eq(url_encode(param->in, param->in_size, out, sizeof(out)), param->exp_size);
|
||||||
|
cr_assert_arr_eq(out, param->exp, param->exp_size + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(utils, url_encode_bytes) {
|
||||||
|
char out[4];
|
||||||
|
char exp[4];
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
unsigned char ch = i;
|
||||||
|
if (ch <= 0x20 || ch >= 0x7F) {
|
||||||
|
cr_assert_eq(url_encode(&ch, 1, out, sizeof(out)), 3);
|
||||||
|
sprintf(exp, "%%%02X", ch);
|
||||||
|
cr_assert_str_eq(out, exp);
|
||||||
|
} else {
|
||||||
|
cr_assert_eq(url_encode(&ch, 1, out, sizeof(out)), 1);
|
||||||
|
sprintf(exp, "%c", ch);
|
||||||
|
cr_assert_str_eq(out, exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(utils, url_encode_invalid) {
|
||||||
|
cr_assert_eq(url_encode("Hello", 5, NULL, 0), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterizedTestParameters(utils, format_duration) {
|
||||||
|
static struct format_duration_t params[] = {
|
||||||
|
{0, "0.0 ms"},
|
||||||
|
{1, "0.0 ms"},
|
||||||
|
{90, "0.1 ms"},
|
||||||
|
{100, "0.1 ms"},
|
||||||
|
{110, "0.1 ms"},
|
||||||
|
{900, "0.9 ms"},
|
||||||
|
{1000, "1.0 ms"},
|
||||||
|
{9000, "9.0 ms"},
|
||||||
|
{9899, "9.9 ms"},
|
||||||
|
{9999, "10.0 ms"},
|
||||||
|
{10000, "10 ms"},
|
||||||
|
{11999, "12 ms"},
|
||||||
|
{999999, "1.0 s"},
|
||||||
|
{1000000, "1.0 s"},
|
||||||
|
{3000000, "3.0 s"},
|
||||||
|
{1000000 * 60, "1.0 min"},
|
||||||
|
{1000000 * 60 * 30L - 30000000, "29.5 min"},
|
||||||
|
{1000000 * 60 * 60L, "60.0 min"},
|
||||||
|
{1000000 * 60 * 120L, "120 min"},
|
||||||
|
};
|
||||||
|
return cr_make_param_array(struct format_duration_t, params, sizeof(params) / sizeof(struct format_duration_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterizedTest(struct format_duration_t *param, utils, format_duration) {
|
||||||
|
char buf[16];
|
||||||
|
cr_assert_str_eq(format_duration(param->micros, buf), param->exp);
|
||||||
|
}
|
Reference in New Issue
Block a user