Compare commits
	
		
			22 Commits
		
	
	
		
			v4.6
			...
			0f75aeea7a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0f75aeea7a | |||
| 933aac0f09 | |||
| 7f1299feb4 | |||
| 8435048150 | |||
| 206ae3264d | |||
| 5e050512ad | |||
| db053121f2 | |||
| 89a9d4b9d6 | |||
| bc7c3591a2 | |||
| 1859c432c8 | |||
| 33ec943e8b | |||
| b30f9fa56d | |||
| 90e324cf87 | |||
| e7e1e7b18f | |||
| 63b1ca5d6a | |||
| 54313551fc | |||
| 92779e5dba | |||
| 100eb1597d | |||
| f4c3345445 | |||
| 893316ebfa | |||
| 6a511732af | |||
| bb895c5bca | 
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,8 +1,10 @@ | |||||||
| * | * | ||||||
| !src | !src | ||||||
| !src/** | !src/** | ||||||
| !docs | !doc | ||||||
| !docs/** | !doc/** | ||||||
|  | !test | ||||||
|  | !test/** | ||||||
| !Makefile | !Makefile | ||||||
| !.gitignore | !.gitignore | ||||||
| !README.md | !README.md | ||||||
|   | |||||||
							
								
								
									
										87
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								Makefile
									
									
									
									
									
								
							| @@ -5,22 +5,79 @@ 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\"" | ||||||
|  |  | ||||||
| packages: | .PHONY: all prod debug default permit clean test | ||||||
| 	@echo "Installing packages..." | all: prod | ||||||
| 	sudo apt install gcc php-fpm libmagic-dev libssl-dev libmaxminddb-dev | default: bin bin/lib bin/libsesimos.so bin/sesimos | ||||||
| 	@echo "Finished downloading!" | prod: CFLAGS += -O3 | ||||||
|  | prod: default | ||||||
|  | debug: default | ||||||
|  | debian: CFLAGS += $(DEBIAN_OPTS) | ||||||
|  | debian: prod | ||||||
|  |  | ||||||
|  | test: CFLAGS += -include test/mock_*.h | ||||||
|  | test: bin bin/test | ||||||
|  | 	bin/test | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bin: | ||||||
|  | 	mkdir -p bin | ||||||
|  |  | ||||||
|  | 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 | ||||||
|  | 	$(CC) -c -o $@ $(CFLAGS) $< | ||||||
|  |  | ||||||
|  | bin/lib/%.o: src/lib/%.c | ||||||
|  | 	$(CC) -c -o $@ $(CFLAGS) -fPIC $< | ||||||
|  |  | ||||||
|  | bin/libsesimos.so: bin/lib/cache.o bin/lib/compress.o bin/lib/config.o bin/lib/fastcgi.o bin/lib/geoip.o \ | ||||||
|  | 				   bin/lib/http.o bin/lib/http_static.o bin/lib/rev_proxy.o bin/lib/sock.o bin/lib/uri.o \ | ||||||
|  | 				   bin/lib/utils.o bin/lib/websocket.o | ||||||
|  | 	$(CC) -o $@ --shared -fPIC $(CFLAGS) $^ $(LIBS) | ||||||
|  |  | ||||||
|  | bin/sesimos: bin/server.o bin/client.o | ||||||
|  | 	$(CC) -o $@ $^ $(CFLAGS) -Lbin -lsesimos -Wl,-rpath=$(shell pwd)/bin $(LIBS) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bin/server.o: src/server.h src/defs.h src/client.h src/lib/cache.h src/lib/config.h src/lib/sock.h \ | ||||||
|  |               src/lib/rev_proxy.h src/lib/geoip.h src/lib/utils.h | ||||||
|  |  | ||||||
|  | bin/client.o: src/client.h src/defs.h src/server.h src/lib/utils.h src/lib/config.h src/lib/sock.h \ | ||||||
|  |               src/lib/http.h src/lib/rev_proxy.h src/lib/fastcgi.h src/lib/cache.h src/lib/geoip.h src/lib/compress.h \ | ||||||
|  |               src/lib/websocket.h | ||||||
|  |  | ||||||
|  | bin/lib/cache.o: src/lib/cache.h src/lib/utils.h src/lib/uri.h src/lib/compress.h | ||||||
|  |  | ||||||
|  | bin/lib/compress.o: src/lib/compress.h | ||||||
|  |  | ||||||
|  | bin/lib/config.o: src/lib/config.h src/lib/utils.h src/lib/uri.h | ||||||
|  |  | ||||||
|  | bin/lib/fastcgi.o: src/lib/fastcgi.h src/server.h src/lib/utils.h src/lib/compress.h src/lib/http.h \ | ||||||
|  |                    src/lib/uri.h src/lib/include/fastcgi.h | ||||||
|  |  | ||||||
|  | bin/lib/geoip.o: src/lib/geoip.h | ||||||
|  |  | ||||||
|  | bin/lib/http.o: src/lib/http.h src/lib/utils.h src/lib/compress.h src/lib/sock.h | ||||||
|  |  | ||||||
|  | bin/lib/rev_proxy.o: src/lib/rev_proxy.h src/defs.h src/server.h src/lib/compress.h | ||||||
|  |  | ||||||
|  | bin/lib/sock.o: src/lib/sock.h | ||||||
|  |  | ||||||
|  | bin/lib/uri.o: src/lib/uri.h src/lib/utils.h | ||||||
|  |  | ||||||
|  | bin/lib/utils.o: src/lib/utils.h | ||||||
|  |  | ||||||
|  | bin/lib/websocket.o: src/lib/websocket.h src/defs.h src/lib/utils.h src/lib/sock.h | ||||||
|  |  | ||||||
|  |  | ||||||
| permit: | permit: | ||||||
| 	sudo setcap 'cap_net_bind_service=+ep' "$(shell pwd)/bin/sesimos" | 	sudo setcap 'cap_net_bind_service=+ep' "$(shell pwd)/bin/sesimos" | ||||||
|  |  | ||||||
| compile: | clean: | ||||||
| 	@mkdir -p bin | 	rm -rf bin/* | ||||||
| 	$(CC) src/lib/*.c -o bin/libsesimos.so --shared -fPIC $(CFLAGS) $(LIBS) |  | ||||||
| 	$(CC) src/server.c src/client.c -o bin/sesimos $(CFLAGS) $(LIBS) \ |  | ||||||
| 		-Lbin -lsesimos -Wl,-rpath=$(shell pwd)/bin |  | ||||||
|  |  | ||||||
| compile-prod: |  | ||||||
| 	@mkdir -p bin |  | ||||||
| 	$(CC) src/lib/*.c -o bin/libsesimos.so --shared -fPIC $(CFLAGS) $(LIBS) $(DEBIAN_OPTS) -O3 |  | ||||||
| 	$(CC) src/server.c src/client.c -o bin/sesimos $(CFLAGS) $(LIBS) $(DEBIAN_OPTS) -O3 \ |  | ||||||
| 		-Lbin -lsesimos -Wl,-rpath=$(shell pwd)/bin |  | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ Sesimos – Secure, simple, modern web server | |||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
|  |  | ||||||
| See [docs/example.conf](docs/example.conf) for more details. | See [doc/example.conf](doc/example.conf) for more details. | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Global directives | ### Global directives | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								src/client.c
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								src/client.c
									
									
									
									
									
								
							| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Client connection and request handlers |  * @brief Client connection and request handlers | ||||||
|  * src/client.c |  * @file src/client.c | ||||||
|  * Lorenz Stechauner, 2020-12-03 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-03 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "defs.h" | #include "defs.h" | ||||||
| @@ -29,7 +30,7 @@ | |||||||
| #include <arpa/inet.h> | #include <arpa/inet.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| int server_keep_alive = 1; | volatile sig_atomic_t server_keep_alive = 1; | ||||||
| struct timeval client_timeout = {.tv_sec = CLIENT_TIMEOUT, .tv_usec = 0}; | struct timeval client_timeout = {.tv_sec = CLIENT_TIMEOUT, .tv_usec = 0}; | ||||||
|  |  | ||||||
| char *log_client_prefix, *log_conn_prefix, *log_req_prefix, *client_geoip; | char *log_client_prefix, *log_conn_prefix, *log_req_prefix, *client_geoip; | ||||||
| @@ -48,7 +49,7 @@ host_config *get_host_config(const char *host) { | |||||||
|     return NULL; |     return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| void client_terminate() { | void client_terminate(int _) { | ||||||
|     server_keep_alive = 0; |     server_keep_alive = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -85,7 +86,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|  |  | ||||||
|     clock_gettime(CLOCK_MONOTONIC, &begin); |     clock_gettime(CLOCK_MONOTONIC, &begin); | ||||||
|  |  | ||||||
|     ret = sock_poll_read(&client, NULL, 1, CLIENT_TIMEOUT * 1000); |     ret = sock_poll_read(&client, NULL, NULL, 1, NULL, NULL, CLIENT_TIMEOUT * 1000); | ||||||
|  |  | ||||||
|     http_add_header_field(&res.hdr, "Date", http_get_date(buf0, sizeof(buf0))); |     http_add_header_field(&res.hdr, "Date", http_get_date(buf0, sizeof(buf0))); | ||||||
|     http_add_header_field(&res.hdr, "Server", SERVER_STR); |     http_add_header_field(&res.hdr, "Server", SERVER_STR); | ||||||
| @@ -178,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)) { | ||||||
| @@ -200,12 +200,6 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|         goto respond; |         goto respond; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (http_get_header_field(&req.hdr, "Transfer-Encoding") != NULL) { |  | ||||||
|         sprintf(err_msg, "This server is unable to process requests with the Transfer-Encoding header field."); |  | ||||||
|         res.status = http_get_status(501); |  | ||||||
|         goto respond; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (conf->type == CONFIG_TYPE_LOCAL) { |     if (conf->type == CONFIG_TYPE_LOCAL) { | ||||||
|         if (strcmp(req.method, "TRACE") == 0) { |         if (strcmp(req.method, "TRACE") == 0) { | ||||||
|             res.status = http_get_status(200); |             res.status = http_get_status(200); | ||||||
| @@ -253,7 +247,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|                 goto respond; |                 goto respond; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (http_get_header_field(&req.hdr, "Content-Length") != NULL) { |             if (http_get_header_field(&req.hdr, "Content-Length") != NULL || http_get_header_field(&req.hdr, "Transfer-Encoding") != NULL) { | ||||||
|                 res.status = http_get_status(400); |                 res.status = http_get_status(400); | ||||||
|                 sprintf(err_msg, "A GET request must not contain a payload"); |                 sprintf(err_msg, "A GET request must not contain a payload"); | ||||||
|                 goto respond; |                 goto respond; | ||||||
| @@ -396,18 +390,23 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             const 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"); | ||||||
|  |             const char *client_transfer_encoding = http_get_header_field(&req.hdr, "Transfer-Encoding"); | ||||||
|             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); | ||||||
|                 if (ret != 0) { |             } else if (client_transfer_encoding != NULL && strstr(client_transfer_encoding, "chunked") != NULL) { | ||||||
|                     if (ret < 0) { |                 ret = fastcgi_receive_chunked(&fcgi_conn, client); | ||||||
|                         goto abort; |             } else { | ||||||
|                     } else { |                 ret = 0; | ||||||
|                         sprintf(err_msg, "Unable to communicate with FastCGI socket."); |             } | ||||||
|                     } |             if (ret != 0) { | ||||||
|                     res.status = http_get_status(502); |                 if (ret < 0) { | ||||||
|                     goto respond; |                     goto abort; | ||||||
|  |                 } else { | ||||||
|  |                     sprintf(err_msg, "Unable to communicate with FastCGI socket."); | ||||||
|                 } |                 } | ||||||
|  |                 res.status = http_get_status(502); | ||||||
|  |                 goto respond; | ||||||
|             } |             } | ||||||
|             fastcgi_close_stdin(&fcgi_conn); |             fastcgi_close_stdin(&fcgi_conn); | ||||||
|  |  | ||||||
| @@ -495,7 +494,6 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|                     use_rev_proxy = (strcmp(buf0, ws_accept) == 0) ? 2 : 1; |                     use_rev_proxy = (strcmp(buf0, ws_accept) == 0) ? 2 : 1; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 print("Fail Test1"); |  | ||||||
|                 ctx.status = 101; |                 ctx.status = 101; | ||||||
|                 ctx.origin = INTERNAL; |                 ctx.origin = INTERNAL; | ||||||
|                 res.status = http_get_status(501); |                 res.status = http_get_status(501); | ||||||
| @@ -679,7 +677,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|             } |             } | ||||||
|         } else if (use_fastcgi) { |         } else if (use_fastcgi) { | ||||||
|             const 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 && strstr(transfer_encoding, "chunked") != NULL); | ||||||
|  |  | ||||||
|             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); | ||||||
| @@ -720,12 +718,6 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int | |||||||
|     } |     } | ||||||
|     http_free_req(&req); |     http_free_req(&req); | ||||||
|     http_free_res(&res); |     http_free_res(&res); | ||||||
|     if (client->buf != NULL) { |  | ||||||
|         free(client->buf); |  | ||||||
|         client->buf = NULL; |  | ||||||
|         client->buf_off = 0; |  | ||||||
|         client->buf_len = 0; |  | ||||||
|     } |  | ||||||
|     return !client_keep_alive; |     return !client_keep_alive; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Client connection and request handlers (header file) |  * @brief Client connection and request handlers (header file) | ||||||
|  * src/client.h |  * @file src/client.h | ||||||
|  * Lorenz Stechauner, 2022-08-16 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2022-08-16 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_CLIENT_H | #ifndef SESIMOS_CLIENT_H | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Definitions |  * @brief Definitions | ||||||
|  * src/defs.h |  * @file src/defs.h | ||||||
|  * Lorenz Stechauner, 2021-05-04 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-05-04 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_DEF_H | #ifndef SESIMOS_DEF_H | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * File cache implementation |  * @brief File cache implementation | ||||||
|  * src/lib/cache.c |  * @file src/lib/cache.c | ||||||
|  * Lorenz Stechauner, 2020-12-19 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-19 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "cache.h" | #include "cache.h" | ||||||
| @@ -16,15 +17,14 @@ | |||||||
| #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; | ||||||
| magic_t magic; | magic_t magic; | ||||||
| cache_entry *cache; | cache_entry *cache; | ||||||
|  |  | ||||||
| int magic_init() { | int magic_init(void) { | ||||||
|     magic = magic_open(MAGIC_MIME); |     magic = magic_open(MAGIC_MIME); | ||||||
|     if (magic == NULL) { |     if (magic == NULL) { | ||||||
|         fprintf(stderr, ERR_STR "Unable to open magic cookie: %s" CLR_STR "\n", strerror(errno)); |         fprintf(stderr, ERR_STR "Unable to open magic cookie: %s" CLR_STR "\n", strerror(errno)); | ||||||
| @@ -37,11 +37,11 @@ int magic_init() { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| void cache_process_term() { | void cache_process_term(int _) { | ||||||
|     cache_continue = 0; |     cache_continue = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int cache_process() { | int cache_process(void) { | ||||||
|     signal(SIGINT, cache_process_term); |     signal(SIGINT, cache_process_term); | ||||||
|     signal(SIGTERM, cache_process_term); |     signal(SIGTERM, cache_process_term); | ||||||
|  |  | ||||||
| @@ -80,14 +80,12 @@ int cache_process() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     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; | ||||||
| @@ -96,7 +94,9 @@ int cache_process() { | |||||||
|             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); | ||||||
|  |  | ||||||
| @@ -130,11 +130,8 @@ int cache_process() { | |||||||
|                     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; | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
| @@ -158,21 +155,19 @@ int cache_process() { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 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); | ||||||
|                     } |                     } | ||||||
| @@ -189,9 +184,12 @@ int cache_process() { | |||||||
|                     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); | ||||||
| @@ -206,8 +204,6 @@ int cache_process() { | |||||||
|             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); | ||||||
| @@ -216,12 +212,11 @@ int cache_process() { | |||||||
|             sleep(1); |             sleep(1); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     free(buf); |  | ||||||
|     free(comp_buf); |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int cache_init() { | int cache_init(void) { | ||||||
|     if (magic_init() != 0) { |     if (magic_init() != 0) { | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
| @@ -267,7 +262,7 @@ int cache_init() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| int cache_unload() { | int cache_unload(void) { | ||||||
|     int shm_id = shmget(CACHE_SHM_KEY, 0, 0); |     int shm_id = shmget(CACHE_SHM_KEY, 0, 0); | ||||||
|     if (shm_id < 0) { |     if (shm_id < 0) { | ||||||
|         fprintf(stderr, ERR_STR "Unable to get cache shared memory id: %s" CLR_STR "\n", strerror(errno)); |         fprintf(stderr, ERR_STR "Unable to get cache shared memory id: %s" CLR_STR "\n", strerror(errno)); | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * File cache implementation (header file) |  * @brief File cache implementation (header file) | ||||||
|  * src/lib/cache.h |  * @file src/lib/cache.h | ||||||
|  * Lorenz Stechauner, 2020-12-19 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-19 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_CACHE_H | #ifndef SESIMOS_CACHE_H | ||||||
| @@ -30,15 +31,15 @@ extern cache_entry *cache; | |||||||
|  |  | ||||||
| extern int cache_continue; | extern int cache_continue; | ||||||
|  |  | ||||||
| int magic_init(); | int magic_init(void); | ||||||
|  |  | ||||||
| void cache_process_term(); | void cache_process_term(int _); | ||||||
|  |  | ||||||
| int cache_process(); | int cache_process(void); | ||||||
|  |  | ||||||
| int cache_init(); | int cache_init(void); | ||||||
|  |  | ||||||
| int cache_unload(); | int cache_unload(void); | ||||||
|  |  | ||||||
| int cache_update_entry(int entry_num, const char *filename, const char *webroot); | int cache_update_entry(int entry_num, const char *filename, const char *webroot); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Compression interface |  * @brief Compression interface | ||||||
|  * src/lib/compress.c |  * @file src/lib/compress.c | ||||||
|  * Lorenz Stechauner, 2021-05-05 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-05-05 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "compress.h" | #include "compress.h" | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Compression interface (header file) |  * @brief Compression interface (header file) | ||||||
|  * src/lib/compress.h |  * @file src/lib/compress.h | ||||||
|  * Lorenz Stechauner, 2021-05-05 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-05-05 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_COMPRESS_H | #ifndef SESIMOS_COMPRESS_H | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Configuration file loader |  * @brief Configuration file loader | ||||||
|  * src/lib/config.c |  * @file src/lib/config.c | ||||||
|  * Lorenz Stechauner, 2021-01-05 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-01-05 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "config.h" | #include "config.h" | ||||||
| @@ -19,7 +20,7 @@ | |||||||
| t_config *config; | t_config *config; | ||||||
| char geoip_dir[256], dns_server[256]; | char geoip_dir[256], dns_server[256]; | ||||||
|  |  | ||||||
| int config_init() { | int config_init(void) { | ||||||
|     int shm_id = shmget(CONFIG_SHM_KEY, sizeof(t_config), IPC_CREAT | IPC_EXCL | 0640); |     int shm_id = shmget(CONFIG_SHM_KEY, sizeof(t_config), IPC_CREAT | IPC_EXCL | 0640); | ||||||
|     if (shm_id < 0) { |     if (shm_id < 0) { | ||||||
|         fprintf(stderr, ERR_STR "Unable to create config shared memory: %s" CLR_STR "\n", strerror(errno)); |         fprintf(stderr, ERR_STR "Unable to create config shared memory: %s" CLR_STR "\n", strerror(errno)); | ||||||
| @@ -45,7 +46,7 @@ int config_init() { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int config_unload() { | int config_unload(void) { | ||||||
|     int shm_id = shmget(CONFIG_SHM_KEY, 0, 0); |     int shm_id = shmget(CONFIG_SHM_KEY, 0, 0); | ||||||
|     if (shm_id < 0) { |     if (shm_id < 0) { | ||||||
|         fprintf(stderr, ERR_STR "Unable to get config shared memory id: %s" CLR_STR "\n", strerror(errno)); |         fprintf(stderr, ERR_STR "Unable to get config shared memory id: %s" CLR_STR "\n", strerror(errno)); | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Configuration file loader (header file) |  * @brief Configuration file loader (header file) | ||||||
|  * src/lib/config.h |  * @file src/lib/config.h | ||||||
|  * Lorenz Stechauner, 2021-01-05 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-01-05 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_CONFIG_H | #ifndef SESIMOS_CONFIG_H | ||||||
| @@ -55,10 +56,10 @@ typedef struct { | |||||||
| extern t_config *config; | extern t_config *config; | ||||||
| extern char geoip_dir[256], dns_server[256]; | extern char geoip_dir[256], dns_server[256]; | ||||||
|  |  | ||||||
| int config_init(); | int config_init(void); | ||||||
|  |  | ||||||
| int config_load(const char *filename); | int config_load(const char *filename); | ||||||
|  |  | ||||||
| int config_unload(); | int config_unload(void); | ||||||
|  |  | ||||||
| #endif //SESIMOS_CONFIG_H | #endif //SESIMOS_CONFIG_H | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * FastCGI interface implementation |  * @brief FastCGI interface implementation | ||||||
|  * src/lib/fastcgi.c |  * @file src/lib/fastcgi.c | ||||||
|  * Lorenz Stechauner, 2020-12-26 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-26 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "fastcgi.h" | #include "fastcgi.h" | ||||||
| @@ -599,12 +600,6 @@ int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len) { | |||||||
|             .reserved = 0 |             .reserved = 0 | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     if (client->buf != NULL && client->buf_len - client->buf_off > 0) { |  | ||||||
|         ret = (int) (client->buf_len - client->buf_off); |  | ||||||
|         memcpy(buf, client->buf + client->buf_off, ret); |  | ||||||
|         goto send; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     while (rcv_len < len) { |     while (rcv_len < len) { | ||||||
|         ret = sock_recv(client, buf, sizeof(buf), 0); |         ret = sock_recv(client, buf, sizeof(buf), 0); | ||||||
|         if (ret <= 0) { |         if (ret <= 0) { | ||||||
| @@ -612,7 +607,6 @@ int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len) { | |||||||
|             return -1; |             return -1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         send: |  | ||||||
|         rcv_len += ret; |         rcv_len += ret; | ||||||
|         header.contentLengthB1 = (ret >> 8) & 0xFF; |         header.contentLengthB1 = (ret >> 8) & 0xFF; | ||||||
|         header.contentLengthB0 = ret & 0xFF; |         header.contentLengthB0 = ret & 0xFF; | ||||||
| @@ -625,3 +619,21 @@ int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len) { | |||||||
|     } |     } | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int fastcgi_receive_chunked(fastcgi_conn *conn, sock *client) { | ||||||
|  |     long ret; | ||||||
|  |     unsigned long next_len; | ||||||
|  |  | ||||||
|  |     while (1) { | ||||||
|  |         ret = sock_get_chunk_header(client); | ||||||
|  |         if (ret < 0) return (int) ret; | ||||||
|  |  | ||||||
|  |         next_len = ret; | ||||||
|  |         if (next_len <= 0) break; | ||||||
|  |  | ||||||
|  |         ret = fastcgi_receive(conn, client, next_len); | ||||||
|  |         if (ret < 0) return (int) ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * FastCGI interface implementation (header file) |  * @brief FastCGI interface implementation (header file) | ||||||
|  * src/lib/fastcgi.h |  * @file src/lib/fastcgi.h | ||||||
|  * Lorenz Stechauner, 2020-12-26 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-26 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_FASTCGI_H | #ifndef SESIMOS_FASTCGI_H | ||||||
| @@ -54,4 +55,6 @@ int fastcgi_dump(fastcgi_conn *conn, char *buf, long len); | |||||||
|  |  | ||||||
| int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len); | int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len); | ||||||
|  |  | ||||||
|  | int fastcgi_receive_chunked(fastcgi_conn *conn, sock *client); | ||||||
|  |  | ||||||
| #endif //SESIMOS_FASTCGI_H | #endif //SESIMOS_FASTCGI_H | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * MaxMind GeoIP Database interface |  * @brief MaxMind GeoIP Database interface | ||||||
|  * src/lib/geoip.c |  * @file src/lib/geoip.c | ||||||
|  * Lorenz Stechauner, 2021-05-04 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-05-04 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "geoip.h" | #include "geoip.h" | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * MaxMind GeoIP Database interface (header file) |  * @brief MaxMind GeoIP Database interface (header file) | ||||||
|  * src/lib/geoip.h |  * @file src/lib/geoip.h | ||||||
|  * Lorenz Stechauner, 2021-05-04 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-05-04 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * HTTP implementation |  * @brief HTTP implementation | ||||||
|  * src/lib/http.c |  * @file src/lib/http.c | ||||||
|  * Lorenz Stechauner, 2020-12-09 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-09 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "http.h" | #include "http.h" | ||||||
| @@ -144,7 +145,7 @@ int http_receive_request(sock *client, http_req *req) { | |||||||
|     req->hdr.last_field_num = -1; |     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, MSG_PEEK); | ||||||
|         if (rcv_len <= 0) { |         if (rcv_len <= 0) { | ||||||
|             print("Unable to receive http header: %s", sock_strerror(client)); |             print("Unable to receive http header: %s", sock_strerror(client)); | ||||||
|             return -1; |             return -1; | ||||||
| @@ -154,6 +155,8 @@ int http_receive_request(sock *client, http_req *req) { | |||||||
|         if (header_len <= 0) { |         if (header_len <= 0) { | ||||||
|             print(ERR_STR "Unable to parse http header: End of header not found" CLR_STR); |             print(ERR_STR "Unable to parse http header: End of header not found" CLR_STR); | ||||||
|             return 5; |             return 5; | ||||||
|  |         } else { | ||||||
|  |             rcv_len = sock_recv(client, buf, header_len, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (int i = 0; i < header_len; i++) { |         for (int i = 0; i < header_len; i++) { | ||||||
| @@ -215,13 +218,6 @@ int http_receive_request(sock *client, http_req *req) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     client->buf_len = rcv_len - (pos0 - buf + 4); |  | ||||||
|     if (client->buf_len > 0) { |  | ||||||
|         client->buf = malloc(client->buf_len); |  | ||||||
|         client->buf_off = 0; |  | ||||||
|         memcpy(client->buf, pos0 + 4, client->buf_len); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * HTTP implementation (header file) |  * @brief HTTP implementation (header file) | ||||||
|  * src/lib/http.h |  * @file src/lib/http.h | ||||||
|  * Lorenz Stechauner, 2020-12-09 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-09 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_HTTP_H | #ifndef SESIMOS_HTTP_H | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * HTTP static implementation |  * @brief HTTP static implementation | ||||||
|  * src/lib/http_static.c |  * @file src/lib/http_static.c | ||||||
|  * Lorenz Stechauner, 2021-05-03 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-05-03 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "../defs.h" | #include "../defs.h" | ||||||
|   | |||||||
| @@ -1,8 +1,7 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * FastCGI header file |  * @brief FastCGI header file | ||||||
|  * src/lib/include/fastcgi.h |  * @file src/lib/include/fastcgi.h | ||||||
|  * Lorenz Stechauner, 2021-05-03 |  | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_EXTERN_FASTCGI_H | #ifndef SESIMOS_EXTERN_FASTCGI_H | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Reverse proxy |  * @brief Reverse proxy | ||||||
|  * src/lib/rev_proxy.c |  * @file src/lib/rev_proxy.c | ||||||
|  * Lorenz Stechauner, 2021-01-07 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-01-07 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "../defs.h" | #include "../defs.h" | ||||||
| @@ -23,10 +24,7 @@ sock rev_proxy; | |||||||
| char *rev_proxy_host = NULL; | char *rev_proxy_host = NULL; | ||||||
| struct timeval server_timeout = {.tv_sec = SERVER_TIMEOUT, .tv_usec = 0}; | struct timeval server_timeout = {.tv_sec = SERVER_TIMEOUT, .tv_usec = 0}; | ||||||
|  |  | ||||||
| int rev_proxy_preload() { | int rev_proxy_preload(void) { | ||||||
|     rev_proxy.buf = NULL; |  | ||||||
|     rev_proxy.buf_len = 0; |  | ||||||
|     rev_proxy.buf_off = 0; |  | ||||||
|     rev_proxy.ctx = SSL_CTX_new(TLS_client_method()); |     rev_proxy.ctx = SSL_CTX_new(TLS_client_method()); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| @@ -323,46 +321,35 @@ int rev_proxy_init(http_req *req, http_res *res, http_status_ctx *ctx, host_conf | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     const 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) { |     unsigned long content_len = content_length != NULL ? strtoul(content_length, NULL, 10) : 0; | ||||||
|         unsigned long content_len = strtoul(content_length, NULL, 10); |     const char *transfer_encoding = http_get_header_field(&req->hdr, "Transfer-Encoding"); | ||||||
|         if (client->buf_len - client->buf_off > 0) { |  | ||||||
|             unsigned long len = client->buf_len - client->buf_off; |     ret = 0; | ||||||
|             if (len > content_len) { |     if (content_len > 0) { | ||||||
|                 len = content_len; |         ret = sock_splice(&rev_proxy, client, buffer, sizeof(buffer), content_len); | ||||||
|             } |     } else if (transfer_encoding != NULL && strstr(transfer_encoding, "chunked") != NULL) { | ||||||
|             ret = sock_send(&rev_proxy, client->buf, len, 0); |         ret = sock_splice_chunked(&rev_proxy, client, buffer, sizeof(buffer)); | ||||||
|             if (ret <= 0) { |     } | ||||||
|                 res->status = http_get_status(502); |  | ||||||
|                 ctx->origin = SERVER_REQ; |     if (ret < 0 || (content_len != 0 && ret != content_len)) { | ||||||
|                 print(ERR_STR "Unable to send request to server (2): %s" CLR_STR, sock_strerror(&rev_proxy)); |         if (ret == -1) { | ||||||
|                 sprintf(err_msg, "Unable to send request to server: %s.", sock_strerror(&rev_proxy)); |             res->status = http_get_status(502); | ||||||
|                 retry = tries < 4; |             ctx->origin = SERVER_REQ; | ||||||
|                 goto proxy_err; |             print(ERR_STR "Unable to send request to server (2): %s" CLR_STR, sock_strerror(&rev_proxy)); | ||||||
|             } |             sprintf(err_msg, "Unable to send request to server: %s.", sock_strerror(&rev_proxy)); | ||||||
|             content_len -= len; |             retry = tries < 4; | ||||||
|         } |             goto proxy_err; | ||||||
|         if (content_len > 0) { |         } else if (ret == -2) { | ||||||
|             ret = sock_splice(&rev_proxy, client, buffer, sizeof(buffer), content_len); |             res->status = http_get_status(400); | ||||||
|             if (ret <= 0) { |             ctx->origin = CLIENT_REQ; | ||||||
|                 if (ret == -1) { |             print(ERR_STR "Unable to receive request from client: %s" CLR_STR, sock_strerror(client)); | ||||||
|                     res->status = http_get_status(502); |             sprintf(err_msg, "Unable to receive request from client: %s.", sock_strerror(client)); | ||||||
|                     ctx->origin = SERVER_REQ; |             return -1; | ||||||
|                     print(ERR_STR "Unable to send request to server (3): %s" CLR_STR, sock_strerror(&rev_proxy)); |  | ||||||
|                     sprintf(err_msg, "Unable to send request to server: %s.", sock_strerror(&rev_proxy)); |  | ||||||
|                     goto proxy_err; |  | ||||||
|                 } else if (ret == -2) { |  | ||||||
|                     res->status = http_get_status(400); |  | ||||||
|                     ctx->origin = CLIENT_REQ; |  | ||||||
|                     print(ERR_STR "Unable to receive request from client: %s" CLR_STR, sock_strerror(client)); |  | ||||||
|                     sprintf(err_msg, "Unable to receive request from client: %s.", sock_strerror(client)); |  | ||||||
|                     return -1; |  | ||||||
|                 } |  | ||||||
|                 res->status = http_get_status(500); |  | ||||||
|                 ctx->origin = INTERNAL; |  | ||||||
|                 print(ERR_STR "Unknown Error" CLR_STR); |  | ||||||
|                 return -1; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |         res->status = http_get_status(500); | ||||||
|  |         ctx->origin = INTERNAL; | ||||||
|  |         print(ERR_STR "Unknown Error" CLR_STR); | ||||||
|  |         return -1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ret = sock_recv(&rev_proxy, buffer, sizeof(buffer), MSG_PEEK); |     ret = sock_recv(&rev_proxy, buffer, sizeof(buffer), MSG_PEEK); | ||||||
| @@ -491,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; | ||||||
| @@ -538,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: | ||||||
| @@ -558,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); | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Reverse proxy (header file) |  * @brief Reverse proxy (header file) | ||||||
|  * src/lib/rev_proxy.h |  * @file src/lib/rev_proxy.h | ||||||
|  * Lorenz Stechauner, 2021-01-07 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-01-07 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_REV_PROXY_H | #ifndef SESIMOS_REV_PROXY_H | ||||||
| @@ -22,7 +23,7 @@ | |||||||
|  |  | ||||||
| extern sock rev_proxy; | extern sock rev_proxy; | ||||||
|  |  | ||||||
| int rev_proxy_preload(); | int rev_proxy_preload(void); | ||||||
|  |  | ||||||
| int rev_proxy_request_header(http_req *req, int enc); | int rev_proxy_request_header(http_req *req, int enc); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,11 +1,13 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Basic TCP and TLS socket |  * @brief Basic TCP and TLS socket | ||||||
|  * src/lib/sock.c |  * @file src/lib/sock.c | ||||||
|  * Lorenz Stechauner, 2021-01-07 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-01-07 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #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> | ||||||
| @@ -71,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); | ||||||
| @@ -92,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; | ||||||
| @@ -102,6 +101,25 @@ long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigne | |||||||
|     return (long) send_len; |     return (long) send_len; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | long sock_splice_chunked(sock *dst, sock *src, void *buf, unsigned long buf_len) { | ||||||
|  |     long ret; | ||||||
|  |     unsigned long send_len = 0; | ||||||
|  |     unsigned long next_len; | ||||||
|  |  | ||||||
|  |     while (1) { | ||||||
|  |         ret = sock_get_chunk_header(src); | ||||||
|  |         if (ret < 0) return -2; | ||||||
|  |  | ||||||
|  |         next_len = ret; | ||||||
|  |         if (next_len <= 0) break; | ||||||
|  |  | ||||||
|  |         ret = sock_splice(dst, src, buf, buf_len, next_len); | ||||||
|  |         if (ret < 0) return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return (long) send_len; | ||||||
|  | } | ||||||
|  |  | ||||||
| int sock_close(sock *s) { | int sock_close(sock *s) { | ||||||
|     if ((int) s->enc && s->ssl != NULL) { |     if ((int) s->enc && s->ssl != NULL) { | ||||||
|         if (s->_last_ret >= 0) SSL_shutdown(s->ssl); |         if (s->_last_ret >= 0) SSL_shutdown(s->ssl); | ||||||
| @@ -120,7 +138,7 @@ int sock_check(sock *s) { | |||||||
|     return recv(s->socket, &buf, 1, MSG_PEEK | MSG_DONTWAIT) == 1; |     return recv(s->socket, &buf, 1, MSG_PEEK | MSG_DONTWAIT) == 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| int sock_poll(sock *sockets[], sock *ready[], short events, int n_sock, int timeout_ms) { | int sock_poll(sock *sockets[], sock *ready[], sock *error[], int n_sock, int *n_ready, int *n_error, short events, int timeout_ms) { | ||||||
|     struct pollfd fds[n_sock]; |     struct pollfd fds[n_sock]; | ||||||
|     for (int i = 0; i < n_sock; i++) { |     for (int i = 0; i < n_sock; i++) { | ||||||
|         fds[i].fd = sockets[i]->socket; |         fds[i].fd = sockets[i]->socket; | ||||||
| @@ -128,20 +146,59 @@ int sock_poll(sock *sockets[], sock *ready[], short events, int n_sock, int time | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     int ret = poll(fds, n_sock, timeout_ms); |     int ret = poll(fds, n_sock, timeout_ms); | ||||||
|     if (ret < 0 || ready == NULL) return ret; |     if (ret < 0 || ready == NULL || error == NULL) return ret; | ||||||
|  |  | ||||||
|     int j = 0; |     *n_ready = 0, *n_error = 0; | ||||||
|     for (int i = 0; i < n_sock; i++) { |     for (int i = 0; i < n_sock; i++) { | ||||||
|         if (fds[i].revents & events) |         if (fds[i].revents & events) | ||||||
|             ready[j++] = sockets[i]; |             ready[(*n_ready)++] = sockets[i]; | ||||||
|  |         if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) | ||||||
|  |             error[(*n_error)++] = sockets[i]; | ||||||
|     } |     } | ||||||
|     return j; |  | ||||||
|  |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| int sock_poll_read(sock *sockets[], sock *readable[], int n_sock, int timeout_ms) { | int sock_poll_read(sock *sockets[], sock *readable[], sock *error[], int n_sock, int *n_readable, int *n_error, int timeout_ms) { | ||||||
|     return sock_poll(sockets, readable, POLLIN, n_sock, timeout_ms); |     return sock_poll(sockets, readable, error, n_sock, n_readable, n_error, POLLIN, timeout_ms); | ||||||
| } | } | ||||||
|  |  | ||||||
| int sock_poll_write(sock *sockets[], sock *writable[], int n_sock, 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, POLLOUT, n_sock, 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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Basic TCP and TLS socket (header file) |  * @brief Basic TCP and TLS socket (header file) | ||||||
|  * src/lib/sock.h |  * @file src/lib/sock.h | ||||||
|  * Lorenz Stechauner, 2021-01-07 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2021-01-07 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_SOCK_H | #ifndef SESIMOS_SOCK_H | ||||||
| @@ -16,9 +17,6 @@ typedef struct { | |||||||
|     int socket; |     int socket; | ||||||
|     SSL_CTX *ctx; |     SSL_CTX *ctx; | ||||||
|     SSL *ssl; |     SSL *ssl; | ||||||
|     char *buf; |  | ||||||
|     unsigned long buf_len; |  | ||||||
|     unsigned long buf_off; |  | ||||||
|     long _last_ret; |     long _last_ret; | ||||||
|     int _errno; |     int _errno; | ||||||
|     unsigned long _ssl_error; |     unsigned long _ssl_error; | ||||||
| @@ -34,14 +32,20 @@ long sock_recv(sock *s, void *buf, unsigned long len, int flags); | |||||||
|  |  | ||||||
| long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigned long len); | long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigned long len); | ||||||
|  |  | ||||||
|  | long sock_splice_chunked(sock *dst, sock *src, void *buf, unsigned long buf_len); | ||||||
|  |  | ||||||
| int sock_close(sock *s); | int sock_close(sock *s); | ||||||
|  |  | ||||||
| int sock_check(sock *s); | int sock_check(sock *s); | ||||||
|  |  | ||||||
| int sock_poll(sock *sockets[], sock *readable[], short events, int n_sock, int timeout_ms); | int sock_poll(sock *sockets[], sock *ready[], sock *error[], int n_sock, int *n_ready, int *n_error, short events, int timeout_ms); | ||||||
|  |  | ||||||
| int sock_poll_read(sock *sockets[], sock *readable[], int n_sock, int timeout_ms); | int sock_poll_read(sock *sockets[], sock *readable[], sock *error[], int n_sock, int *n_readable, int *n_error, int timeout_ms); | ||||||
|  |  | ||||||
| int sock_poll_write(sock *sockets[], sock *writable[], int n_sock, 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 | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * URI and path handlers |  * @brief URI and path handlers | ||||||
|  * src/lib/uri.c |  * @file src/lib/uri.c | ||||||
|  * Lorenz Stechauner, 2020-12-13 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-13 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "uri.h" | #include "uri.h" | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * URI and path handlers (header file) |  * @brief URI and path handlers (header file) | ||||||
|  * src/lib/uri.h |  * @file src/lib/uri.h | ||||||
|  * Lorenz Stechauner, 2020-12-13 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-13 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_URI_H | #ifndef SESIMOS_URI_H | ||||||
|   | |||||||
							
								
								
									
										103
									
								
								src/lib/utils.c
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								src/lib/utils.c
									
									
									
									
									
								
							| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Utilities |  * @brief Utilities | ||||||
|  * src/lib/utils.c |  * @file src/lib/utils.c | ||||||
|  * Lorenz Stechauner, 2020-12-03 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-03 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "utils.h" | #include "utils.h" | ||||||
| @@ -14,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) { | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Utilities (header file) |  * @brief Utilities (header file) | ||||||
|  * src/lib/utils.h |  * @file src/lib/utils.h | ||||||
|  * Lorenz Stechauner, 2020-12-03 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-03 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_UTILS_H | #ifndef SESIMOS_UTILS_H | ||||||
| @@ -20,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) | ||||||
| @@ -36,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); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * WebSocket reverse proxy |  * @brief WebSocket reverse proxy | ||||||
|  * src/lib/websocket.c |  * @file src/lib/websocket.c | ||||||
|  * Lorenz Stechauner, 2022-08-16 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2022-08-16 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "../defs.h" | #include "../defs.h" | ||||||
| @@ -15,9 +16,9 @@ | |||||||
| #include <signal.h> | #include <signal.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| int terminate = 0; | volatile sig_atomic_t terminate = 0; | ||||||
|  |  | ||||||
| void ws_terminate() { | void ws_terminate(int _) { | ||||||
|     terminate = 1; |     terminate = 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -145,33 +146,38 @@ int ws_send_frame_header(sock *s, ws_frame *frame) { | |||||||
|  |  | ||||||
| int ws_handle_connection(sock *s1, sock *s2) { | int ws_handle_connection(sock *s1, sock *s2) { | ||||||
|     sock *poll_socks[2] = {s1, s2}; |     sock *poll_socks[2] = {s1, s2}; | ||||||
|     sock *readable[2]; |     sock *readable[2], *error[2]; | ||||||
|     int n_sock = 2; |     int n_sock = 2, n_readable = 0, n_error = 0; | ||||||
|     ws_frame frame; |     ws_frame frame; | ||||||
|     char buf[CHUNK_SIZE]; |     char buf[CHUNK_SIZE]; | ||||||
|     int poll, closes = 0; |     int closes = 0; | ||||||
|     long ret; |     long ret; | ||||||
|  |  | ||||||
|     signal(SIGINT, ws_terminate); |     signal(SIGINT, ws_terminate); | ||||||
|     signal(SIGTERM, ws_terminate); |     signal(SIGTERM, ws_terminate); | ||||||
|  |  | ||||||
|     while (!terminate && closes != 3) { |     while (!terminate && closes != 3) { | ||||||
|         poll = sock_poll_read(poll_socks, readable, n_sock, WS_TIMEOUT * 1000); |         ret = sock_poll_read(poll_socks, readable, error, n_sock, &n_readable, &n_error, WS_TIMEOUT * 1000); | ||||||
|         if (terminate) { |         if (terminate) { | ||||||
|             break; |             break; | ||||||
|         } else if (poll < 0) { |         } else if (ret < 0) { | ||||||
|             print(ERR_STR "Unable to poll sockets: %s" CLR_STR, strerror(errno)); |             print(ERR_STR "Unable to poll sockets: %s" CLR_STR, strerror(errno)); | ||||||
|             return -1; |             return -1; | ||||||
|         } else if (poll == 0) { |         } else if (n_readable == 0) { | ||||||
|             print(ERR_STR "Connection timed out" CLR_STR); |             print(ERR_STR "Connection timed out" CLR_STR); | ||||||
|             return -2; |             return -2; | ||||||
|  |         } else if (n_error > 0) { | ||||||
|  |             print(ERR_STR "Peer closed connection" CLR_STR); | ||||||
|  |             return -3; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (int i = 0; i < poll; i++) { |         for (int i = 0; i < n_readable; i++) { | ||||||
|             sock *s = readable[i]; |             sock *s = readable[i]; | ||||||
|             sock *o = (s == s1) ? s2 : s1; |             sock *o = (s == s1) ? s2 : s1; | ||||||
|             if (ws_recv_frame_header(s, &frame) != 0) return -3; |             if (ws_recv_frame_header(s, &frame) != 0) return -3; | ||||||
|  |  | ||||||
|  |             // print("WebSocket: Peer %s, Opcode=0x%X, Len=%li", (s == s1) ? "1" : "2", frame.opcode, frame.len); | ||||||
|  |  | ||||||
|             if (frame.opcode == 0x8) { |             if (frame.opcode == 0x8) { | ||||||
|                 n_sock--; |                 n_sock--; | ||||||
|                 if (s == s1) { |                 if (s == s1) { | ||||||
| @@ -188,10 +194,10 @@ int ws_handle_connection(sock *s1, sock *s2) { | |||||||
|                 ret = sock_splice(o, s, buf, sizeof(buf), frame.len); |                 ret = sock_splice(o, s, buf, sizeof(buf), frame.len); | ||||||
|                 if (ret < 0) { |                 if (ret < 0) { | ||||||
|                     print(ERR_STR "Unable to forward data in WebSocket: %s" CLR_STR, strerror(errno)); |                     print(ERR_STR "Unable to forward data in WebSocket: %s" CLR_STR, strerror(errno)); | ||||||
|                     return -3; |                     return -4; | ||||||
|                 } else if (ret != frame.len) { |                 } else if (ret != frame.len) { | ||||||
|                     print(ERR_STR "Unable to forward correct number of bytes in WebSocket" CLR_STR); |                     print(ERR_STR "Unable to forward correct number of bytes in WebSocket" CLR_STR); | ||||||
|                     return -3; |                     return -4; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * WebSocket reverse proxy (header file) |  * @brief WebSocket reverse proxy (header file) | ||||||
|  * src/lib/websocket.h |  * @file src/lib/websocket.h | ||||||
|  * Lorenz Stechauner, 2022-08-16 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2022-08-16 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_WEBSOCKET_H | #ifndef SESIMOS_WEBSOCKET_H | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								src/server.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/server.c
									
									
									
									
									
								
							| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * Sesimos - secure, simple, modern web server |  * Sesimos - secure, simple, modern web server | ||||||
|  * Main executable |  * @brief Main executable | ||||||
|  * src/server.c |  * @file src/server.c | ||||||
|  * Lorenz Stechauner, 2020-12-03 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-03 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #define _POSIX_C_SOURCE 199309L | #define _POSIX_C_SOURCE 199309L | ||||||
| @@ -35,14 +36,14 @@ | |||||||
| #include <dirent.h> | #include <dirent.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| int active = 1; | volatile sig_atomic_t active = 1; | ||||||
| const char *config_file; | const char *config_file; | ||||||
| int sockets[NUM_SOCKETS]; | int sockets[NUM_SOCKETS]; | ||||||
| pid_t children[MAX_CHILDREN]; | pid_t children[MAX_CHILDREN]; | ||||||
| MMDB_s mmdbs[MAX_MMDB]; | MMDB_s mmdbs[MAX_MMDB]; | ||||||
| SSL_CTX *contexts[CONFIG_MAX_CERT_CONFIG]; | SSL_CTX *contexts[CONFIG_MAX_CERT_CONFIG]; | ||||||
|  |  | ||||||
| void openssl_init() { | void openssl_init(void) { | ||||||
|     SSL_library_init(); |     SSL_library_init(); | ||||||
|     SSL_load_error_strings(); |     SSL_load_error_strings(); | ||||||
|     ERR_load_BIO_strings(); |     ERR_load_BIO_strings(); | ||||||
| @@ -58,7 +59,7 @@ static int ssl_servername_cb(SSL *ssl, int *ad, void *arg) { | |||||||
|     return SSL_TLSEXT_ERR_OK; |     return SSL_TLSEXT_ERR_OK; | ||||||
| } | } | ||||||
|  |  | ||||||
| void destroy() { | void destroy(int _) { | ||||||
|     fprintf(stderr, "\n" ERR_STR "Terminating forcefully!" CLR_STR "\n"); |     fprintf(stderr, "\n" ERR_STR "Terminating forcefully!" CLR_STR "\n"); | ||||||
|     int status = 0; |     int status = 0; | ||||||
|     int ret; |     int ret; | ||||||
| @@ -87,7 +88,7 @@ void destroy() { | |||||||
|     exit(2); |     exit(2); | ||||||
| } | } | ||||||
|  |  | ||||||
| void terminate() { | void terminate(int _) { | ||||||
|     fprintf(stderr, "\nTerminating gracefully...\n"); |     fprintf(stderr, "\nTerminating gracefully...\n"); | ||||||
|     active = 0; |     active = 0; | ||||||
|  |  | ||||||
| @@ -290,10 +291,6 @@ int main(int argc, const char *argv[]) { | |||||||
|  |  | ||||||
|     openssl_init(); |     openssl_init(); | ||||||
|  |  | ||||||
|     client.buf = NULL; |  | ||||||
|     client.buf_len = 0; |  | ||||||
|     client.buf_off = 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < CONFIG_MAX_CERT_CONFIG; i++) { |     for (int i = 0; i < CONFIG_MAX_CERT_CONFIG; i++) { | ||||||
|         const cert_config *conf = &config->certs[i]; |         const cert_config *conf = &config->certs[i]; | ||||||
|         if (conf->name[0] == 0) break; |         if (conf->name[0] == 0) break; | ||||||
| @@ -347,7 +344,7 @@ int main(int argc, const char *argv[]) { | |||||||
|         ready_sockets_num = poll(poll_fds, NUM_SOCKETS, 1000); |         ready_sockets_num = poll(poll_fds, NUM_SOCKETS, 1000); | ||||||
|         if (ready_sockets_num < 0) { |         if (ready_sockets_num < 0) { | ||||||
|             fprintf(stderr, ERR_STR "Unable to poll sockets: %s" CLR_STR "\n", strerror(errno)); |             fprintf(stderr, ERR_STR "Unable to poll sockets: %s" CLR_STR "\n", strerror(errno)); | ||||||
|             terminate(); |             terminate(0); | ||||||
|             return 1; |             return 1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								src/server.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/server.h
									
									
									
									
									
								
							| @@ -1,8 +1,9 @@ | |||||||
| /** | /** | ||||||
|  * sesimos - secure, simple, modern web server |  * sesimos - secure, simple, modern web server | ||||||
|  * Main executable (header file) |  * @brief Main executable (header file) | ||||||
|  * src/server.h |  * @file src/server.h | ||||||
|  * Lorenz Stechauner, 2020-12-03 |  * @author Lorenz Stechauner | ||||||
|  |  * @date 2020-12-03 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef SESIMOS_SERVER_H | #ifndef SESIMOS_SERVER_H | ||||||
| @@ -10,6 +11,7 @@ | |||||||
|  |  | ||||||
| #include <sys/time.h> | #include <sys/time.h> | ||||||
| #include <maxminddb.h> | #include <maxminddb.h> | ||||||
|  | #include <signal.h> | ||||||
|  |  | ||||||
| #define NUM_SOCKETS 2 | #define NUM_SOCKETS 2 | ||||||
| #define MAX_CHILDREN 1024 | #define MAX_CHILDREN 1024 | ||||||
| @@ -25,7 +27,7 @@ extern int sockets[NUM_SOCKETS]; | |||||||
| extern pid_t children[MAX_CHILDREN]; | extern pid_t children[MAX_CHILDREN]; | ||||||
| extern MMDB_s mmdbs[MAX_MMDB]; | extern MMDB_s mmdbs[MAX_MMDB]; | ||||||
|  |  | ||||||
| extern int server_keep_alive; | extern volatile sig_atomic_t server_keep_alive; | ||||||
| extern char *log_client_prefix, *log_conn_prefix, *log_req_prefix, *client_geoip; | extern char *log_client_prefix, *log_conn_prefix, *log_req_prefix, *client_geoip; | ||||||
| extern char *client_addr_str, *client_addr_str_ptr, *server_addr_str, *server_addr_str_ptr, *client_host_str; | extern char *client_addr_str, *client_addr_str_ptr, *server_addr_str, *server_addr_str_ptr, *client_host_str; | ||||||
| extern struct timeval client_timeout; | extern struct timeval client_timeout; | ||||||
|   | |||||||
							
								
								
									
										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