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 <pthread.h>
 | 
				
			||||||
#include <semaphore.h>
 | 
					#include <semaphore.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <openssl/ssl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ASYNC_MAX_EVENTS 16
 | 
					#define ASYNC_MAX_EVENTS 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,7 +39,7 @@ typedef struct {
 | 
				
			|||||||
    evt_listen_t *q[ASYNC_MAX_EVENTS];
 | 
					    evt_listen_t *q[ASYNC_MAX_EVENTS];
 | 
				
			||||||
} listen_queue_t;
 | 
					} 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 volatile sig_atomic_t alive = 1;
 | 
				
			||||||
static pthread_t thread = -1;
 | 
					static pthread_t thread = -1;
 | 
				
			||||||
static sem_t lock;
 | 
					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_IN)  ret |= POLLIN;
 | 
				
			||||||
    if (events & ASYNC_PRI) ret |= POLLPRI;
 | 
					    if (events & ASYNC_PRI) ret |= POLLPRI;
 | 
				
			||||||
    if (events & ASYNC_OUT) ret |= POLLOUT;
 | 
					    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_HUP) ret |= POLLHUP;
 | 
				
			||||||
    if (events & ASYNC_RDNORM) ret |= POLLRDNORM;
 | 
					    if (events & ASYNC_RDNORM) ret |= POLLRDNORM;
 | 
				
			||||||
    if (events & ASYNC_RDBAND) ret |= POLLRDBAND;
 | 
					    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_IN)  ret |= EPOLLIN;
 | 
				
			||||||
    if (events & ASYNC_PRI) ret |= EPOLLPRI;
 | 
					    if (events & ASYNC_PRI) ret |= EPOLLPRI;
 | 
				
			||||||
    if (events & ASYNC_OUT) ret |= EPOLLOUT;
 | 
					    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_HUP) ret |= EPOLLHUP;
 | 
				
			||||||
    if (events & ASYNC_RDNORM) ret |= EPOLLRDNORM;
 | 
					    if (events & ASYNC_RDNORM) ret |= EPOLLRDNORM;
 | 
				
			||||||
    if (events & ASYNC_RDBAND) ret |= EPOLLRDBAND;
 | 
					    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 & POLLIN)   ret |= ASYNC_IN;
 | 
				
			||||||
    if (events & POLLPRI)  ret |= ASYNC_PRI;
 | 
					    if (events & POLLPRI)  ret |= ASYNC_PRI;
 | 
				
			||||||
    if (events & POLLOUT)  ret |= ASYNC_OUT;
 | 
					    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 & POLLHUP)  ret |= ASYNC_HUP;
 | 
				
			||||||
    if (events & POLLRDNORM) ret |= ASYNC_RDNORM;
 | 
					    if (events & POLLRDNORM) ret |= ASYNC_RDNORM;
 | 
				
			||||||
    if (events & POLLRDBAND) ret |= ASYNC_RDBAND;
 | 
					    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 & EPOLLIN)   ret |= ASYNC_IN;
 | 
				
			||||||
    if (events & EPOLLPRI)  ret |= ASYNC_PRI;
 | 
					    if (events & EPOLLPRI)  ret |= ASYNC_PRI;
 | 
				
			||||||
    if (events & EPOLLOUT)  ret |= ASYNC_OUT;
 | 
					    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 & EPOLLHUP)  ret |= ASYNC_HUP;
 | 
				
			||||||
    if (events & EPOLLRDNORM) ret |= ASYNC_RDNORM;
 | 
					    if (events & EPOLLRDNORM) ret |= ASYNC_RDNORM;
 | 
				
			||||||
    if (events & EPOLLRDBAND) ret |= ASYNC_RDBAND;
 | 
					    if (events & EPOLLRDBAND) ret |= ASYNC_RDBAND;
 | 
				
			||||||
@@ -167,6 +168,11 @@ static int async_check(evt_listen_t *evt) {
 | 
				
			|||||||
    }};
 | 
					    }};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // check, if fd is already ready
 | 
					    // 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)) {
 | 
					    switch (poll(fds, 1, 0)) {
 | 
				
			||||||
        case 1:
 | 
					        case 1:
 | 
				
			||||||
            // fd already ready
 | 
					            // fd already ready
 | 
				
			||||||
@@ -247,7 +253,7 @@ void async_thread(void) {
 | 
				
			|||||||
    struct epoll_event ev, events[ASYNC_MAX_EVENTS];
 | 
					    struct epoll_event ev, events[ASYNC_MAX_EVENTS];
 | 
				
			||||||
    int num_fds;
 | 
					    int num_fds;
 | 
				
			||||||
    long ts, min_ts, cur_ts;
 | 
					    long ts, min_ts, cur_ts;
 | 
				
			||||||
    listen_queue_t *l;
 | 
					    volatile listen_queue_t *l;
 | 
				
			||||||
    evt_listen_t **local;
 | 
					    evt_listen_t **local;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((local = list_create(sizeof(evt_listen_t *), 16)) == NULL) {
 | 
					    if ((local = list_create(sizeof(evt_listen_t *), 16)) == NULL) {
 | 
				
			||||||
@@ -260,8 +266,18 @@ void async_thread(void) {
 | 
				
			|||||||
    // main event loop
 | 
					    // main event loop
 | 
				
			||||||
    while (alive) {
 | 
					    while (alive) {
 | 
				
			||||||
        // swap listen queue
 | 
					        // 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;
 | 
					        l = listen_q;
 | 
				
			||||||
        listen_q = (listen_q == &listen1) ? &listen2 : &listen1;
 | 
					        listen_q = (listen_q == &listen1) ? &listen2 : &listen1;
 | 
				
			||||||
 | 
					        sem_post(&lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // fill local list and epoll instance with previously added queue entries
 | 
					        // fill local list and epoll instance with previously added queue entries
 | 
				
			||||||
        for (int i = 0; i < l->n; i++) {
 | 
					        for (int i = 0; i < l->n; i++) {
 | 
				
			||||||
@@ -282,8 +298,9 @@ void async_thread(void) {
 | 
				
			|||||||
                    errno = 0;
 | 
					                    errno = 0;
 | 
				
			||||||
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) != -1)
 | 
					                    if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) != -1)
 | 
				
			||||||
                        continue;
 | 
					                        continue;
 | 
				
			||||||
                } else if (errno == EBADF) {
 | 
					                } else if (errno == EBADF || errno == EPERM) {
 | 
				
			||||||
                    // fd probably already closed
 | 
					                    // fd probably already closed or does not support epoll somehow
 | 
				
			||||||
 | 
					                    // FIXME should not happen
 | 
				
			||||||
                    warning("Unable to add file descriptor to epoll instance");
 | 
					                    warning("Unable to add file descriptor to epoll instance");
 | 
				
			||||||
                    errno = 0;
 | 
					                    errno = 0;
 | 
				
			||||||
                    local = list_delete(local, &evt);
 | 
					                    local = list_delete(local, &evt);
 | 
				
			||||||
@@ -331,9 +348,8 @@ void async_thread(void) {
 | 
				
			|||||||
            if (async_exec(evt, async_e2a(events[i].events)) == 0) {
 | 
					            if (async_exec(evt, async_e2a(events[i].events)) == 0) {
 | 
				
			||||||
                logger_set_prefix("");
 | 
					                logger_set_prefix("");
 | 
				
			||||||
                if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) == -1) {
 | 
					                if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) == -1) {
 | 
				
			||||||
                    if (errno == EBADF || errno == ENOENT) {
 | 
					                    if (errno == EBADF || errno == ENOENT || errno == EPERM) {
 | 
				
			||||||
                        // already closed fd or not found, do not die
 | 
					                        // already closed, fd not found, or fd does not support epoll, anyway do not die
 | 
				
			||||||
                        warning("Unable to remove file descriptor from epoll instance");
 | 
					 | 
				
			||||||
                        errno = 0;
 | 
					                        errno = 0;
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        critical("Unable to remove file descriptor from epoll instance");
 | 
					                        critical("Unable to remove file descriptor from epoll instance");
 | 
				
			||||||
@@ -362,9 +378,8 @@ void async_thread(void) {
 | 
				
			|||||||
                evt->to_cb(evt->arg);
 | 
					                evt->to_cb(evt->arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) == -1) {
 | 
					                if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) == -1) {
 | 
				
			||||||
                    if (errno == EBADF || errno == ENOENT) {
 | 
					                    if (errno == EBADF || errno == ENOENT || errno == EPERM) {
 | 
				
			||||||
                        // already closed fd or not found, do not die
 | 
					                        // already closed, fd not found, or fd does not support epoll, anyway do not die
 | 
				
			||||||
                        warning("Unable to remove file descriptor from epoll instance");
 | 
					 | 
				
			||||||
                        errno = 0;
 | 
					                        errno = 0;
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        critical("Unable to remove file descriptor from epoll instance");
 | 
					                        critical("Unable to remove file descriptor from epoll instance");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@
 | 
				
			|||||||
#define ASYNC_IN     0x001
 | 
					#define ASYNC_IN     0x001
 | 
				
			||||||
#define ASYNC_PRI    0x002
 | 
					#define ASYNC_PRI    0x002
 | 
				
			||||||
#define ASYNC_OUT    0x004
 | 
					#define ASYNC_OUT    0x004
 | 
				
			||||||
#define ASYNC_ERR    0x008
 | 
					#define ASYNC_ERR_   0x008
 | 
				
			||||||
#define ASYNC_HUP    0x010
 | 
					#define ASYNC_HUP    0x010
 | 
				
			||||||
#define ASYNC_RDNORM 0x040
 | 
					#define ASYNC_RDNORM 0x040
 | 
				
			||||||
#define ASYNC_RDBAND 0x080
 | 
					#define ASYNC_RDBAND 0x080
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,6 +75,10 @@ static void magic_mime_type(const char *restrict filename, char *buf) {
 | 
				
			|||||||
            strcpy(buf, "application/javascript");
 | 
					            strcpy(buf, "application/javascript");
 | 
				
			||||||
            sem_post(&sem_magic);
 | 
					            sem_post(&sem_magic);
 | 
				
			||||||
            return;
 | 
					            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);
 | 
					    sock_close(&cnx->out);
 | 
				
			||||||
    if (cnx->fd_err != -1) close(cnx->fd_err);
 | 
					    if (cnx->fd_err != -1) close(cnx->fd_err);
 | 
				
			||||||
    if (cnx->fd_out != -1) close(cnx->fd_out);
 | 
					    if (cnx->fd_out != -1) close(cnx->fd_out);
 | 
				
			||||||
 | 
					    cnx->fd_err = -1;
 | 
				
			||||||
 | 
					    cnx->fd_out = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    errno = e;
 | 
					    errno = e;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -229,6 +231,7 @@ int fastcgi_php_error(fastcgi_cnx_t *cnx, char *err_msg) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    log_lvl_t msg_type = LOG_INFO;
 | 
					    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) {
 | 
					    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;
 | 
					        if (ret > 0) line[ret - 1] = 0;
 | 
				
			||||||
        line_ptr = line;
 | 
					        line_ptr = line;
 | 
				
			||||||
@@ -319,6 +322,7 @@ int fastcgi_recv_frame(fastcgi_cnx_t *cnx) {
 | 
				
			|||||||
            cnx->fd_err_bytes += content_len + 1;
 | 
					            cnx->fd_err_bytes += content_len + 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        for (long ret, sent = 0; sent < content_len; sent += ret) {
 | 
					        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 ((ret = splice(cnx->socket.socket, 0, fd, 0, content_len - sent, 0)) == -1) {
 | 
				
			||||||
                if (errno == EINTR) {
 | 
					                if (errno == EINTR) {
 | 
				
			||||||
                    errno = 0, ret = 0;
 | 
					                    errno = 0, ret = 0;
 | 
				
			||||||
@@ -353,11 +357,6 @@ int fastcgi_recv_frame(fastcgi_cnx_t *cnx) {
 | 
				
			|||||||
    return header.type;
 | 
					    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) {
 | 
					int fastcgi_header(fastcgi_cnx_t *cnx, http_res *res, char *err_msg) {
 | 
				
			||||||
    long ret, len;
 | 
					    long ret, len;
 | 
				
			||||||
    char content[CLIENT_MAX_HEADER_SIZE];
 | 
					    char content[CLIENT_MAX_HEADER_SIZE];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@
 | 
				
			|||||||
#include "http.h"
 | 
					#include "http.h"
 | 
				
			||||||
#include "uri.h"
 | 
					#include "uri.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FASTCGI_SOCKET_TIMEOUT 1
 | 
				
			||||||
#define FASTCGI_TIMEOUT 3600
 | 
					#define FASTCGI_TIMEOUT 3600
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define FASTCGI_BACKEND_PHP 1
 | 
					#define FASTCGI_BACKEND_PHP 1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -387,6 +387,14 @@ int http_send_request(sock *server, http_req *req) {
 | 
				
			|||||||
    return 0;
 | 
					    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) {
 | 
					const http_status *http_get_status(status_code_t status_code) {
 | 
				
			||||||
    for (int i = 0; i < http_statuses_size; i++) {
 | 
					    for (int i = 0; i < http_statuses_size; i++) {
 | 
				
			||||||
        if (http_statuses[i].code == status_code) {
 | 
					        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_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 *http_get_status(status_code_t status_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const http_status_msg *http_get_error_msg(status_code_t status_code);
 | 
					const http_status_msg *http_get_error_msg(status_code_t status_code);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										125
									
								
								src/lib/proxy.c
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								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);
 | 
					    info(BLUE_STR "Connecting to " BLD_STR "[%s]:%i" CLR_STR BLUE_STR "...", conf->proxy.hostname, conf->proxy.port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int fd;
 | 
					    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) {
 | 
					        if (errno == ETIMEDOUT || errno == EINPROGRESS || errno == EHOSTDOWN || errno == EHOSTUNREACH) {
 | 
				
			||||||
            res->status = http_get_status(504);
 | 
					            res->status = http_get_status(504);
 | 
				
			||||||
            ctx->origin = SERVER_REQ;
 | 
					            ctx->origin = SERVER_REQ;
 | 
				
			||||||
@@ -440,6 +440,46 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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");
 | 
					        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;
 | 
					        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");
 | 
					        const char *transfer_encoding = http_get_header_field(&req->hdr, "Transfer-Encoding");
 | 
				
			||||||
@@ -470,6 +510,57 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
 | 
				
			|||||||
            error("Unknown Error");
 | 
					            error("Unknown Error");
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (sock_set_socket_timeout(&proxy->proxy, SERVER_SOCKET_TIMEOUT_RES) != 0) {
 | 
				
			||||||
 | 
					        res->status = http_get_status(500);
 | 
				
			||||||
 | 
					        ctx->origin = INTERNAL;
 | 
				
			||||||
 | 
					        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);
 | 
					    ret = sock_recv(&proxy->proxy, buffer, sizeof(buffer) - 1, MSG_PEEK);
 | 
				
			||||||
    if (ret <= 0) {
 | 
					    if (ret <= 0) {
 | 
				
			||||||
@@ -487,6 +578,13 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    buffer[ret] = 0;
 | 
					    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;
 | 
					    char *buf = buffer;
 | 
				
			||||||
    unsigned short header_len = (unsigned short) (strstr(buffer, "\r\n\r\n") - buffer + 4);
 | 
					    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;
 | 
					        ptr = pos0 + 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (sock_recv_x(&proxy->proxy, buffer, header_len, 0) == -1)
 | 
					    return header_len;
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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];
 | 
					    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 -1;
 | 
				
			||||||
    return 0;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int proxy_dump(proxy_ctx_t *proxy, char *buf, long len) {
 | 
					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_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);
 | 
					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) {
 | 
					long sock_send_x(sock *s, void *buf, unsigned long len, int flags) {
 | 
				
			||||||
    for (long ret, sent = 0; sent < len; sent += ret) {
 | 
					    for (long ret, sent = 0; sent < len; sent += ret) {
 | 
				
			||||||
        if ((ret = sock_send(s, (unsigned char *) buf + sent, len - sent, flags)) <= 0) {
 | 
					        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;
 | 
					                errno = 0, ret = 0;
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            } else {
 | 
					            } 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) {
 | 
					long sock_recv_x(sock *s, void *buf, unsigned long len, int flags) {
 | 
				
			||||||
    for (long ret, rcv = 0; rcv < len; rcv += ret) {
 | 
					    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 ((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;
 | 
					                errno = 0, ret = 0;
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            } else {
 | 
					            } 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) {
 | 
					    if ((src->pipe || dst->pipe) && !src->enc && !dst->enc) {
 | 
				
			||||||
        for (long ret; send_len < len; send_len += ret) {
 | 
					        for (long ret; send_len < len; send_len += ret) {
 | 
				
			||||||
            if ((ret = splice(src->socket, 0, dst->socket, 0, len, 0)) == -1) {
 | 
					            if ((ret = splice(src->socket, 0, dst->socket, 0, len, 0)) == -1) {
 | 
				
			||||||
                if (errno == EINTR) {
 | 
					                if (errno == EINTR || errno == EAGAIN) {
 | 
				
			||||||
                    errno = 0, ret = 0;
 | 
					                    errno = 0, ret = 0;
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                } else {
 | 
					                } 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));
 | 
					            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 ((ret = sock_recv(src, buf, next_len, MSG_WAITALL)) <= 0) {
 | 
				
			||||||
                if (errno == EINTR) {
 | 
					                if (errno == EINTR || errno == EAGAIN) {
 | 
				
			||||||
                    errno = 0, ret = 0;
 | 
					                    errno = 0, ret = 0;
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
@@ -328,7 +328,7 @@ long sock_splice_all(sock *dst, sock *src, void *buf, unsigned long buf_len) {
 | 
				
			|||||||
    long send_len = 0;
 | 
					    long send_len = 0;
 | 
				
			||||||
    for (long ret;; send_len += ret) {
 | 
					    for (long ret;; send_len += ret) {
 | 
				
			||||||
        if ((ret = sock_recv(src, buf, buf_len, 0)) <= 0) {
 | 
					        if ((ret = sock_recv(src, buf, buf_len, 0)) <= 0) {
 | 
				
			||||||
            if (errno == EINTR) {
 | 
					            if (errno == EINTR || errno == EAGAIN) {
 | 
				
			||||||
                errno = 0, ret = 0;
 | 
					                errno = 0, ret = 0;
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            } else if (ret == 0) {
 | 
					            } else if (ret == 0) {
 | 
				
			||||||
@@ -419,7 +419,7 @@ long sock_recv_chunk_header(sock *s) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
        if ((ret = sock_recv(s, buf, sizeof(buf) - 1, MSG_PEEK)) <= 0) {
 | 
					        if ((ret = sock_recv(s, buf, sizeof(buf) - 1, MSG_PEEK)) <= 0) {
 | 
				
			||||||
            if (errno == EINTR) {
 | 
					            if (errno == EINTR || errno == EAGAIN) {
 | 
				
			||||||
                errno = 0;
 | 
					                errno = 0;
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            } else {
 | 
					            } 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) {
 | 
					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;
 | 
					    int p_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uri->webroot = NULL;
 | 
					    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) {
 | 
					    while (1) {
 | 
				
			||||||
        sprintf(buf0, "%s%s", uri->webroot, uri->path);
 | 
					        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;
 | 
					        if (p_len < 0 || p_len >= sizeof(buf1)) return -1;
 | 
				
			||||||
        p_len = snprintf(buf2, sizeof(buf2), "%s.html", buf0);
 | 
					        p_len = snprintf(buf2, sizeof(buf2), "%s.html", buf0);
 | 
				
			||||||
        if (p_len < 0 || p_len >= sizeof(buf2)) return -1;
 | 
					        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;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        char *ptr;
 | 
					        char *ptr;
 | 
				
			||||||
        parent_dir:
 | 
					        parent_dir:
 | 
				
			||||||
        ptr = strrchr(uri->path, '/');
 | 
					        ptr = strrchr(uri->path, '/');
 | 
				
			||||||
        size = (long) strlen(ptr);
 | 
					        size = (long) strlen(ptr);
 | 
				
			||||||
        sprintf(buf3, "%.*s%s", (int) size, ptr, uri->pathinfo);
 | 
					        sprintf(buf4, "%.*s%s", (int) size, ptr, uri->pathinfo);
 | 
				
			||||||
        strcpy(uri->pathinfo, buf3);
 | 
					        strcpy(uri->pathinfo, buf4);
 | 
				
			||||||
        ptr[0] = 0;
 | 
					        ptr[0] = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (uri->pathinfo[0] != 0) {
 | 
					    if (uri->pathinfo[0] != 0) {
 | 
				
			||||||
        sprintf(buf3, "%s", uri->pathinfo + 1);
 | 
					        sprintf(buf4, "%s", uri->pathinfo + 1);
 | 
				
			||||||
        strcpy(uri->pathinfo, buf3);
 | 
					        strcpy(uri->pathinfo, buf4);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (path_is_file(buf0)) {
 | 
					    if (path_is_file(buf0)) {
 | 
				
			||||||
        uri->filename = malloc(strlen(buf0) + 1);
 | 
					        uri->filename = malloc(strlen(buf0) + 1);
 | 
				
			||||||
        strcpy(uri->filename, buf0);
 | 
					        strcpy(uri->filename, buf0);
 | 
				
			||||||
        long len = (long) strlen(uri->path);
 | 
					        long len = (long) strlen(uri->path);
 | 
				
			||||||
        if (strends(uri->path, ".php")) {
 | 
					        if (strends(uri->path, ".xhtml")) {
 | 
				
			||||||
            uri->path[len - 4] = 0;
 | 
					            uri->path[len - 6] = 0;
 | 
				
			||||||
            uri->is_static = 0;
 | 
					 | 
				
			||||||
        } else if (strends(uri->path, ".html")) {
 | 
					        } else if (strends(uri->path, ".html")) {
 | 
				
			||||||
            uri->path[len - 5] = 0;
 | 
					            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)) {
 | 
					    } else if (path_is_file(buf1)) {
 | 
				
			||||||
        uri->is_static = 0;
 | 
					 | 
				
			||||||
        uri->filename = malloc(strlen(buf1) + 1);
 | 
					        uri->filename = malloc(strlen(buf1) + 1);
 | 
				
			||||||
        strcpy(uri->filename, buf1);
 | 
					        strcpy(uri->filename, buf1);
 | 
				
			||||||
    } else if (path_is_file(buf2)) {
 | 
					    } else if (path_is_file(buf2)) {
 | 
				
			||||||
        uri->is_static = 0;
 | 
					 | 
				
			||||||
        uri->filename = malloc(strlen(buf2) + 1);
 | 
					        uri->filename = malloc(strlen(buf2) + 1);
 | 
				
			||||||
        strcpy(uri->filename, buf2);
 | 
					        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 {
 | 
					    } else {
 | 
				
			||||||
        uri->is_dir = 1;
 | 
					        uri->is_dir = 1;
 | 
				
			||||||
        strcpy(uri->path + strlen(uri->path), "/");
 | 
					        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);
 | 
					        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);
 | 
					            uri->filename = malloc(strlen(buf1) + 1);
 | 
				
			||||||
            strcpy(uri->filename, buf1);
 | 
					            strcpy(uri->filename, buf1);
 | 
				
			||||||
            uri->is_static = 0;
 | 
					 | 
				
			||||||
        } else if (path_is_file(buf2)) {
 | 
					        } else if (path_is_file(buf2)) {
 | 
				
			||||||
            uri->filename = malloc(strlen(buf2) + 1);
 | 
					            uri->filename = malloc(strlen(buf2) + 1);
 | 
				
			||||||
            strcpy(uri->filename, buf2);
 | 
					            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 {
 | 
					        } else {
 | 
				
			||||||
            if (dir_mode == URI_DIR_MODE_FORBIDDEN) {
 | 
					            if (dir_mode == URI_DIR_MODE_FORBIDDEN) {
 | 
				
			||||||
                uri->is_static = 1;
 | 
					                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;
 | 
					        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;
 | 
					        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] == '/') ? "" : "/",
 | 
					            (strlen(uri->pathinfo) == 0 || uri->path[strlen(uri->path) - 1] == '/') ? "" : "/",
 | 
				
			||||||
            uri->pathinfo, uri->query != NULL ? "?" : "", uri->query != NULL ? uri->query : "");
 | 
					            uri->pathinfo, uri->query != NULL ? "?" : "", uri->query != NULL ? uri->query : "");
 | 
				
			||||||
    uri->uri = malloc(strlen(buf0) + 1);
 | 
					    uri->uri = malloc(strlen(buf4) + 1);
 | 
				
			||||||
    strcpy(uri->uri, buf0);
 | 
					    strcpy(uri->uri, buf4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static const char base64_encode_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
					static const char base64_encode_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
				
			||||||
static const int base64_mod_table[3] = {0, 2, 1};
 | 
					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) {
 | 
					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/javascript") ||
 | 
				
			||||||
        streq(type_parsed, "application/json") ||
 | 
					        streq(type_parsed, "application/json") ||
 | 
				
			||||||
        streq(type_parsed, "application/xml") ||
 | 
					        streq(type_parsed, "application/xml") ||
 | 
				
			||||||
 | 
					        streq(type_parsed, "application/sql") ||
 | 
				
			||||||
        streq(type_parsed, "application/x-www-form-urlencoded") ||
 | 
					        streq(type_parsed, "application/x-www-form-urlencoded") ||
 | 
				
			||||||
        streq(type_parsed, "application/x-tex") ||
 | 
					        streq(type_parsed, "application/x-tex") ||
 | 
				
			||||||
        streq(type_parsed, "application/x-httpd-php") ||
 | 
					        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) {
 | 
					int strstarts(const char *restrict str, const char *restrict prefix) {
 | 
				
			||||||
    if (str == NULL || prefix == NULL) return 0;
 | 
					    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;
 | 
					    return l2 <= l1 && strncmp(str, prefix, l2) == 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int strends(const char *restrict str, const char *restrict suffix) {
 | 
					int strends(const char *restrict str, const char *restrict suffix) {
 | 
				
			||||||
    if (str == NULL || suffix == NULL) return 0;
 | 
					    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;
 | 
					    return l2 <= l1 && strcmp(str + l1 - l2, suffix) == 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int base64_encode(void *data, unsigned long data_len, char *output, unsigned long *output_len) {
 | 
					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;
 | 
					    if (output_len != NULL) *output_len = out_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (int i = 0, j = 0; i < data_len;) {
 | 
					    for (int i = 0, j = 0; i < data_len;) {
 | 
				
			||||||
        unsigned int octet_a = (i < data_len) ? ((unsigned char *) data)[i++] : 0;
 | 
					        const unsigned int octet_a = (i < data_len) ? ((unsigned char *) data)[i++] : 0;
 | 
				
			||||||
        unsigned int octet_b = (i < data_len) ? ((unsigned char *) data)[i++] : 0;
 | 
					        const unsigned int octet_b = (i < data_len) ? ((unsigned char *) data)[i++] : 0;
 | 
				
			||||||
        unsigned int octet_c = (i < data_len) ? ((unsigned char *) data)[i++] : 0;
 | 
					        const 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 triple = (octet_a << 16) | (octet_b << 8) | octet_c;
 | 
				
			||||||
        output[j++] = base64_encode_table[(triple >> 3 * 6) & 0x3F];
 | 
					        output[j++] = base64_encode_table[(triple >> 3 * 6) & 0x3F];
 | 
				
			||||||
        output[j++] = base64_encode_table[(triple >> 2 * 6) & 0x3F];
 | 
					        output[j++] = base64_encode_table[(triple >> 2 * 6) & 0x3F];
 | 
				
			||||||
        output[j++] = base64_encode_table[(triple >> 1 * 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;
 | 
					    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) {
 | 
					long clock_micros(void) {
 | 
				
			||||||
    struct timespec time;
 | 
					    struct timespec time;
 | 
				
			||||||
    clock_gettime(CLOCK_MONOTONIC, &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_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_micros(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
long clock_cpu(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 client_ctx_t **clients;
 | 
				
			||||||
static sem_t sem_clients_lock;
 | 
					static sem_t sem_clients_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void terminate_gracefully(int sig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void clean(void) {
 | 
					static void clean(void) {
 | 
				
			||||||
    notice("Cleaning sesimos cache and metadata files...");
 | 
					    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));
 | 
					    client_ctx_t *client_ctx = malloc(sizeof(client_ctx_t));
 | 
				
			||||||
    if (client_ctx == NULL) {
 | 
					    if (client_ctx == NULL) {
 | 
				
			||||||
        critical("Unable to allocate memory for client context");
 | 
					        critical("Unable to allocate memory for client context");
 | 
				
			||||||
        errno = 0;
 | 
					        terminate_gracefully(0);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    sock *client = &client_ctx->socket;
 | 
					    sock *client = &client_ctx->socket;
 | 
				
			||||||
@@ -132,6 +134,7 @@ static void accept_cb(void *arg) {
 | 
				
			|||||||
    if (client_fd < 0) {
 | 
					    if (client_fd < 0) {
 | 
				
			||||||
        critical("Unable to accept connection");
 | 
					        critical("Unable to accept connection");
 | 
				
			||||||
        free(client_ctx);
 | 
					        free(client_ctx);
 | 
				
			||||||
 | 
					        terminate_gracefully(0);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -146,6 +149,7 @@ static void accept_cb(void *arg) {
 | 
				
			|||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            critical("Unable to lock clients list");
 | 
					            critical("Unable to lock clients list");
 | 
				
			||||||
 | 
					            terminate_gracefully(0);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -154,8 +158,9 @@ static void accept_cb(void *arg) {
 | 
				
			|||||||
    clients = list_append(clients, &client_ctx);
 | 
					    clients = list_append(clients, &client_ctx);
 | 
				
			||||||
    if (clients == NULL) {
 | 
					    if (clients == NULL) {
 | 
				
			||||||
        critical("Unable to add client context to list");
 | 
					        critical("Unable to add client context to list");
 | 
				
			||||||
 | 
					        sem_post(&sem_clients_lock);
 | 
				
			||||||
        free(client_ctx);
 | 
					        free(client_ctx);
 | 
				
			||||||
        errno = 0;
 | 
					        terminate_gracefully(0);
 | 
				
			||||||
        return;
 | 
					        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_options(ctx, SSL_OP_SINGLE_DH_USE);
 | 
				
			||||||
        SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
 | 
					        SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
 | 
				
			||||||
        SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
 | 
					        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_cipher_list(ctx, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4");
 | 
				
			||||||
        SSL_CTX_set_ecdh_auto(ctx, 1);
 | 
					        SSL_CTX_set_ecdh_auto(ctx, 1);
 | 
				
			||||||
        SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
 | 
					        SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,8 +14,11 @@
 | 
				
			|||||||
#define NUM_SOCKETS 2
 | 
					#define NUM_SOCKETS 2
 | 
				
			||||||
#define LISTEN_BACKLOG 16
 | 
					#define LISTEN_BACKLOG 16
 | 
				
			||||||
#define REQ_PER_CONNECTION 200
 | 
					#define REQ_PER_CONNECTION 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SOCKET_TIMEOUT 1
 | 
				
			||||||
#define CLIENT_TIMEOUT 3600
 | 
					#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 SERVER_TIMEOUT 3600
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CNX_HANDLER_WORKERS 8
 | 
					#define CNX_HANDLER_WORKERS 8
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * sesimos - secure, simple, modern web server
 | 
					 * sesimos - secure, simple, modern web server
 | 
				
			||||||
 * @brief FastCGI frame handler
 | 
					 * @brief FastCGI frame handler
 | 
				
			||||||
 * @file src/worker/fcti_frame_handler.c
 | 
					 * @file src/worker/fcgi_frame_handler.c
 | 
				
			||||||
 * @author Lorenz Stechauner
 | 
					 * @author Lorenz Stechauner
 | 
				
			||||||
 * @date 2023-01-22
 | 
					 * @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);
 | 
					    logger_set_prefix("[%*s]%s", ADDRSTRLEN, ctx->client->socket.s_addr, ctx->client->log_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char buf[CHUNK_SIZE];
 | 
					    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) {
 | 
					    if (sent < 0) {
 | 
				
			||||||
        // error
 | 
					        // error
 | 
				
			||||||
        error("Unable to splice chunk");
 | 
					        error("Unable to splice chunk");
 | 
				
			||||||
@@ -28,6 +28,7 @@ void chunk_handler_func(chunk_ctx_t *ctx) {
 | 
				
			|||||||
        ctx->next_cb(ctx);
 | 
					        ctx->next_cb(ctx);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        // next chunk
 | 
					        // next chunk
 | 
				
			||||||
 | 
					        ctx->client->transferred_length += sent;
 | 
				
			||||||
        handle_chunk(ctx);
 | 
					        handle_chunk(ctx);
 | 
				
			||||||
        return;
 | 
					        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) {
 | 
					int fastcgi_handle_connection(client_ctx_t *ctx, fastcgi_cnx_t **cnx) {
 | 
				
			||||||
    sock_set_timeout(&(*cnx)->socket, FASTCGI_TIMEOUT);
 | 
					    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));
 | 
					    fastcgi_ctx_t *a = malloc(sizeof(fastcgi_ctx_t));
 | 
				
			||||||
    a->closed = 0;
 | 
					    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) {
 | 
					void fastcgi_close(fastcgi_ctx_t *ctx) {
 | 
				
			||||||
    if (ctx->closed == 0) {
 | 
					 | 
				
			||||||
    ctx->closed++;
 | 
					    ctx->closed++;
 | 
				
			||||||
 | 
					    if (ctx->closed != 2)
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logger_set_prefix("[%*s]%s", ADDRSTRLEN, ctx->client->socket.s_addr, ctx->client->log_prefix);
 | 
					    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);
 | 
					    free(ctx);
 | 
				
			||||||
    errno = 0;
 | 
					    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);
 | 
					        int ret = fastcgi_handler_1(ctx, &fcgi_cnx);
 | 
				
			||||||
        respond(ctx);
 | 
					        respond(ctx);
 | 
				
			||||||
        if (ret == 0) {
 | 
					        if (ret == 0) {
 | 
				
			||||||
            switch (fastcgi_handler_2(ctx, fcgi_cnx)) {
 | 
					            fastcgi_handler_2(ctx, fcgi_cnx);
 | 
				
			||||||
                case 1: return;
 | 
					            return;
 | 
				
			||||||
                case 2: break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if (ctx->fcgi_ctx != NULL) {
 | 
					        } else if (ctx->fcgi_ctx != NULL) {
 | 
				
			||||||
            fastcgi_close(ctx->fcgi_ctx);
 | 
					            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_addr = ctx->socket.addr;
 | 
				
			||||||
    fcgi_cnx_buf.r_host = (ctx->host[0] != 0) ? ctx->host : NULL;
 | 
					    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);
 | 
					    res->status = http_get_status(200);
 | 
				
			||||||
    if (fastcgi_init(&fcgi_cnx_buf, mode, ctx->req_num, client, req, uri) != 0) {
 | 
					    if (fastcgi_init(&fcgi_cnx_buf, mode, ctx->req_num, client, req, uri) != 0) {
 | 
				
			||||||
        fastcgi_close_cnx(&fcgi_cnx_buf);
 | 
					        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;
 | 
					    (*fcgi_cnx) = &fcgi_cnx_buf;
 | 
				
			||||||
    fastcgi_handle_connection(ctx, fcgi_cnx);
 | 
					    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_content_length = http_get_header_field(&req->hdr, "Content-Length");
 | 
				
			||||||
    const char *client_transfer_encoding = http_get_header_field(&req->hdr, "Transfer-Encoding");
 | 
					    const char *client_transfer_encoding = http_get_header_field(&req->hdr, "Transfer-Encoding");
 | 
				
			||||||
    if (client_content_length != NULL) {
 | 
					    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);
 | 
					        unsigned long client_content_len = strtoul(client_content_length, NULL, 10);
 | 
				
			||||||
        ret = fastcgi_receive(*fcgi_cnx, client, client_content_len);
 | 
					        ret = fastcgi_receive(*fcgi_cnx, client, client_content_len);
 | 
				
			||||||
    } else if (strcontains(client_transfer_encoding, "chunked")) {
 | 
					    } 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);
 | 
					        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 {
 | 
					    } else {
 | 
				
			||||||
        ret = 0;
 | 
					        ret = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -165,7 +179,7 @@ static void fastcgi_error_cb(chunk_ctx_t *ctx) {
 | 
				
			|||||||
    // FIXME segfault on error_cb
 | 
					    // FIXME segfault on error_cb
 | 
				
			||||||
    warning("Closing connection due to FastCGI error");
 | 
					    warning("Closing connection due to FastCGI error");
 | 
				
			||||||
    if(ctx->client->fcgi_ctx) {
 | 
					    if(ctx->client->fcgi_ctx) {
 | 
				
			||||||
        fastcgi_close(ctx->client->fcgi_ctx);
 | 
					        fastcgi_close_error(ctx->client->fcgi_ctx);
 | 
				
			||||||
        ctx->client->fcgi_ctx = NULL;
 | 
					        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) {
 | 
					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");
 | 
					    int chunked = strcontains(http_get_header_field(&ctx->res.hdr, "Transfer-Encoding"), "chunked");
 | 
				
			||||||
 | 
					    handle_chunks(ctx, &fcgi_cnx->out, chunked ? SOCK_CHUNKED : 0, fastcgi_next_cb, fastcgi_error_cb);
 | 
				
			||||||
    if (chunked) {
 | 
					 | 
				
			||||||
        handle_chunks(ctx, &fcgi_cnx->out, SOCK_CHUNKED, fastcgi_next_cb, fastcgi_error_cb);
 | 
					 | 
				
			||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        fastcgi_send(fcgi_cnx, &ctx->socket);
 | 
					 | 
				
			||||||
        fastcgi_close(ctx->fcgi_ctx);
 | 
					 | 
				
			||||||
        ctx->fcgi_ctx = NULL;
 | 
					 | 
				
			||||||
        fastcgi_handle(ctx);
 | 
					 | 
				
			||||||
        return 2;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ typedef struct {
 | 
				
			|||||||
    http_status custom_status;
 | 
					    http_status custom_status;
 | 
				
			||||||
    host_config_t *conf;
 | 
					    host_config_t *conf;
 | 
				
			||||||
    FILE *file;
 | 
					    FILE *file;
 | 
				
			||||||
    long content_length;
 | 
					    long content_length, transferred_length;
 | 
				
			||||||
    char *msg_buf, *msg_buf_ptr, msg_content[1024];
 | 
					    char *msg_buf, *msg_buf_ptr, msg_content[1024];
 | 
				
			||||||
    proxy_ctx_t *proxy;
 | 
					    proxy_ctx_t *proxy;
 | 
				
			||||||
    void *fcgi_ctx;
 | 
					    void *fcgi_ctx;
 | 
				
			||||||
@@ -46,7 +46,7 @@ typedef struct {
 | 
				
			|||||||
} ws_ctx_t;
 | 
					} ws_ctx_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    int closed:2;
 | 
					    unsigned char closed:4;
 | 
				
			||||||
    client_ctx_t *client;
 | 
					    client_ctx_t *client;
 | 
				
			||||||
    fastcgi_cnx_t cnx;
 | 
					    fastcgi_cnx_t cnx;
 | 
				
			||||||
} fastcgi_ctx_t;
 | 
					} 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(fastcgi_ctx_t *ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void fastcgi_close_error(fastcgi_ctx_t *ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif //SESIMOS_FUNC_H
 | 
					#endif //SESIMOS_FUNC_H
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -155,7 +155,16 @@ static int local_handler(client_ctx_t *ctx) {
 | 
				
			|||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (uri->is_static) {
 | 
					    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);
 | 
					    res->status = http_get_status(200);
 | 
				
			||||||
    cache_init_uri(ctx->conf->cache, uri);
 | 
					    cache_init_uri(ctx->conf->cache, uri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -199,28 +208,32 @@ static int local_handler(client_ctx_t *ctx) {
 | 
				
			|||||||
                enc = COMPRESS_GZ;
 | 
					                enc = COMPRESS_GZ;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            if (enc != 0) {
 | 
					    }
 | 
				
			||||||
 | 
					    if (uri->meta->filename_comp_br[0] != 0 || uri->meta->filename_comp_gz[0] != 0) {
 | 
				
			||||||
        http_add_header_field(&res->hdr, "Vary", "Accept-Encoding");
 | 
					        http_add_header_field(&res->hdr, "Vary", "Accept-Encoding");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buf1[0] = 0;
 | 
				
			||||||
    if (uri->meta->etag[0] != 0) {
 | 
					    if (uri->meta->etag[0] != 0) {
 | 
				
			||||||
            strcpy(buf1, uri->meta->etag);
 | 
					        buf1[0] = '"';
 | 
				
			||||||
 | 
					        strcpy(buf1 + 1, uri->meta->etag);
 | 
				
			||||||
        if (enc) {
 | 
					        if (enc) {
 | 
				
			||||||
            strcat(buf1, "-");
 | 
					            strcat(buf1, "-");
 | 
				
			||||||
            strcat(buf1, (enc & COMPRESS_BR) ? "br" : (enc & COMPRESS_GZ) ? "gzip" : "");
 | 
					            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, "ETag", buf1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        http_add_header_field(&res->hdr, "Cache-Control", mime_is_text(uri->meta->type) ? "public, max-age=3600" : "public, max-age=86400");
 | 
					    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_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");
 | 
					    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)) ||
 | 
					    if ((if_none_match != NULL && strcontains(if_none_match, buf1)) ||
 | 
				
			||||||
        (accept_if_modified_since && streq(if_modified_since, last_modified)))
 | 
					        (accept_if_modified_since && streq(if_modified_since, last_modified)))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        res->status = http_get_status(304);
 | 
					        res->status = http_get_status(304);
 | 
				
			||||||
 | 
					        ctx->content_length = 0;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -243,9 +256,6 @@ static int local_handler(client_ctx_t *ctx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (ctx->file == NULL) ctx->file = fopen(uri->filename, "rb");
 | 
					    if (ctx->file == NULL) ctx->file = fopen(uri->filename, "rb");
 | 
				
			||||||
    ctx->content_length = fsize(ctx->file);
 | 
					    ctx->content_length = fsize(ctx->file);
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        return 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    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_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_length_f = http_get_header_field(&res->hdr, "Content-Length");
 | 
				
			||||||
        const char *content_encoding = http_get_header_field(&res->hdr, "Content-Encoding");
 | 
					        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 ||
 | 
					                content_length_f == NULL ||
 | 
				
			||||||
                streq(content_length_f, "0") ||
 | 
					                streq(content_length_f, "0") ||
 | 
				
			||||||
                (content_length_f != NULL && strstarts(content_type, "text/html"))))
 | 
					                (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) {
 | 
					static int proxy_handler_2(client_ctx_t *ctx) {
 | 
				
			||||||
    const char *transfer_encoding = http_get_header_field(&ctx->res.hdr, "Transfer-Encoding");
 | 
					    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");
 | 
					    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) {
 | 
					    if (chunked) {
 | 
				
			||||||
        handle_chunks(ctx, &ctx->proxy->proxy, SOCK_CHUNKED, proxy_chunk_next_cb, proxy_chunk_err_cb);
 | 
					        handle_chunks(ctx, &ctx->proxy->proxy, SOCK_CHUNKED, proxy_chunk_next_cb, proxy_chunk_err_cb);
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int ret;
 | 
					    long ret;
 | 
				
			||||||
    if ((ret = proxy_send(ctx->proxy, &ctx->socket, len_to_send, 0)) == -1) {
 | 
					    if ((ret = proxy_send(ctx->proxy, &ctx->socket, len_to_send, 0)) == -1) {
 | 
				
			||||||
        ctx->c_keep_alive = 0;
 | 
					        ctx->c_keep_alive = 0;
 | 
				
			||||||
 | 
					    } else if (ret > 0) {
 | 
				
			||||||
 | 
					        ctx->transferred_length += ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,8 @@ static void init_ctx(client_ctx_t *ctx) {
 | 
				
			|||||||
    ctx->req_host[0] = 0;
 | 
					    ctx->req_host[0] = 0;
 | 
				
			||||||
    ctx->err_msg[0] = 0;
 | 
					    ctx->err_msg[0] = 0;
 | 
				
			||||||
    ctx->req_s = ctx->socket.ts_last;
 | 
					    ctx->req_s = ctx->socket.ts_last;
 | 
				
			||||||
 | 
					    ctx->transferred_length = 0;
 | 
				
			||||||
 | 
					    ctx->content_length = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memset(&ctx->uri, 0, sizeof(ctx->uri));
 | 
					    memset(&ctx->uri, 0, sizeof(ctx->uri));
 | 
				
			||||||
    memset(&ctx->req, 0, sizeof(ctx->req));
 | 
					    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) {
 | 
					        if (http_get_header_field(&res->hdr, "Accept-Ranges") == NULL) {
 | 
				
			||||||
            http_add_header_field(&res->hdr, "Accept-Ranges", "none");
 | 
					            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, "Date", HTTP_REMOVE_ALL);
 | 
				
			||||||
            http_remove_header_field(&res->hdr, "Server", HTTP_REMOVE_ALL);
 | 
					            http_remove_header_field(&res->hdr, "Server", HTTP_REMOVE_ALL);
 | 
				
			||||||
            http_remove_header_field(&res->hdr, "Cache-Control", 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) {
 | 
					void request_complete(client_ctx_t *ctx) {
 | 
				
			||||||
    char buf[32];
 | 
					    char buf[64];
 | 
				
			||||||
    ctx->req_e = clock_micros();
 | 
					    ctx->req_e = clock_micros();
 | 
				
			||||||
    info("Transfer complete: %s", format_duration(ctx->req_e - ctx->req_s, buf));
 | 
					    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);
 | 
					    if (ctx->file) fclose(ctx->file);
 | 
				
			||||||
    free(ctx->msg_buf_ptr);
 | 
					    free(ctx->msg_buf_ptr);
 | 
				
			||||||
    uri_free(&ctx->uri);
 | 
					    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->host[0] != 0 ? ctx->host : "", ctx->host[0] != 0 ? ") " : "",
 | 
				
			||||||
         ctx->cc[0] != 0 ? ctx->cc : "N/A");
 | 
					         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");
 | 
					        error("Unable to set timeout for socket");
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,11 +38,11 @@ int ws_handle_connection(client_ctx_t *ctx) {
 | 
				
			|||||||
    // copy proxy connection details
 | 
					    // copy proxy connection details
 | 
				
			||||||
    proxy_ctx_t *proxy = malloc(sizeof(proxy_ctx_t));
 | 
					    proxy_ctx_t *proxy = malloc(sizeof(proxy_ctx_t));
 | 
				
			||||||
    memcpy(proxy, ctx->proxy, sizeof(proxy_ctx_t));
 | 
					    memcpy(proxy, ctx->proxy, sizeof(proxy_ctx_t));
 | 
				
			||||||
    ctx->proxy = proxy;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // free proxy connection slot
 | 
					    // free proxy connection slot
 | 
				
			||||||
    ctx->proxy->initialized = 0;
 | 
					    ctx->proxy->initialized = 0;
 | 
				
			||||||
    proxy_unlock_ctx(ctx->proxy);
 | 
					    proxy_unlock_ctx(ctx->proxy);
 | 
				
			||||||
 | 
					    ctx->proxy = proxy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sock_set_timeout(&ctx->socket, WS_TIMEOUT);
 | 
					    sock_set_timeout(&ctx->socket, WS_TIMEOUT);
 | 
				
			||||||
    sock_set_timeout(&proxy->proxy, WS_TIMEOUT);
 | 
					    sock_set_timeout(&proxy->proxy, WS_TIMEOUT);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user