Compare commits
	
		
			30 Commits
		
	
	
		
			f4697ce0f3
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c36ba8d3a5 | |||
| 3bc1faac39 | |||
| 151c4804fe | |||
| e1a92729d2 | |||
| 72904c3ba9 | |||
| be84c3048b | |||
| 73a469a7de | |||
| a0d774c9a4 | |||
| 28c6809768 | |||
| e93c478cc3 | |||
| 1d0a545610 | |||
| fb67f7e9b0 | |||
| 0dd9a9a843 | |||
| 6eaf5f5776 | |||
| 75d36bb5bb | |||
| c6da5413d4 | |||
| 80d7626208 | |||
| e97809253a | |||
| b26e80f18a | |||
| 90b20d40d8 | |||
| 34b860073c | |||
| 5d6bd07cfd | |||
| 2a2c1ea442 | |||
| fee4cc808a | |||
| 0232331f99 | |||
| 62b631c862 | |||
| 0f526d7b95 | |||
| 642286a838 | |||
| 91a8959c8d | |||
| 197756bf15 | 
							
								
								
									
										43
									
								
								src/async.c
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								src/async.c
									
									
									
									
									
								
							| @@ -19,6 +19,7 @@ | ||||
| #include <pthread.h> | ||||
| #include <semaphore.h> | ||||
| #include <unistd.h> | ||||
| #include <openssl/ssl.h> | ||||
|  | ||||
| #define ASYNC_MAX_EVENTS 16 | ||||
|  | ||||
| @@ -38,7 +39,7 @@ typedef struct { | ||||
|     evt_listen_t *q[ASYNC_MAX_EVENTS]; | ||||
| } listen_queue_t; | ||||
|  | ||||
| static listen_queue_t listen1, listen2, *listen_q = &listen1; | ||||
| static volatile listen_queue_t listen1, listen2, *listen_q = &listen1; | ||||
| static volatile sig_atomic_t alive = 1; | ||||
| static pthread_t thread = -1; | ||||
| static sem_t lock; | ||||
| @@ -49,7 +50,7 @@ static short async_a2p(async_evt_t events) { | ||||
|     if (events & ASYNC_IN)  ret |= POLLIN; | ||||
|     if (events & ASYNC_PRI) ret |= POLLPRI; | ||||
|     if (events & ASYNC_OUT) ret |= POLLOUT; | ||||
|     if (events & ASYNC_ERR) ret |= POLLERR; | ||||
|     if (events & ASYNC_ERR_) ret |= POLLERR; | ||||
|     if (events & ASYNC_HUP) ret |= POLLHUP; | ||||
|     if (events & ASYNC_RDNORM) ret |= POLLRDNORM; | ||||
|     if (events & ASYNC_RDBAND) ret |= POLLRDBAND; | ||||
| @@ -64,7 +65,7 @@ static unsigned int async_a2e(async_evt_t events) { | ||||
|     if (events & ASYNC_IN)  ret |= EPOLLIN; | ||||
|     if (events & ASYNC_PRI) ret |= EPOLLPRI; | ||||
|     if (events & ASYNC_OUT) ret |= EPOLLOUT; | ||||
|     if (events & ASYNC_ERR) ret |= EPOLLERR; | ||||
|     if (events & ASYNC_ERR_) ret |= EPOLLERR; | ||||
|     if (events & ASYNC_HUP) ret |= EPOLLHUP; | ||||
|     if (events & ASYNC_RDNORM) ret |= EPOLLRDNORM; | ||||
|     if (events & ASYNC_RDBAND) ret |= EPOLLRDBAND; | ||||
| @@ -79,7 +80,7 @@ static async_evt_t async_p2a(short events) { | ||||
|     if (events & POLLIN)   ret |= ASYNC_IN; | ||||
|     if (events & POLLPRI)  ret |= ASYNC_PRI; | ||||
|     if (events & POLLOUT)  ret |= ASYNC_OUT; | ||||
|     if (events & POLLERR)  ret |= ASYNC_ERR; | ||||
|     if (events & POLLERR)  ret |= ASYNC_ERR_; | ||||
|     if (events & POLLHUP)  ret |= ASYNC_HUP; | ||||
|     if (events & POLLRDNORM) ret |= ASYNC_RDNORM; | ||||
|     if (events & POLLRDBAND) ret |= ASYNC_RDBAND; | ||||
| @@ -94,7 +95,7 @@ static async_evt_t async_e2a(unsigned int events) { | ||||
|     if (events & EPOLLIN)   ret |= ASYNC_IN; | ||||
|     if (events & EPOLLPRI)  ret |= ASYNC_PRI; | ||||
|     if (events & EPOLLOUT)  ret |= ASYNC_OUT; | ||||
|     if (events & EPOLLERR)  ret |= ASYNC_ERR; | ||||
|     if (events & EPOLLERR)  ret |= ASYNC_ERR_; | ||||
|     if (events & EPOLLHUP)  ret |= ASYNC_HUP; | ||||
|     if (events & EPOLLRDNORM) ret |= ASYNC_RDNORM; | ||||
|     if (events & EPOLLRDBAND) ret |= ASYNC_RDBAND; | ||||
| @@ -167,6 +168,11 @@ static int async_check(evt_listen_t *evt) { | ||||
|     }}; | ||||
|  | ||||
|     // check, if fd is already ready | ||||
|     if (evt->events & ASYNC_IN && evt->socket && evt->socket->enc && SSL_pending(evt->socket->ssl) > 0) { | ||||
|         // ssl layer already ready | ||||
|         if (async_exec(evt, ASYNC_IN) == 0) | ||||
|             return 1; | ||||
|     } | ||||
|     switch (poll(fds, 1, 0)) { | ||||
|         case 1: | ||||
|             // fd already ready | ||||
| @@ -247,7 +253,7 @@ void async_thread(void) { | ||||
|     struct epoll_event ev, events[ASYNC_MAX_EVENTS]; | ||||
|     int num_fds; | ||||
|     long ts, min_ts, cur_ts; | ||||
|     listen_queue_t *l; | ||||
|     volatile listen_queue_t *l; | ||||
|     evt_listen_t **local; | ||||
|  | ||||
|     if ((local = list_create(sizeof(evt_listen_t *), 16)) == NULL) { | ||||
| @@ -260,8 +266,18 @@ void async_thread(void) { | ||||
|     // main event loop | ||||
|     while (alive) { | ||||
|         // swap listen queue | ||||
|         while (sem_wait(&lock) != 0) { | ||||
|             if (errno == EINTR) { | ||||
|                 errno = 0; | ||||
|                 continue; | ||||
|             } else { | ||||
|                 critical("Unable to lock async queue"); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         l = listen_q; | ||||
|         listen_q = (listen_q == &listen1) ? &listen2 : &listen1; | ||||
|         sem_post(&lock); | ||||
|  | ||||
|         // fill local list and epoll instance with previously added queue entries | ||||
|         for (int i = 0; i < l->n; i++) { | ||||
| @@ -282,8 +298,9 @@ void async_thread(void) { | ||||
|                     errno = 0; | ||||
|                     if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) != -1) | ||||
|                         continue; | ||||
|                 } else if (errno == EBADF) { | ||||
|                     // fd probably already closed | ||||
|                 } else if (errno == EBADF || errno == EPERM) { | ||||
|                     // fd probably already closed or does not support epoll somehow | ||||
|                     // FIXME should not happen | ||||
|                     warning("Unable to add file descriptor to epoll instance"); | ||||
|                     errno = 0; | ||||
|                     local = list_delete(local, &evt); | ||||
| @@ -331,9 +348,8 @@ void async_thread(void) { | ||||
|             if (async_exec(evt, async_e2a(events[i].events)) == 0) { | ||||
|                 logger_set_prefix(""); | ||||
|                 if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) == -1) { | ||||
|                     if (errno == EBADF || errno == ENOENT) { | ||||
|                         // already closed fd or not found, do not die | ||||
|                         warning("Unable to remove file descriptor from epoll instance"); | ||||
|                     if (errno == EBADF || errno == ENOENT || errno == EPERM) { | ||||
|                         // already closed, fd not found, or fd does not support epoll, anyway do not die | ||||
|                         errno = 0; | ||||
|                     } else { | ||||
|                         critical("Unable to remove file descriptor from epoll instance"); | ||||
| @@ -362,9 +378,8 @@ void async_thread(void) { | ||||
|                 evt->to_cb(evt->arg); | ||||
|  | ||||
|                 if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) == -1) { | ||||
|                     if (errno == EBADF || errno == ENOENT) { | ||||
|                         // already closed fd or not found, do not die | ||||
|                         warning("Unable to remove file descriptor from epoll instance"); | ||||
|                     if (errno == EBADF || errno == ENOENT || errno == EPERM) { | ||||
|                         // already closed, fd not found, or fd does not support epoll, anyway do not die | ||||
|                         errno = 0; | ||||
|                     } else { | ||||
|                         critical("Unable to remove file descriptor from epoll instance"); | ||||
|   | ||||
| @@ -17,7 +17,7 @@ | ||||
| #define ASYNC_IN     0x001 | ||||
| #define ASYNC_PRI    0x002 | ||||
| #define ASYNC_OUT    0x004 | ||||
| #define ASYNC_ERR    0x008 | ||||
| #define ASYNC_ERR_   0x008 | ||||
| #define ASYNC_HUP    0x010 | ||||
| #define ASYNC_RDNORM 0x040 | ||||
| #define ASYNC_RDBAND 0x080 | ||||
|   | ||||
| @@ -75,6 +75,10 @@ static void magic_mime_type(const char *restrict filename, char *buf) { | ||||
|             strcpy(buf, "application/javascript"); | ||||
|             sem_post(&sem_magic); | ||||
|             return; | ||||
|         } else if (strends(filename, ".xhtml")) { | ||||
|             strcpy(buf, "application/xhtml+xml"); | ||||
|             sem_post(&sem_magic); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -213,6 +213,8 @@ int fastcgi_close_cnx(fastcgi_cnx_t *cnx) { | ||||
|     sock_close(&cnx->out); | ||||
|     if (cnx->fd_err != -1) close(cnx->fd_err); | ||||
|     if (cnx->fd_out != -1) close(cnx->fd_out); | ||||
|     cnx->fd_err = -1; | ||||
|     cnx->fd_out = -1; | ||||
|  | ||||
|     errno = e; | ||||
|     return 0; | ||||
| @@ -229,6 +231,7 @@ int fastcgi_php_error(fastcgi_cnx_t *cnx, char *err_msg) { | ||||
|  | ||||
|     log_lvl_t msg_type = LOG_INFO; | ||||
|  | ||||
|     // FIXME php fastcgi sends multiple calls with '; ' as delimiter | ||||
|     for (long ret; cnx->fd_err_bytes > 0 && (ret = getline(&line, &line_len, cnx->err)) != -1; cnx->fd_err_bytes -= ret) { | ||||
|         if (ret > 0) line[ret - 1] = 0; | ||||
|         line_ptr = line; | ||||
| @@ -319,6 +322,7 @@ int fastcgi_recv_frame(fastcgi_cnx_t *cnx) { | ||||
|             cnx->fd_err_bytes += content_len + 1; | ||||
|         } | ||||
|         for (long ret, sent = 0; sent < content_len; sent += ret) { | ||||
|             // FIXME if pipe is full thread gets stuck | ||||
|             if ((ret = splice(cnx->socket.socket, 0, fd, 0, content_len - sent, 0)) == -1) { | ||||
|                 if (errno == EINTR) { | ||||
|                     errno = 0, ret = 0; | ||||
| @@ -353,11 +357,6 @@ int fastcgi_recv_frame(fastcgi_cnx_t *cnx) { | ||||
|     return header.type; | ||||
| } | ||||
|  | ||||
| long fastcgi_send(fastcgi_cnx_t *cnx, sock *client) { | ||||
|     char buf[CHUNK_SIZE]; | ||||
|     return sock_splice_all(client, &cnx->out, buf, sizeof(buf)); | ||||
| } | ||||
|  | ||||
| int fastcgi_header(fastcgi_cnx_t *cnx, http_res *res, char *err_msg) { | ||||
|     long ret, len; | ||||
|     char content[CLIENT_MAX_HEADER_SIZE]; | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
| #include "http.h" | ||||
| #include "uri.h" | ||||
|  | ||||
| #define FASTCGI_SOCKET_TIMEOUT 1 | ||||
| #define FASTCGI_TIMEOUT 3600 | ||||
|  | ||||
| #define FASTCGI_BACKEND_PHP 1 | ||||
|   | ||||
| @@ -387,6 +387,14 @@ int http_send_request(sock *server, http_req *req) { | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int http_send_100_continue(sock *client) { | ||||
|     char buf[256]; | ||||
|     char date_buf[64]; | ||||
|     int size = sprintf(buf, "HTTP/1.1 100 Continue\r\nDate: %s\r\nServer: " SERVER_STR "\r\n\r\n", | ||||
|                        http_get_date(date_buf, sizeof(date_buf))); | ||||
|     return sock_send_x(client, buf, size, 0) == -1 ? -1 : 0; | ||||
| } | ||||
|  | ||||
| const http_status *http_get_status(status_code_t status_code) { | ||||
|     for (int i = 0; i < http_statuses_size; i++) { | ||||
|         if (http_statuses[i].code == status_code) { | ||||
|   | ||||
| @@ -174,6 +174,8 @@ int http_send_response(sock *client, http_res *res); | ||||
|  | ||||
| int http_send_request(sock *server, http_req *req); | ||||
|  | ||||
| int http_send_100_continue(sock *client); | ||||
|  | ||||
| const http_status *http_get_status(status_code_t status_code); | ||||
|  | ||||
| const http_status_msg *http_get_error_msg(status_code_t status_code); | ||||
|   | ||||
							
								
								
									
										173
									
								
								src/lib/proxy.c
									
									
									
									
									
								
							
							
						
						
									
										173
									
								
								src/lib/proxy.c
									
									
									
									
									
								
							| @@ -314,7 +314,7 @@ static int proxy_connect(proxy_ctx_t *proxy, host_config_t *conf, http_res *res, | ||||
|     info(BLUE_STR "Connecting to " BLD_STR "[%s]:%i" CLR_STR BLUE_STR "...", conf->proxy.hostname, conf->proxy.port); | ||||
|  | ||||
|     int fd; | ||||
|     if ((fd = sock_connect(conf->proxy.hostname, conf->proxy.port, SERVER_TIMEOUT_INIT, addr_buf, sizeof(addr_buf))) == -1) { | ||||
|     if ((fd = sock_connect(conf->proxy.hostname, conf->proxy.port, SERVER_SOCKET_TIMEOUT_INIT, addr_buf, sizeof(addr_buf))) == -1) { | ||||
|         if (errno == ETIMEDOUT || errno == EINPROGRESS || errno == EHOSTDOWN || errno == EHOSTUNREACH) { | ||||
|             res->status = http_get_status(504); | ||||
|             ctx->origin = SERVER_REQ; | ||||
| @@ -440,37 +440,128 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     const char *content_length = http_get_header_field(&req->hdr, "Content-Length"); | ||||
|     unsigned long content_len = content_length != NULL ? strtoul(content_length, NULL, 10) : 0; | ||||
|     const char *transfer_encoding = http_get_header_field(&req->hdr, "Transfer-Encoding"); | ||||
|  | ||||
|     ret = 0; | ||||
|     if (content_len > 0) { | ||||
|         ret = sock_splice(&proxy->proxy, client, buffer, sizeof(buffer), content_len); | ||||
|     } else if (strcontains(transfer_encoding, "chunked")) { | ||||
|         ret = sock_splice_chunked(&proxy->proxy, client, buffer, sizeof(buffer), SOCK_CHUNKED); | ||||
|     } | ||||
|  | ||||
|     if (ret < 0 || (content_len != 0 && ret != content_len)) { | ||||
|         if (ret == -1 && errno != EPROTO) { | ||||
|             res->status = http_get_status(502); | ||||
|             ctx->origin = SERVER_REQ; | ||||
|             error("Unable to send request to server (2)"); | ||||
|             sprintf(err_msg, "Unable to send request to server: %s.", error_str(errno, err_buf, sizeof(err_buf))); | ||||
|             return -1; | ||||
|         } else if (ret == -1) { | ||||
|             res->status = http_get_status(400); | ||||
|             ctx->origin = CLIENT_REQ; | ||||
|             error("Unable to receive request from client"); | ||||
|             sprintf(err_msg, "Unable to receive request from client: %s.", error_str(errno, err_buf, sizeof(err_buf))); | ||||
|     const char *client_expect = http_get_header_field(&req->hdr, "Expect"); | ||||
|     int expect_100_continue = (client_expect != NULL && strcasecmp(client_expect, "100-continue") == 0); | ||||
|     int ignore_content = 0; | ||||
|     if (expect_100_continue) { | ||||
|         http_res tmp_res = { | ||||
|             .version = "1.1", | ||||
|             .status = http_get_status(501), | ||||
|         }; | ||||
|         if (http_init_hdr(&tmp_res.hdr) != 0) { | ||||
|             res->status = http_get_status(500); | ||||
|             ctx->origin = INTERNAL; | ||||
|             error("Unable to initialize http header"); | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         ret = proxy_peek_response(proxy, &tmp_res, ctx, custom_status, err_msg); | ||||
|         http_free_hdr(&tmp_res.hdr); | ||||
|         if (ret < 0) | ||||
|             return (int) ret; | ||||
|  | ||||
|         if (tmp_res.status->code == 100) { | ||||
|             if (sock_recv_x(&proxy->proxy, buffer, ret, 0) == -1) { | ||||
|                 res->status = http_get_status(502); | ||||
|                 ctx->origin = SERVER_RES; | ||||
|                 error("Unable to receive from server"); | ||||
|                 return -1; | ||||
|             } | ||||
|             info("%s -> %03i %s%s", http_get_status_color(tmp_res.status->code), tmp_res.status->code, tmp_res.status->msg, CLR_STR); | ||||
|             if (http_send_response(client, &tmp_res) != 0) { | ||||
|                 res->status = http_get_status(400); | ||||
|                 ctx->origin = CLIENT_RES; | ||||
|                 error("Unable to send to client"); | ||||
|                 return -1; | ||||
|             } | ||||
|         } else { | ||||
|             ignore_content = 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (!ignore_content) { | ||||
|         const char *content_length = http_get_header_field(&req->hdr, "Content-Length"); | ||||
|         unsigned long content_len = content_length != NULL ? strtoul(content_length, NULL, 10) : 0; | ||||
|         const char *transfer_encoding = http_get_header_field(&req->hdr, "Transfer-Encoding"); | ||||
|  | ||||
|         ret = 0; | ||||
|         if (content_len > 0) { | ||||
|             ret = sock_splice(&proxy->proxy, client, buffer, sizeof(buffer), content_len); | ||||
|         } else if (strcontains(transfer_encoding, "chunked")) { | ||||
|             ret = sock_splice_chunked(&proxy->proxy, client, buffer, sizeof(buffer), SOCK_CHUNKED); | ||||
|         } | ||||
|  | ||||
|         if (ret < 0 || (content_len != 0 && ret != content_len)) { | ||||
|             if (ret == -1 && errno != EPROTO) { | ||||
|                 res->status = http_get_status(502); | ||||
|                 ctx->origin = SERVER_REQ; | ||||
|                 error("Unable to send request to server (2)"); | ||||
|                 sprintf(err_msg, "Unable to send request to server: %s.", error_str(errno, err_buf, sizeof(err_buf))); | ||||
|                 return -1; | ||||
|             } else if (ret == -1) { | ||||
|                 res->status = http_get_status(400); | ||||
|                 ctx->origin = CLIENT_REQ; | ||||
|                 error("Unable to receive request from client"); | ||||
|                 sprintf(err_msg, "Unable to receive request from client: %s.", error_str(errno, err_buf, sizeof(err_buf))); | ||||
|                 return -1; | ||||
|             } | ||||
|             res->status = http_get_status(500); | ||||
|             ctx->origin = INTERNAL; | ||||
|             error("Unknown Error"); | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (sock_set_socket_timeout(&proxy->proxy, SERVER_SOCKET_TIMEOUT_RES) != 0) { | ||||
|         res->status = http_get_status(500); | ||||
|         ctx->origin = INTERNAL; | ||||
|         error("Unknown Error"); | ||||
|         error("Unable to set timeout for reverse proxy socket"); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     while (1) { | ||||
|         ret = proxy_peek_response(proxy, res, ctx, custom_status, err_msg); | ||||
|         if (ret < 0) { | ||||
|             return (int) ret; | ||||
|         } else if (sock_recv_x(&proxy->proxy, buffer, ret, 0) == -1) { | ||||
|             res->status = http_get_status(502); | ||||
|             ctx->origin = SERVER_RES; | ||||
|             error("Unable to receive from server"); | ||||
|             return -1; | ||||
|         } | ||||
|         if (res->status->code == 100) { | ||||
|             info("%s -> %03i %s%s", http_get_status_color(res->status->code), res->status->code, res->status->msg, CLR_STR); | ||||
|             if (http_send_response(client, res) != 0) { | ||||
|                 res->status = http_get_status(400); | ||||
|                 ctx->origin = CLIENT_RES; | ||||
|                 error("Unable to send to client"); | ||||
|                 return -1; | ||||
|             } | ||||
|         } else { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     long keep_alive_timeout = http_get_keep_alive_timeout(&res->hdr); | ||||
|     proxy->http_timeout = (keep_alive_timeout > 0) ? keep_alive_timeout * 1000000 : 0; | ||||
|  | ||||
|     connection = http_get_header_field(&res->hdr, "Connection"); | ||||
|     proxy->close = !streq(res->version, "1.1") || strcontains(connection, "close") || strcontains(connection, "Close"); | ||||
|  | ||||
|     ret = proxy_response_header(req, res, conf); | ||||
|     if (ret != 0) { | ||||
|         res->status = http_get_status(500); | ||||
|         ctx->origin = INTERNAL; | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int proxy_peek_response(proxy_ctx_t *proxy, http_res *res, http_status_ctx *ctx, http_status *custom_status, char *err_msg) { | ||||
|     char buffer[CHUNK_SIZE], err_buf[256]; | ||||
|     long ret; | ||||
|  | ||||
|     ret = sock_recv(&proxy->proxy, buffer, sizeof(buffer) - 1, MSG_PEEK); | ||||
|     if (ret <= 0) { | ||||
|         int e_sys = error_get_sys(), e_ssl = error_get_ssl(); | ||||
| @@ -487,6 +578,13 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu | ||||
|     } | ||||
|     buffer[ret] = 0; | ||||
|  | ||||
|     if (sock_set_socket_timeout(&proxy->proxy, SOCKET_TIMEOUT) != 0) { | ||||
|         res->status = http_get_status(500); | ||||
|         ctx->origin = INTERNAL; | ||||
|         error("Unable to set timeout for reverse proxy socket"); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     char *buf = buffer; | ||||
|     unsigned short header_len = (unsigned short) (strstr(buffer, "\r\n\r\n") - buffer + 4); | ||||
|  | ||||
| @@ -555,30 +653,15 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu | ||||
|         } | ||||
|         ptr = pos0 + 2; | ||||
|     } | ||||
|     if (sock_recv_x(&proxy->proxy, buffer, header_len, 0) == -1) | ||||
|         return -1; | ||||
|  | ||||
|     long keep_alive_timeout = http_get_keep_alive_timeout(&res->hdr); | ||||
|     proxy->http_timeout = (keep_alive_timeout > 0) ? keep_alive_timeout * 1000000 : 0; | ||||
|  | ||||
|     connection = http_get_header_field(&res->hdr, "Connection"); | ||||
|     proxy->close = !streq(res->version, "1.1") || strcontains(connection, "close") || strcontains(connection, "Close"); | ||||
|  | ||||
|     ret = proxy_response_header(req, res, conf); | ||||
|     if (ret != 0) { | ||||
|         res->status = http_get_status(500); | ||||
|         ctx->origin = INTERNAL; | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
|     return header_len; | ||||
| } | ||||
|  | ||||
| int proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int flags) { | ||||
| long proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int flags) { | ||||
|     long ret; | ||||
|     char buffer[CHUNK_SIZE]; | ||||
|     if (sock_splice(client, &proxy->proxy, buffer, sizeof(buffer), len_to_send) == -1) | ||||
|     if ((ret = sock_splice(client, &proxy->proxy, buffer, sizeof(buffer), len_to_send)) == -1) | ||||
|         return -1; | ||||
|     return 0; | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| int proxy_dump(proxy_ctx_t *proxy, char *buf, long len) { | ||||
|   | ||||
| @@ -43,7 +43,9 @@ int proxy_response_header(http_req *req, http_res *res, host_config_t *conf); | ||||
|  | ||||
| int proxy_init(proxy_ctx_t **proxy, http_req *req, http_res *res, http_status_ctx *ctx, host_config_t *conf, sock *client, http_status *custom_status, char *err_msg); | ||||
|  | ||||
| int proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int flags); | ||||
| int proxy_peek_response(proxy_ctx_t *proxy, http_res *res, http_status_ctx *ctx, http_status *custom_status, char *err_msg); | ||||
|  | ||||
| long proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int flags); | ||||
|  | ||||
| int proxy_dump(proxy_ctx_t *proxy, char *buf, long len); | ||||
|  | ||||
|   | ||||
| @@ -235,7 +235,7 @@ long sock_send(sock *s, void *buf, unsigned long len, int flags) { | ||||
| long sock_send_x(sock *s, void *buf, unsigned long len, int flags) { | ||||
|     for (long ret, sent = 0; sent < len; sent += ret) { | ||||
|         if ((ret = sock_send(s, (unsigned char *) buf + sent, len - sent, flags)) <= 0) { | ||||
|             if (errno == EINTR) { | ||||
|             if (errno == EINTR || errno == EAGAIN) { | ||||
|                 errno = 0, ret = 0; | ||||
|                 continue; | ||||
|             } else { | ||||
| @@ -278,7 +278,7 @@ long sock_recv(sock *s, void *buf, unsigned long len, int flags) { | ||||
| long sock_recv_x(sock *s, void *buf, unsigned long len, int flags) { | ||||
|     for (long ret, rcv = 0; rcv < len; rcv += ret) { | ||||
|         if ((ret = sock_recv(s, (unsigned char *) buf + rcv, len - rcv, flags | MSG_WAITALL)) <= 0) { | ||||
|             if (errno == EINTR) { | ||||
|             if (errno == EINTR || errno == EAGAIN) { | ||||
|                 errno = 0, ret = 0; | ||||
|                 continue; | ||||
|             } else { | ||||
| @@ -295,7 +295,7 @@ long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigne | ||||
|     if ((src->pipe || dst->pipe) && !src->enc && !dst->enc) { | ||||
|         for (long ret; send_len < len; send_len += ret) { | ||||
|             if ((ret = splice(src->socket, 0, dst->socket, 0, len, 0)) == -1) { | ||||
|                 if (errno == EINTR) { | ||||
|                 if (errno == EINTR || errno == EAGAIN) { | ||||
|                     errno = 0, ret = 0; | ||||
|                     continue; | ||||
|                 } else { | ||||
| @@ -308,7 +308,7 @@ long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigne | ||||
|             next_len = (long) ((buf_len < (len - send_len)) ? buf_len : (len - send_len)); | ||||
|  | ||||
|             if ((ret = sock_recv(src, buf, next_len, MSG_WAITALL)) <= 0) { | ||||
|                 if (errno == EINTR) { | ||||
|                 if (errno == EINTR || errno == EAGAIN) { | ||||
|                     errno = 0, ret = 0; | ||||
|                     continue; | ||||
|                 } else { | ||||
| @@ -328,7 +328,7 @@ long sock_splice_all(sock *dst, sock *src, void *buf, unsigned long buf_len) { | ||||
|     long send_len = 0; | ||||
|     for (long ret;; send_len += ret) { | ||||
|         if ((ret = sock_recv(src, buf, buf_len, 0)) <= 0) { | ||||
|             if (errno == EINTR) { | ||||
|             if (errno == EINTR || errno == EAGAIN) { | ||||
|                 errno = 0, ret = 0; | ||||
|                 continue; | ||||
|             } else if (ret == 0) { | ||||
| @@ -419,7 +419,7 @@ long sock_recv_chunk_header(sock *s) { | ||||
|  | ||||
|     do { | ||||
|         if ((ret = sock_recv(s, buf, sizeof(buf) - 1, MSG_PEEK)) <= 0) { | ||||
|             if (errno == EINTR) { | ||||
|             if (errno == EINTR || errno == EAGAIN) { | ||||
|                 errno = 0; | ||||
|                 continue; | ||||
|             } else { | ||||
|   | ||||
| @@ -39,7 +39,7 @@ int path_exists(const char *path) { | ||||
| } | ||||
|  | ||||
| int uri_init(http_uri *uri, const char *webroot, const char *uri_str, int dir_mode) { | ||||
|     char buf0[1024], buf1[1024], buf2[1024], buf3[1024]; | ||||
|     char buf0[1024], buf1[1024], buf2[1024], buf3[1024], buf4[1024]; | ||||
|     int p_len; | ||||
|  | ||||
|     uri->webroot = NULL; | ||||
| @@ -107,57 +107,71 @@ int uri_init(http_uri *uri, const char *webroot, const char *uri_str, int dir_mo | ||||
|  | ||||
|     while (1) { | ||||
|         sprintf(buf0, "%s%s", uri->webroot, uri->path); | ||||
|         p_len = snprintf(buf1, sizeof(buf1), "%s.php", buf0); | ||||
|         p_len = snprintf(buf1, sizeof(buf1), "%s.xhtml", buf0); | ||||
|         if (p_len < 0 || p_len >= sizeof(buf1)) return -1; | ||||
|         p_len = snprintf(buf2, sizeof(buf2), "%s.html", buf0); | ||||
|         if (p_len < 0 || p_len >= sizeof(buf2)) return -1; | ||||
|         p_len = snprintf(buf3, sizeof(buf3), "%s.php", buf0); | ||||
|         if (p_len < 0 || p_len >= sizeof(buf3)) return -1; | ||||
|  | ||||
|         if (strlen(uri->path) <= 1 || path_exists(buf0) || path_is_file(buf1) || path_is_file(buf2)) | ||||
|         if (strlen(uri->path) <= 1 || path_exists(buf0) || path_is_file(buf1) || path_is_file(buf2) || path_is_file(buf3)) | ||||
|             break; | ||||
|  | ||||
|         char *ptr; | ||||
|         parent_dir: | ||||
|         ptr = strrchr(uri->path, '/'); | ||||
|         size = (long) strlen(ptr); | ||||
|         sprintf(buf3, "%.*s%s", (int) size, ptr, uri->pathinfo); | ||||
|         strcpy(uri->pathinfo, buf3); | ||||
|         sprintf(buf4, "%.*s%s", (int) size, ptr, uri->pathinfo); | ||||
|         strcpy(uri->pathinfo, buf4); | ||||
|         ptr[0] = 0; | ||||
|     } | ||||
|     if (uri->pathinfo[0] != 0) { | ||||
|         sprintf(buf3, "%s", uri->pathinfo + 1); | ||||
|         strcpy(uri->pathinfo, buf3); | ||||
|         sprintf(buf4, "%s", uri->pathinfo + 1); | ||||
|         strcpy(uri->pathinfo, buf4); | ||||
|     } | ||||
|  | ||||
|     if (path_is_file(buf0)) { | ||||
|         uri->filename = malloc(strlen(buf0) + 1); | ||||
|         strcpy(uri->filename, buf0); | ||||
|         long len = (long) strlen(uri->path); | ||||
|         if (strends(uri->path, ".php")) { | ||||
|             uri->path[len - 4] = 0; | ||||
|             uri->is_static = 0; | ||||
|         if (strends(uri->path, ".xhtml")) { | ||||
|             uri->path[len - 6] = 0; | ||||
|         } else if (strends(uri->path, ".html")) { | ||||
|             uri->path[len - 5] = 0; | ||||
|         } else if (strends(uri->path, ".php")) { | ||||
|             uri->path[len - 4] = 0; | ||||
|             uri->is_static = 0; | ||||
|         } | ||||
|     } else if (path_is_file(buf1)) { | ||||
|         uri->is_static = 0; | ||||
|         uri->filename = malloc(strlen(buf1) + 1); | ||||
|         strcpy(uri->filename, buf1); | ||||
|     } else if (path_is_file(buf2)) { | ||||
|         uri->is_static = 0; | ||||
|         uri->filename = malloc(strlen(buf2) + 1); | ||||
|         strcpy(uri->filename, buf2); | ||||
|     } else if (path_is_file(buf3)) { | ||||
|         uri->filename = malloc(strlen(buf3) + 1); | ||||
|         strcpy(uri->filename, buf3); | ||||
|         uri->is_static = 0; | ||||
|     } else { | ||||
|         uri->is_dir = 1; | ||||
|         strcpy(uri->path + strlen(uri->path), "/"); | ||||
|         sprintf(buf1, "%s%s" "index.php", uri->webroot, uri->path); | ||||
|         sprintf(buf1, "%s%s" "index.xhtml", uri->webroot, uri->path); | ||||
|         sprintf(buf2, "%s%s" "index.html", uri->webroot, uri->path); | ||||
|         if (path_is_file(buf1)) { | ||||
|         sprintf(buf3, "%s%s" "index.php", uri->webroot, uri->path); | ||||
|         if (path_is_file(buf3) && uri->pathinfo[0] != 0) { | ||||
|             uri->filename = malloc(strlen(buf3) + 1); | ||||
|             strcpy(uri->filename, buf3); | ||||
|             uri->is_static = 0; | ||||
|         } else if (path_is_file(buf1)) { | ||||
|             uri->filename = malloc(strlen(buf1) + 1); | ||||
|             strcpy(uri->filename, buf1); | ||||
|             uri->is_static = 0; | ||||
|         } else if (path_is_file(buf2)) { | ||||
|             uri->filename = malloc(strlen(buf2) + 1); | ||||
|             strcpy(uri->filename, buf2); | ||||
|         } else if (path_is_file(buf3)) { | ||||
|             uri->filename = malloc(strlen(buf3) + 1); | ||||
|             strcpy(uri->filename, buf3); | ||||
|             uri->is_static = 0; | ||||
|         } else { | ||||
|             if (dir_mode == URI_DIR_MODE_FORBIDDEN) { | ||||
|                 uri->is_static = 1; | ||||
| @@ -174,17 +188,17 @@ int uri_init(http_uri *uri, const char *webroot, const char *uri_str, int dir_mo | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (strends(uri->path + strlen(uri->path), "index")) | ||||
|     if (strends(uri->path, "/index")) | ||||
|         uri->path[strlen(uri->path) - 5] = 0; | ||||
|  | ||||
|     if (streq(uri->pathinfo, "index.php") || streq(uri->pathinfo, "index.html")) | ||||
|     if (streq(uri->pathinfo, "index.php") || streq(uri->pathinfo, "index.html") || streq(uri->pathinfo, "index.xhtml")) | ||||
|         uri->pathinfo[0] = 0; | ||||
|  | ||||
|     sprintf(buf0, "%s%s%s%s%s", uri->path, | ||||
|     sprintf(buf4, "%s%s%s%s%s", uri->path, | ||||
|             (strlen(uri->pathinfo) == 0 || uri->path[strlen(uri->path) - 1] == '/') ? "" : "/", | ||||
|             uri->pathinfo, uri->query != NULL ? "?" : "", uri->query != NULL ? uri->query : ""); | ||||
|     uri->uri = malloc(strlen(buf0) + 1); | ||||
|     strcpy(uri->uri, buf0); | ||||
|     uri->uri = malloc(strlen(buf4) + 1); | ||||
|     strcpy(uri->uri, buf4); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -20,6 +20,24 @@ | ||||
|  | ||||
| static const char base64_encode_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||||
| static const int base64_mod_table[3] = {0, 2, 1}; | ||||
| static const char base64_decode_table[256] = { | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, | ||||
|     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1,  0, -1, -1, | ||||
|     -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, | ||||
|     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, | ||||
|     -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | ||||
|     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||
| }; | ||||
|  | ||||
|  | ||||
| char *format_duration(unsigned long micros, char *buf) { | ||||
| @@ -150,6 +168,7 @@ int mime_is_text(const char *restrict type) { | ||||
|         streq(type_parsed, "application/javascript") || | ||||
|         streq(type_parsed, "application/json") || | ||||
|         streq(type_parsed, "application/xml") || | ||||
|         streq(type_parsed, "application/sql") || | ||||
|         streq(type_parsed, "application/x-www-form-urlencoded") || | ||||
|         streq(type_parsed, "application/x-tex") || | ||||
|         streq(type_parsed, "application/x-httpd-php") || | ||||
| @@ -206,25 +225,25 @@ int strcontains(const char *restrict haystack, const char *restrict needle) { | ||||
|  | ||||
| int strstarts(const char *restrict str, const char *restrict prefix) { | ||||
|     if (str == NULL || prefix == NULL) return 0; | ||||
|     unsigned long l1 = strlen(str), l2 = strlen(prefix); | ||||
|     const unsigned long l1 = strlen(str), l2 = strlen(prefix); | ||||
|     return l2 <= l1 && strncmp(str, prefix, l2) == 0; | ||||
| } | ||||
|  | ||||
| int strends(const char *restrict str, const char *restrict suffix) { | ||||
|     if (str == NULL || suffix == NULL) return 0; | ||||
|     unsigned long l1 = strlen(str), l2 = strlen(suffix); | ||||
|     const unsigned long l1 = strlen(str), l2 = strlen(suffix); | ||||
|     return l2 <= l1 && strcmp(str + l1 - l2, suffix) == 0; | ||||
| } | ||||
|  | ||||
| int base64_encode(void *data, unsigned long data_len, char *output, unsigned long *output_len) { | ||||
|     unsigned long out_len = 4 * ((data_len + 2) / 3); | ||||
|     const unsigned long out_len = 4 * ((data_len + 2) / 3); | ||||
|     if (output_len != NULL) *output_len = out_len; | ||||
|  | ||||
|     for (int i = 0, j = 0; i < data_len;) { | ||||
|         unsigned int octet_a = (i < data_len) ? ((unsigned char *) data)[i++] : 0; | ||||
|         unsigned int octet_b = (i < data_len) ? ((unsigned char *) data)[i++] : 0; | ||||
|         unsigned int octet_c = (i < data_len) ? ((unsigned char *) data)[i++] : 0; | ||||
|         unsigned int triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; | ||||
|         const unsigned int octet_a = (i < data_len) ? ((unsigned char *) data)[i++] : 0; | ||||
|         const unsigned int octet_b = (i < data_len) ? ((unsigned char *) data)[i++] : 0; | ||||
|         const unsigned int octet_c = (i < data_len) ? ((unsigned char *) data)[i++] : 0; | ||||
|         const unsigned int triple = (octet_a << 16) | (octet_b << 8) | octet_c; | ||||
|         output[j++] = base64_encode_table[(triple >> 3 * 6) & 0x3F]; | ||||
|         output[j++] = base64_encode_table[(triple >> 2 * 6) & 0x3F]; | ||||
|         output[j++] = base64_encode_table[(triple >> 1 * 6) & 0x3F]; | ||||
| @@ -238,6 +257,28 @@ int base64_encode(void *data, unsigned long data_len, char *output, unsigned lon | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int base64_decode(const char *data, unsigned long data_len, void *output, unsigned long *output_len) { | ||||
|     const unsigned long out_len = 3 * ((data_len + 2) / 4); | ||||
|     if (output_len != NULL) *output_len = out_len; | ||||
|  | ||||
|     char *out = output; | ||||
|     for (int i = 0, j = 0; i < data_len;) { | ||||
|         const int octet_a = (i < data_len) ? base64_decode_table[((unsigned char *) data)[i++]] : 0; | ||||
|         const int octet_b = (i < data_len) ? base64_decode_table[((unsigned char *) data)[i++]] : 0; | ||||
|         const int octet_c = (i < data_len) ? base64_decode_table[((unsigned char *) data)[i++]] : 0; | ||||
|         const int octet_d = (i < data_len) ? base64_decode_table[((unsigned char *) data)[i++]] : 0; | ||||
|         if (octet_a < 0 || octet_b < 0 || octet_c < 0 || octet_d < 0) return -1; | ||||
|         const unsigned int triple = (octet_a << 3 * 6) | (octet_b << 2 * 6) | (octet_c << 6) | octet_d; | ||||
|         out[j++] = (char) (triple >> 16); | ||||
|         out[j++] = (char) ((triple >> 8) & 0xFF); | ||||
|         out[j++] = (char) (triple & 0xFF); | ||||
|     } | ||||
|  | ||||
|     out[out_len] = 0; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| long clock_micros(void) { | ||||
|     struct timespec time; | ||||
|     clock_gettime(CLOCK_MONOTONIC, &time); | ||||
|   | ||||
| @@ -47,6 +47,8 @@ int strends(const char *restrict str, const char *restrict suffix); | ||||
|  | ||||
| int base64_encode(void *data, unsigned long data_len, char *output, unsigned long *output_len); | ||||
|  | ||||
| int base64_decode(const char *data, unsigned long data_len, void *output, unsigned long *output_len); | ||||
|  | ||||
| long clock_micros(void); | ||||
|  | ||||
| long clock_cpu(void); | ||||
|   | ||||
							
								
								
									
										11
									
								
								src/server.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/server.c
									
									
									
									
									
								
							| @@ -40,6 +40,8 @@ static SSL_CTX *contexts[CONFIG_MAX_CERT_CONFIG]; | ||||
| static client_ctx_t **clients; | ||||
| static sem_t sem_clients_lock; | ||||
|  | ||||
| static void terminate_gracefully(int sig); | ||||
|  | ||||
| static void clean(void) { | ||||
|     notice("Cleaning sesimos cache and metadata files..."); | ||||
|  | ||||
| @@ -121,7 +123,7 @@ static void accept_cb(void *arg) { | ||||
|     client_ctx_t *client_ctx = malloc(sizeof(client_ctx_t)); | ||||
|     if (client_ctx == NULL) { | ||||
|         critical("Unable to allocate memory for client context"); | ||||
|         errno = 0; | ||||
|         terminate_gracefully(0); | ||||
|         return; | ||||
|     } | ||||
|     sock *client = &client_ctx->socket; | ||||
| @@ -132,6 +134,7 @@ static void accept_cb(void *arg) { | ||||
|     if (client_fd < 0) { | ||||
|         critical("Unable to accept connection"); | ||||
|         free(client_ctx); | ||||
|         terminate_gracefully(0); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -146,6 +149,7 @@ static void accept_cb(void *arg) { | ||||
|             continue; | ||||
|         } else { | ||||
|             critical("Unable to lock clients list"); | ||||
|             terminate_gracefully(0); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| @@ -154,8 +158,9 @@ static void accept_cb(void *arg) { | ||||
|     clients = list_append(clients, &client_ctx); | ||||
|     if (clients == NULL) { | ||||
|         critical("Unable to add client context to list"); | ||||
|         sem_post(&sem_clients_lock); | ||||
|         free(client_ctx); | ||||
|         errno = 0; | ||||
|         terminate_gracefully(0); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -326,7 +331,7 @@ int main(int argc, char *const argv[]) { | ||||
|         SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); | ||||
|         SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); | ||||
|         SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); | ||||
|         SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); | ||||
|         SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY); | ||||
|         SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"); | ||||
|         SSL_CTX_set_ecdh_auto(ctx, 1); | ||||
|         SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); | ||||
|   | ||||
| @@ -14,8 +14,11 @@ | ||||
| #define NUM_SOCKETS 2 | ||||
| #define LISTEN_BACKLOG 16 | ||||
| #define REQ_PER_CONNECTION 200 | ||||
|  | ||||
| #define SOCKET_TIMEOUT 1 | ||||
| #define CLIENT_TIMEOUT 3600 | ||||
| #define SERVER_TIMEOUT_INIT 4 | ||||
| #define SERVER_SOCKET_TIMEOUT_INIT 5 | ||||
| #define SERVER_SOCKET_TIMEOUT_RES 60 | ||||
| #define SERVER_TIMEOUT 3600 | ||||
|  | ||||
| #define CNX_HANDLER_WORKERS 8 | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /** | ||||
|  * sesimos - secure, simple, modern web server | ||||
|  * @brief FastCGI frame handler | ||||
|  * @file src/worker/fcti_frame_handler.c | ||||
|  * @file src/worker/fcgi_frame_handler.c | ||||
|  * @author Lorenz Stechauner | ||||
|  * @date 2023-01-22 | ||||
|  */ | ||||
| @@ -16,7 +16,7 @@ void chunk_handler_func(chunk_ctx_t *ctx) { | ||||
|     logger_set_prefix("[%*s]%s", ADDRSTRLEN, ctx->client->socket.s_addr, ctx->client->log_prefix); | ||||
|  | ||||
|     char buf[CHUNK_SIZE]; | ||||
|     long sent = sock_splice_chunked(&ctx->client->socket, ctx->socket, buf, sizeof(buf), ctx->flags | SOCK_SINGLE_CHUNK); | ||||
|     const long sent = sock_splice_chunked(&ctx->client->socket, ctx->socket, buf, sizeof(buf), ctx->flags | SOCK_SINGLE_CHUNK); | ||||
|     if (sent < 0) { | ||||
|         // error | ||||
|         error("Unable to splice chunk"); | ||||
| @@ -28,6 +28,7 @@ void chunk_handler_func(chunk_ctx_t *ctx) { | ||||
|         ctx->next_cb(ctx); | ||||
|     } else { | ||||
|         // next chunk | ||||
|         ctx->client->transferred_length += sent; | ||||
|         handle_chunk(ctx); | ||||
|         return; | ||||
|     } | ||||
|   | ||||
| @@ -37,7 +37,7 @@ void fastcgi_frame_handler_func(fastcgi_ctx_t *ctx) { | ||||
|  | ||||
| int fastcgi_handle_connection(client_ctx_t *ctx, fastcgi_cnx_t **cnx) { | ||||
|     sock_set_timeout(&(*cnx)->socket, FASTCGI_TIMEOUT); | ||||
|     sock_set_socket_timeout(&(*cnx)->socket, 1); | ||||
|     sock_set_socket_timeout(&(*cnx)->socket, FASTCGI_SOCKET_TIMEOUT); | ||||
|  | ||||
|     fastcgi_ctx_t *a = malloc(sizeof(fastcgi_ctx_t)); | ||||
|     a->closed = 0; | ||||
| @@ -51,10 +51,9 @@ int fastcgi_handle_connection(client_ctx_t *ctx, fastcgi_cnx_t **cnx) { | ||||
| } | ||||
|  | ||||
| void fastcgi_close(fastcgi_ctx_t *ctx) { | ||||
|     if (ctx->closed == 0) { | ||||
|         ctx->closed++; | ||||
|     ctx->closed++; | ||||
|     if (ctx->closed != 2) | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     logger_set_prefix("[%*s]%s", ADDRSTRLEN, ctx->client->socket.s_addr, ctx->client->log_prefix); | ||||
|  | ||||
| @@ -70,3 +69,8 @@ void fastcgi_close(fastcgi_ctx_t *ctx) { | ||||
|     free(ctx); | ||||
|     errno = 0; | ||||
| } | ||||
|  | ||||
| void fastcgi_close_error(fastcgi_ctx_t *ctx) { | ||||
|     logger_set_prefix("[%*s]%s", ADDRSTRLEN, ctx->client->socket.s_addr, ctx->client->log_prefix); | ||||
|     fastcgi_close_cnx(&ctx->cnx); | ||||
| } | ||||
|   | ||||
| @@ -27,10 +27,8 @@ void fastcgi_handler_func(client_ctx_t *ctx) { | ||||
|         int ret = fastcgi_handler_1(ctx, &fcgi_cnx); | ||||
|         respond(ctx); | ||||
|         if (ret == 0) { | ||||
|             switch (fastcgi_handler_2(ctx, fcgi_cnx)) { | ||||
|                 case 1: return; | ||||
|                 case 2: break; | ||||
|             } | ||||
|             fastcgi_handler_2(ctx, fcgi_cnx); | ||||
|             return; | ||||
|         } else if (ctx->fcgi_ctx != NULL) { | ||||
|             fastcgi_close(ctx->fcgi_ctx); | ||||
|         } | ||||
| @@ -63,11 +61,6 @@ static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t **fcgi_cnx) { | ||||
|     fcgi_cnx_buf.r_addr = ctx->socket.addr; | ||||
|     fcgi_cnx_buf.r_host = (ctx->host[0] != 0) ? ctx->host : NULL; | ||||
|  | ||||
|     struct stat statbuf; | ||||
|     stat(uri->filename, &statbuf); | ||||
|     char *last_modified = http_format_date(statbuf.st_mtime, buf, sizeof(buf)); | ||||
|     http_add_header_field(&res->hdr, "Last-Modified", last_modified); | ||||
|  | ||||
|     res->status = http_get_status(200); | ||||
|     if (fastcgi_init(&fcgi_cnx_buf, mode, ctx->req_num, client, req, uri) != 0) { | ||||
|         fastcgi_close_cnx(&fcgi_cnx_buf); | ||||
| @@ -79,13 +72,34 @@ static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t **fcgi_cnx) { | ||||
|     (*fcgi_cnx) = &fcgi_cnx_buf; | ||||
|     fastcgi_handle_connection(ctx, fcgi_cnx); | ||||
|  | ||||
|     int expect_100_continue = 0; | ||||
|     const char *client_expect = http_get_header_field(&req->hdr, "Expect"); | ||||
|     if (client_expect != NULL && strcasecmp(client_expect, "100-continue") == 0) { | ||||
|         expect_100_continue = 1; | ||||
|     } else if (client_expect != NULL) { | ||||
|         fastcgi_close_cnx((&fcgi_cnx_buf)); | ||||
|         res->status = http_get_status(417); | ||||
|         return 3; | ||||
|     } | ||||
|     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 (expect_100_continue) { | ||||
|             info(HTTP_1XX_STR "100 Continue" CLR_STR); | ||||
|             http_send_100_continue(client); | ||||
|         } | ||||
|         unsigned long client_content_len = strtoul(client_content_length, NULL, 10); | ||||
|         ret = fastcgi_receive(*fcgi_cnx, client, client_content_len); | ||||
|     } else if (strcontains(client_transfer_encoding, "chunked")) { | ||||
|         if (expect_100_continue) { | ||||
|             info(HTTP_1XX_STR "100 Continue" CLR_STR); | ||||
|             http_send_100_continue(client); | ||||
|         } | ||||
|         ret = fastcgi_receive_chunked(*fcgi_cnx, client); | ||||
|     } else if (expect_100_continue) { | ||||
|         fastcgi_close_cnx((&fcgi_cnx_buf)); | ||||
|         res->status = http_get_status(417); | ||||
|         return 3; | ||||
|     } else { | ||||
|         ret = 0; | ||||
|     } | ||||
| @@ -165,7 +179,7 @@ static void fastcgi_error_cb(chunk_ctx_t *ctx) { | ||||
|     // FIXME segfault on error_cb | ||||
|     warning("Closing connection due to FastCGI error"); | ||||
|     if(ctx->client->fcgi_ctx) { | ||||
|         fastcgi_close(ctx->client->fcgi_ctx); | ||||
|         fastcgi_close_error(ctx->client->fcgi_ctx); | ||||
|         ctx->client->fcgi_ctx = NULL; | ||||
|     } | ||||
|  | ||||
| @@ -176,15 +190,6 @@ static void fastcgi_error_cb(chunk_ctx_t *ctx) { | ||||
|  | ||||
| static int fastcgi_handler_2(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) { | ||||
|     int chunked = strcontains(http_get_header_field(&ctx->res.hdr, "Transfer-Encoding"), "chunked"); | ||||
|  | ||||
|     if (chunked) { | ||||
|         handle_chunks(ctx, &fcgi_cnx->out, SOCK_CHUNKED, fastcgi_next_cb, fastcgi_error_cb); | ||||
|         return 1; | ||||
|     } else { | ||||
|         fastcgi_send(fcgi_cnx, &ctx->socket); | ||||
|         fastcgi_close(ctx->fcgi_ctx); | ||||
|         ctx->fcgi_ctx = NULL; | ||||
|         fastcgi_handle(ctx); | ||||
|         return 2; | ||||
|     } | ||||
|     handle_chunks(ctx, &fcgi_cnx->out, chunked ? SOCK_CHUNKED : 0, fastcgi_next_cb, fastcgi_error_cb); | ||||
|     return 1; | ||||
| } | ||||
|   | ||||
| @@ -33,7 +33,7 @@ typedef struct { | ||||
|     http_status custom_status; | ||||
|     host_config_t *conf; | ||||
|     FILE *file; | ||||
|     long content_length; | ||||
|     long content_length, transferred_length; | ||||
|     char *msg_buf, *msg_buf_ptr, msg_content[1024]; | ||||
|     proxy_ctx_t *proxy; | ||||
|     void *fcgi_ctx; | ||||
| @@ -46,7 +46,7 @@ typedef struct { | ||||
| } ws_ctx_t; | ||||
|  | ||||
| typedef struct { | ||||
|     int closed:2; | ||||
|     unsigned char closed:4; | ||||
|     client_ctx_t *client; | ||||
|     fastcgi_cnx_t cnx; | ||||
| } fastcgi_ctx_t; | ||||
| @@ -95,4 +95,6 @@ int fastcgi_handle_connection(client_ctx_t *ctx, fastcgi_cnx_t **cnx); | ||||
|  | ||||
| void fastcgi_close(fastcgi_ctx_t *ctx); | ||||
|  | ||||
| void fastcgi_close_error(fastcgi_ctx_t *ctx); | ||||
|  | ||||
| #endif //SESIMOS_FUNC_H | ||||
|   | ||||
| @@ -155,97 +155,107 @@ static int local_handler(client_ctx_t *ctx) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if (uri->is_static) { | ||||
|         res->status = http_get_status(200); | ||||
|         cache_init_uri(ctx->conf->cache, uri); | ||||
|  | ||||
|         http_add_header_field(&res->hdr, "Accept-Ranges", mime_is_text(uri->meta->type) ? "bytes, lines" : "bytes"); | ||||
|  | ||||
|         if (!streq(req->method, "GET") && !streq(req->method, "HEAD")) { | ||||
|             res->status = http_get_status(405); | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         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); | ||||
|             sprintf(err_msg, "A GET request must not contain a payload"); | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         const char *last_modified = http_format_date(uri->meta->mtime, buf1, sizeof(buf1)); | ||||
|         http_add_header_field(&res->hdr, "Last-Modified", last_modified); | ||||
|         sprintf(buf2, "%s; charset=%s", uri->meta->type, uri->meta->charset); | ||||
|         http_add_header_field(&res->hdr, "Content-Type", buf2); | ||||
|  | ||||
|         const char *accept_encoding = http_get_header_field(&req->hdr, "Accept-Encoding"); | ||||
|         int enc = 0; | ||||
|         if (accept_encoding != NULL) { | ||||
|             if (uri->meta->filename_comp_br[0] != 0 && strcontains(accept_encoding, "br")) { | ||||
|                 ctx->file = fopen(uri->meta->filename_comp_br, "rb"); | ||||
|                 if (ctx->file == NULL) { | ||||
|                     cache_mark_dirty(ctx->conf->cache, uri->filename); | ||||
|                     errno = 0; | ||||
|                 } else { | ||||
|                     http_add_header_field(&res->hdr, "Content-Encoding", "br"); | ||||
|                     enc = COMPRESS_BR; | ||||
|                 } | ||||
|             } else if (uri->meta->filename_comp_gz[0] != 0 && strcontains(accept_encoding, "gzip")) { | ||||
|                 ctx->file = fopen(uri->meta->filename_comp_gz, "rb"); | ||||
|                 if (ctx->file == NULL) { | ||||
|                     cache_mark_dirty(ctx->conf->cache, uri->filename); | ||||
|                     errno = 0; | ||||
|                 } else { | ||||
|                     http_add_header_field(&res->hdr, "Content-Encoding", "gzip"); | ||||
|                     enc = COMPRESS_GZ; | ||||
|                 } | ||||
|             } | ||||
|             if (enc != 0) { | ||||
|                 http_add_header_field(&res->hdr, "Vary", "Accept-Encoding"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (uri->meta->etag[0] != 0) { | ||||
|             strcpy(buf1, uri->meta->etag); | ||||
|             if (enc) { | ||||
|                 strcat(buf1, "-"); | ||||
|                 strcat(buf1, (enc & COMPRESS_BR) ? "br" : (enc & COMPRESS_GZ) ? "gzip" : ""); | ||||
|             } | ||||
|             http_add_header_field(&res->hdr, "ETag", buf1); | ||||
|         } | ||||
|  | ||||
|         http_add_header_field(&res->hdr, "Cache-Control", mime_is_text(uri->meta->type) ? "public, max-age=3600" : "public, max-age=86400"); | ||||
|  | ||||
|         const char *if_modified_since = http_get_header_field(&req->hdr, "If-Modified-Since"); | ||||
|         const char *if_none_match = http_get_header_field(&req->hdr, "If-None-Match"); | ||||
|         if ((if_none_match != NULL && !strcontains(if_none_match, uri->meta->etag)) || | ||||
|             (accept_if_modified_since && streq(if_modified_since, last_modified))) | ||||
|         { | ||||
|             res->status = http_get_status(304); | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         if (http_get_header_field(&req->hdr, "Range") != NULL) { | ||||
|             if (range_handler(ctx) == 0) { | ||||
|                 res->status = http_get_status(206); | ||||
|             } else { | ||||
|                 if (ctx->file) { | ||||
|                     fclose(ctx->file); | ||||
|                     ctx->file = NULL; | ||||
|                 } | ||||
|                 http_remove_header_field(&res->hdr, "Content-Type", HTTP_REMOVE_ALL); | ||||
|                 http_remove_header_field(&res->hdr, "Last-Modified", HTTP_REMOVE_ALL); | ||||
|                 http_remove_header_field(&res->hdr, "ETag", HTTP_REMOVE_ALL); | ||||
|                 http_remove_header_field(&res->hdr, "Cache-Control", HTTP_REMOVE_ALL); | ||||
|                 res->status = http_get_status(416); | ||||
|             } | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         if (ctx->file == NULL) ctx->file = fopen(uri->filename, "rb"); | ||||
|         ctx->content_length = fsize(ctx->file); | ||||
|     } else { | ||||
|     if (!uri->is_static) { | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     const char *client_expect = http_get_header_field(&req->hdr, "Expect"); | ||||
|     if (client_expect != NULL && strcasecmp(client_expect, "100-continue") != 0) { | ||||
|         res->status = http_get_status(417); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     res->status = http_get_status(200); | ||||
|     cache_init_uri(ctx->conf->cache, uri); | ||||
|  | ||||
|     http_add_header_field(&res->hdr, "Accept-Ranges", mime_is_text(uri->meta->type) ? "bytes, lines" : "bytes"); | ||||
|  | ||||
|     if (!streq(req->method, "GET") && !streq(req->method, "HEAD")) { | ||||
|         res->status = http_get_status(405); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     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); | ||||
|         sprintf(err_msg, "A GET request must not contain a payload"); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     const char *last_modified = http_format_date(uri->meta->mtime, buf1, sizeof(buf1)); | ||||
|     http_add_header_field(&res->hdr, "Last-Modified", last_modified); | ||||
|     sprintf(buf2, "%s; charset=%s", uri->meta->type, uri->meta->charset); | ||||
|     http_add_header_field(&res->hdr, "Content-Type", buf2); | ||||
|  | ||||
|     const char *accept_encoding = http_get_header_field(&req->hdr, "Accept-Encoding"); | ||||
|     int enc = 0; | ||||
|     if (accept_encoding != NULL) { | ||||
|         if (uri->meta->filename_comp_br[0] != 0 && strcontains(accept_encoding, "br")) { | ||||
|             ctx->file = fopen(uri->meta->filename_comp_br, "rb"); | ||||
|             if (ctx->file == NULL) { | ||||
|                 cache_mark_dirty(ctx->conf->cache, uri->filename); | ||||
|                 errno = 0; | ||||
|             } else { | ||||
|                 http_add_header_field(&res->hdr, "Content-Encoding", "br"); | ||||
|                 enc = COMPRESS_BR; | ||||
|             } | ||||
|         } else if (uri->meta->filename_comp_gz[0] != 0 && strcontains(accept_encoding, "gzip")) { | ||||
|             ctx->file = fopen(uri->meta->filename_comp_gz, "rb"); | ||||
|             if (ctx->file == NULL) { | ||||
|                 cache_mark_dirty(ctx->conf->cache, uri->filename); | ||||
|                 errno = 0; | ||||
|             } else { | ||||
|                 http_add_header_field(&res->hdr, "Content-Encoding", "gzip"); | ||||
|                 enc = COMPRESS_GZ; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     if (uri->meta->filename_comp_br[0] != 0 || uri->meta->filename_comp_gz[0] != 0) { | ||||
|         http_add_header_field(&res->hdr, "Vary", "Accept-Encoding"); | ||||
|     } | ||||
|  | ||||
|     buf1[0] = 0; | ||||
|     if (uri->meta->etag[0] != 0) { | ||||
|         buf1[0] = '"'; | ||||
|         strcpy(buf1 + 1, uri->meta->etag); | ||||
|         if (enc) { | ||||
|             strcat(buf1, "-"); | ||||
|             strcat(buf1, (enc & COMPRESS_BR) ? "br" : (enc & COMPRESS_GZ) ? "gzip" : ""); | ||||
|         } | ||||
|         strcat(buf1, "\""); | ||||
|         http_add_header_field(&res->hdr, "ETag", buf1); | ||||
|     } | ||||
|  | ||||
|     http_add_header_field(&res->hdr, "Cache-Control", mime_is_text(uri->meta->type) ? "public, must-revalidate, max-age=3600" : "public, must-revalidate, max-age=86400"); | ||||
|  | ||||
|     const char *if_modified_since = http_get_header_field(&req->hdr, "If-Modified-Since"); | ||||
|     const char *if_none_match = http_get_header_field(&req->hdr, "If-None-Match"); | ||||
|     if ((if_none_match != NULL && strcontains(if_none_match, buf1)) || | ||||
|         (accept_if_modified_since && streq(if_modified_since, last_modified))) | ||||
|     { | ||||
|         res->status = http_get_status(304); | ||||
|         ctx->content_length = 0; | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if (http_get_header_field(&req->hdr, "Range") != NULL) { | ||||
|         if (range_handler(ctx) == 0) { | ||||
|             res->status = http_get_status(206); | ||||
|         } else { | ||||
|             if (ctx->file) { | ||||
|                 fclose(ctx->file); | ||||
|                 ctx->file = NULL; | ||||
|             } | ||||
|             http_remove_header_field(&res->hdr, "Content-Type", HTTP_REMOVE_ALL); | ||||
|             http_remove_header_field(&res->hdr, "Last-Modified", HTTP_REMOVE_ALL); | ||||
|             http_remove_header_field(&res->hdr, "ETag", HTTP_REMOVE_ALL); | ||||
|             http_remove_header_field(&res->hdr, "Cache-Control", HTTP_REMOVE_ALL); | ||||
|             res->status = http_get_status(416); | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if (ctx->file == NULL) ctx->file = fopen(uri->filename, "rb"); | ||||
|     ctx->content_length = fsize(ctx->file); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -92,7 +92,8 @@ static int proxy_handler_1(client_ctx_t *ctx) { | ||||
|         const char *content_type = http_get_header_field(&res->hdr, "Content-Type"); | ||||
|         const char *content_length_f = http_get_header_field(&res->hdr, "Content-Length"); | ||||
|         const char *content_encoding = http_get_header_field(&res->hdr, "Content-Encoding"); | ||||
|         if (content_encoding == NULL && ( | ||||
|         const char *transfer_encoding = http_get_header_field(&res->hdr, "Transfer-Encoding"); | ||||
|         if (transfer_encoding == NULL && content_encoding == NULL && ( | ||||
|                 content_length_f == NULL || | ||||
|                 streq(content_length_f, "0") || | ||||
|                 (content_length_f != NULL && strstarts(content_type, "text/html")))) | ||||
| @@ -137,19 +138,21 @@ static void proxy_chunk_err_cb(chunk_ctx_t *ctx) { | ||||
|  | ||||
| static int proxy_handler_2(client_ctx_t *ctx) { | ||||
|     const char *transfer_encoding = http_get_header_field(&ctx->res.hdr, "Transfer-Encoding"); | ||||
|     int chunked = strcontains(transfer_encoding, "chunked"); | ||||
|     const int chunked = strcontains(transfer_encoding, "chunked"); | ||||
|  | ||||
|     const char *content_len = http_get_header_field(&ctx->res.hdr, "Content-Length"); | ||||
|     unsigned long len_to_send = (content_len != NULL) ? strtol(content_len, NULL, 10) : 0; | ||||
|     const unsigned long len_to_send = (content_len != NULL) ? strtol(content_len, NULL, 10) : 0; | ||||
|  | ||||
|     if (chunked) { | ||||
|         handle_chunks(ctx, &ctx->proxy->proxy, SOCK_CHUNKED, proxy_chunk_next_cb, proxy_chunk_err_cb); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     int ret; | ||||
|     long ret; | ||||
|     if ((ret = proxy_send(ctx->proxy, &ctx->socket, len_to_send, 0)) == -1) { | ||||
|         ctx->c_keep_alive = 0; | ||||
|     } else if (ret > 0) { | ||||
|         ctx->transferred_length += ret; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
|   | ||||
| @@ -59,6 +59,8 @@ static void init_ctx(client_ctx_t *ctx) { | ||||
|     ctx->req_host[0] = 0; | ||||
|     ctx->err_msg[0] = 0; | ||||
|     ctx->req_s = ctx->socket.ts_last; | ||||
|     ctx->transferred_length = 0; | ||||
|     ctx->content_length = 0; | ||||
|  | ||||
|     memset(&ctx->uri, 0, sizeof(ctx->uri)); | ||||
|     memset(&ctx->req, 0, sizeof(ctx->req)); | ||||
| @@ -249,7 +251,7 @@ int respond(client_ctx_t *ctx) { | ||||
|         if (http_get_header_field(&res->hdr, "Accept-Ranges") == NULL) { | ||||
|             http_add_header_field(&res->hdr, "Accept-Ranges", "none"); | ||||
|         } | ||||
|         if (!ctx->use_fastcgi && ctx->file == NULL && ctx->msg_buf == NULL) { | ||||
|         if (!ctx->use_fastcgi && ctx->file == NULL && ctx->msg_buf == NULL && res->status->code != 304) { | ||||
|             http_remove_header_field(&res->hdr, "Date", HTTP_REMOVE_ALL); | ||||
|             http_remove_header_field(&res->hdr, "Server", HTTP_REMOVE_ALL); | ||||
|             http_remove_header_field(&res->hdr, "Cache-Control", HTTP_REMOVE_ALL); | ||||
| @@ -373,10 +375,48 @@ int respond(client_ctx_t *ctx) { | ||||
| } | ||||
|  | ||||
| void request_complete(client_ctx_t *ctx) { | ||||
|     char buf[32]; | ||||
|     char buf[64]; | ||||
|     ctx->req_e = clock_micros(); | ||||
|     info("Transfer complete: %s", format_duration(ctx->req_e - ctx->req_s, buf)); | ||||
|  | ||||
|     if (ctx->conf) { | ||||
|         char path[256]; | ||||
|         sprintf(path, "/var/log/sesimos/%s.access.log", ctx->req_host); | ||||
|         FILE *log = fopen(path, "a"); | ||||
|         if (log) { | ||||
|             struct timespec time1, time2; | ||||
|             clock_gettime(CLOCK_MONOTONIC, &time1); | ||||
|             clock_gettime(CLOCK_REALTIME, &time2); | ||||
|             const long diff = (time2.tv_sec - time1.tv_sec) * 1000000 + (time2.tv_nsec - time1.tv_nsec) / 1000; | ||||
|             struct tm time_info; | ||||
|             const long ts = (ctx->req_s + diff) / 1000000; | ||||
|             strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&ts, &time_info)); | ||||
|  | ||||
|             const char *auth = http_get_header_field(&ctx->req.hdr, "Authorization"); | ||||
|             char user[256] = {0}; | ||||
|             if (auth != NULL && strstarts(auth, "Basic ")) { | ||||
|                 base64_decode(auth + 6, strlen(auth) - 6, user, NULL); | ||||
|                 char *col = strchr(user, ':'); | ||||
|                 if (col != NULL) col[0] = 0; | ||||
|             } | ||||
|             const char *ref = http_get_header_field(&ctx->req.hdr, "Referer"); | ||||
|             const char *ua = http_get_header_field(&ctx->req.hdr, "User-Agent"); | ||||
|             const char *loc = http_get_header_field(&ctx->res.hdr, "Location"); | ||||
|             const char *type = http_get_header_field(&ctx->res.hdr, "Content-Type"); | ||||
|             const long len = ctx->content_length <= 0 ? ctx->transferred_length : ctx->content_length; | ||||
|  | ||||
|             fprintf(log, "%s %s %s [%s] \"%s %s HTTP/%s\" %i %li %s%s%s %s%s%s %s%s%s %s%s%s\n", | ||||
|                 ctx->socket.addr, "-", user[0] != 0 ? user : "-", buf, | ||||
|                 ctx->req.method, ctx->req.uri, ctx->req.version, ctx->res.status->code, len, | ||||
|                 loc != NULL ? "\"" : "", loc != NULL ? loc : "-", loc != NULL ? "\"" : "", | ||||
|                 type != NULL ? "\"" : "", type != NULL ? type : "-", type != NULL ? "\"" : "", | ||||
|                 ref != NULL ? "\"" : "", ref != NULL ? ref : "-", ref != NULL ? "\"" : "", | ||||
|                 ua != NULL ? "\"" : "", ua != NULL ? ua : "-", ua != NULL ? "\"" : ""); | ||||
|             fclose(log); | ||||
|         } | ||||
|         errno = 0; | ||||
|     } | ||||
|  | ||||
|     if (ctx->file) fclose(ctx->file); | ||||
|     free(ctx->msg_buf_ptr); | ||||
|     uri_free(&ctx->uri); | ||||
|   | ||||
| @@ -67,7 +67,7 @@ static int tcp_acceptor(client_ctx_t *ctx) { | ||||
|          ctx->host[0] != 0 ? ctx->host : "", ctx->host[0] != 0 ? ") " : "", | ||||
|          ctx->cc[0] != 0 ? ctx->cc : "N/A"); | ||||
|  | ||||
|     if (sock_set_socket_timeout(client, 1) != 0 || sock_set_timeout(client, CLIENT_TIMEOUT) != 0) { | ||||
|     if (sock_set_socket_timeout(client, SOCKET_TIMEOUT) != 0 || sock_set_timeout(client, CLIENT_TIMEOUT) != 0) { | ||||
|         error("Unable to set timeout for socket"); | ||||
|         return -1; | ||||
|     } | ||||
|   | ||||
| @@ -38,11 +38,11 @@ int ws_handle_connection(client_ctx_t *ctx) { | ||||
|     // copy proxy connection details | ||||
|     proxy_ctx_t *proxy = malloc(sizeof(proxy_ctx_t)); | ||||
|     memcpy(proxy, ctx->proxy, sizeof(proxy_ctx_t)); | ||||
|     ctx->proxy = proxy; | ||||
|  | ||||
|     // free proxy connection slot | ||||
|     ctx->proxy->initialized = 0; | ||||
|     proxy_unlock_ctx(ctx->proxy); | ||||
|     ctx->proxy = proxy; | ||||
|  | ||||
|     sock_set_timeout(&ctx->socket, WS_TIMEOUT); | ||||
|     sock_set_timeout(&proxy->proxy, WS_TIMEOUT); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user