Compare commits
7 Commits
5f3cd03a6f
...
dev
Author | SHA1 | Date | |
---|---|---|---|
af62a3065a
|
|||
c36ad8c113
|
|||
7f7a07c4d2
|
|||
4ff22bd0c6
|
|||
83ca2467de
|
|||
0a1fb977d6
|
|||
1405036cf2
|
4
Makefile
4
Makefile
@@ -63,7 +63,7 @@ bin/sesimos: bin/server.o bin/logger.o bin/cache_handler.o bin/async.o bin/worke
|
||||
bin/lib/http_static.o bin/res/default.o bin/res/proxy.o bin/res/style.o \
|
||||
bin/res/icon_error.o bin/res/icon_info.o bin/res/icon_success.o bin/res/icon_warning.o \
|
||||
bin/res/globe.o \
|
||||
bin/lib/compress.o bin/lib/config.o bin/lib/fastcgi.o bin/lib/geoip.o \
|
||||
bin/lib/compress.o bin/lib/config.o bin/lib/fastcgi.o bin/lib/geoip.o bin/lib/error.o \
|
||||
bin/lib/http.o bin/lib/proxy.o bin/lib/sock.o bin/lib/uri.o \
|
||||
bin/lib/utils.o bin/lib/websocket.o bin/lib/mpmc.o bin/lib/list.o
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
|
||||
@@ -99,6 +99,8 @@ bin/lib/config.o: src/lib/config.h src/lib/utils.h src/lib/uri.h src/logger.h
|
||||
bin/lib/fastcgi.o: src/lib/fastcgi.h src/server.h src/lib/utils.h src/lib/compress.h src/lib/http.h \
|
||||
src/lib/uri.h src/lib/include/fastcgi.h src/logger.h
|
||||
|
||||
bin/lib/error.o: src/lib/error.h
|
||||
|
||||
bin/lib/geoip.o: src/lib/geoip.h
|
||||
|
||||
bin/lib/http.o: src/lib/http.h src/lib/utils.h src/lib/compress.h src/lib/sock.h src/logger.h
|
||||
|
49
src/async.c
49
src/async.c
@@ -9,6 +9,7 @@
|
||||
#include "async.h"
|
||||
#include "logger.h"
|
||||
#include "lib/list.h"
|
||||
#include "lib/utils.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/epoll.h>
|
||||
@@ -28,6 +29,7 @@ typedef struct {
|
||||
int flags;
|
||||
void *arg;
|
||||
void (*cb)(void *);
|
||||
void (*to_cb)(void *);
|
||||
void (*err_cb)(void *);
|
||||
} evt_listen_t;
|
||||
|
||||
@@ -154,7 +156,7 @@ static int async_add(evt_listen_t *evt) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int async_fd(int fd, async_evt_t events, int flags, void *arg, void cb(void *), void err_cb(void *)) {
|
||||
int async_fd(int fd, async_evt_t events, int flags, void *arg, void cb(void *), void to_cb(void *), void err_cb(void *)) {
|
||||
evt_listen_t evt = {
|
||||
.fd = fd,
|
||||
.socket = NULL,
|
||||
@@ -162,12 +164,13 @@ int async_fd(int fd, async_evt_t events, int flags, void *arg, void cb(void *),
|
||||
.flags = flags,
|
||||
.arg = arg,
|
||||
.cb = cb,
|
||||
.to_cb = to_cb,
|
||||
.err_cb = err_cb,
|
||||
};
|
||||
return async_add(&evt);
|
||||
}
|
||||
|
||||
int async(sock *s, async_evt_t events, int flags, void *arg, void cb(void *), void err_cb(void *)) {
|
||||
int async(sock *s, async_evt_t events, int flags, void *arg, void cb(void *), void to_cb(void *), void err_cb(void *)) {
|
||||
evt_listen_t evt = {
|
||||
.fd = s->socket,
|
||||
.socket = s,
|
||||
@@ -175,6 +178,7 @@ int async(sock *s, async_evt_t events, int flags, void *arg, void cb(void *), vo
|
||||
.flags = flags,
|
||||
.arg = arg,
|
||||
.cb = cb,
|
||||
.to_cb = to_cb,
|
||||
.err_cb = err_cb,
|
||||
};
|
||||
return async_add(&evt);
|
||||
@@ -206,6 +210,8 @@ void async_free(void) {
|
||||
void async_thread(void) {
|
||||
struct epoll_event ev, events[ASYNC_MAX_EVENTS];
|
||||
int num_fds;
|
||||
long ts, min_ts, cur_ts;
|
||||
listen_queue_t *l;
|
||||
evt_listen_t **local = list_create(sizeof(evt_listen_t *), 16);
|
||||
if (local == NULL) {
|
||||
critical("Unable to create async local list");
|
||||
@@ -217,7 +223,7 @@ void async_thread(void) {
|
||||
// main event loop
|
||||
while (alive) {
|
||||
// swap listen queue
|
||||
listen_queue_t *l = listen_q;
|
||||
l = listen_q;
|
||||
listen_q = (listen_q == &listen1) ? &listen2 : &listen1;
|
||||
|
||||
// fill local list and epoll instance with previously added queue entries
|
||||
@@ -240,7 +246,17 @@ void async_thread(void) {
|
||||
// reset size of queue
|
||||
l->n = 0;
|
||||
|
||||
if ((num_fds = epoll_wait(epoll_fd, events, ASYNC_MAX_EVENTS, -1)) == -1) {
|
||||
// calculate wait timeout
|
||||
min_ts = -1000, cur_ts = clock_micros();;
|
||||
for (int i = 0; i < list_size(local); i++) {
|
||||
evt_listen_t *evt = local[i];
|
||||
if (!evt->socket) continue;
|
||||
|
||||
ts = evt->socket->ts_last + evt->socket->timeout_us - cur_ts;
|
||||
if (min_ts == -1000 || ts < min_ts) min_ts = ts;
|
||||
}
|
||||
|
||||
if ((num_fds = epoll_wait(epoll_fd, events, ASYNC_MAX_EVENTS, (int) (min_ts / 1000))) == -1) {
|
||||
if (errno == EINTR) {
|
||||
// interrupt
|
||||
errno = 0;
|
||||
@@ -274,6 +290,31 @@ void async_thread(void) {
|
||||
free(evt);
|
||||
}
|
||||
}
|
||||
|
||||
// check, if some socket ran into a timeout
|
||||
cur_ts = clock_micros();
|
||||
for (int i = 0; i < list_size(local); i++) {
|
||||
evt_listen_t *evt = local[i];
|
||||
if (!evt->socket) continue;
|
||||
|
||||
if ((cur_ts - evt->socket->ts_last) >= evt->socket->timeout_us) {
|
||||
evt->to_cb(evt->arg);
|
||||
|
||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, evt->fd, NULL) == -1) {
|
||||
if (errno == EBADF) {
|
||||
// already closed fd, do not die
|
||||
errno = 0;
|
||||
} else {
|
||||
critical("Unable to remove file descriptor from epoll instance");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
local = list_remove(local, i--);
|
||||
}
|
||||
}
|
||||
logger_set_prefix("");
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
// cleanup
|
||||
|
@@ -24,9 +24,9 @@
|
||||
|
||||
typedef unsigned int async_evt_t;
|
||||
|
||||
int async(sock *s, async_evt_t events, int flags, void *arg, void cb(void *), void err_cb(void *));
|
||||
int async(sock *s, async_evt_t events, int flags, void *arg, void cb(void *), void to_cb(void *), void err_cb(void *));
|
||||
|
||||
int async_fd(int fd, async_evt_t events, int flags, void *arg, void cb(void *), void err_cb(void *));
|
||||
int async_fd(int fd, async_evt_t events, int flags, void *arg, void cb(void *), void to_cb(void *), void err_cb(void *));
|
||||
|
||||
int async_init(void);
|
||||
|
||||
|
134
src/lib/error.c
Normal file
134
src/lib/error.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* sesimos - secure, simple, modern web server
|
||||
* @brief Error interface
|
||||
* @file src/lib/error.c
|
||||
* @author Lorenz Stechauner
|
||||
* @date 2023-01-08
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
#include "http.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <maxminddb.h>
|
||||
|
||||
static const char *error_ssl_strerror(int err) {
|
||||
switch (err) {
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return "closed";
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return "want read";
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return "want write";
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
return "want connect";
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
return "want accept";
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
return "want x509 lookup";
|
||||
case SSL_ERROR_WANT_ASYNC:
|
||||
return "want async";
|
||||
case SSL_ERROR_WANT_ASYNC_JOB:
|
||||
return "want async job";
|
||||
case SSL_ERROR_WANT_CLIENT_HELLO_CB:
|
||||
return "want client hello callback";
|
||||
case SSL_ERROR_WANT_RETRY_VERIFY:
|
||||
return "want retry verify";
|
||||
case SSL_ERROR_SSL:
|
||||
return ERR_reason_error_string(ERR_get_error());
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *error_http_strerror(int err) {
|
||||
switch (err) {
|
||||
case HTTP_ERROR_TOO_MANY_HEADER_FIELDS:
|
||||
return "too many header fields";
|
||||
case HTTP_ERROR_EOH_NOT_FOUND:
|
||||
return "end of http header not found";
|
||||
case HTTP_ERROR_HEADER_MALFORMED:
|
||||
return "http header malformed";
|
||||
case HTTP_ERROR_INVALID_VERSION:
|
||||
return "invalid http version";
|
||||
case HTTP_ERROR_URI_TOO_LONG:
|
||||
return "uri too long";
|
||||
case HTTP_ERROR_GENERAL:
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
const char *error_str(int err_no, char *buf, int buf_len) {
|
||||
buf[0] = 0;
|
||||
unsigned char mode = (unsigned char) (err_no >> 24);
|
||||
int e = err_no & 0x00FFFFFF;
|
||||
if (mode == 0x00) {
|
||||
// normal
|
||||
strerror_r(e, buf, buf_len);
|
||||
return buf;
|
||||
} else if (mode == 0x01) {
|
||||
// ssl
|
||||
return error_ssl_strerror(e);
|
||||
} else if (mode == 0x02) {
|
||||
// mmdb
|
||||
return MMDB_strerror(e);
|
||||
} else if (mode == 0x03) {
|
||||
// http
|
||||
return error_http_strerror(e);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void error_ssl(int err) {
|
||||
if (err == SSL_ERROR_NONE) {
|
||||
errno = 0;
|
||||
} else if (err == SSL_ERROR_SYSCALL) {
|
||||
// errno already set
|
||||
} else {
|
||||
errno = 0x01000000 | err;
|
||||
}
|
||||
}
|
||||
|
||||
void error_mmdb(int err) {
|
||||
if (err == MMDB_SUCCESS) {
|
||||
errno = 0;
|
||||
} else if (err == MMDB_IO_ERROR) {
|
||||
// errno already set
|
||||
} else {
|
||||
errno = 0x02000000 | err;
|
||||
}
|
||||
}
|
||||
|
||||
int error_http(int err) {
|
||||
if (err == 0) {
|
||||
errno = 0;
|
||||
} else if (err == HTTP_ERROR_SYSCALL) {
|
||||
// errno already set
|
||||
} else {
|
||||
errno = 0x03000000 | err;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int error_get(unsigned char prefix) {
|
||||
return (errno >> 24 != prefix) ? 0 : errno & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
int error_get_sys() {
|
||||
return error_get(0x00);
|
||||
}
|
||||
|
||||
int error_get_ssl() {
|
||||
return error_get(0x01);
|
||||
}
|
||||
|
||||
int error_get_mmdb() {
|
||||
return error_get(0x02);
|
||||
}
|
||||
|
||||
int error_get_http() {
|
||||
return error_get(0x03);
|
||||
}
|
28
src/lib/error.h
Normal file
28
src/lib/error.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* sesimos - secure, simple, modern web server
|
||||
* @brief Error interface (header fie)
|
||||
* @file src/lib/error.h
|
||||
* @author Lorenz Stechauner
|
||||
* @date 2023-01-08
|
||||
*/
|
||||
|
||||
#ifndef SESIMOS_ERROR_H
|
||||
#define SESIMOS_ERROR_H
|
||||
|
||||
const char *error_str(int err_no, char *buf, int buf_len);
|
||||
|
||||
void error_ssl(int err);
|
||||
|
||||
void error_mmdb(int err);
|
||||
|
||||
int error_http(int err);
|
||||
|
||||
int error_get_sys();
|
||||
|
||||
int error_get_ssl();
|
||||
|
||||
int error_get_mmdb();
|
||||
|
||||
int error_get_http();
|
||||
|
||||
#endif //SESIMOS_ERROR_H
|
@@ -383,6 +383,7 @@ int fastcgi_header(fastcgi_cnx_t *conn, http_res *res, char *err_msg) {
|
||||
|
||||
ret = http_parse_header_field(&res->hdr, ptr, pos0, 0);
|
||||
if (ret != 0) return (int) ret;
|
||||
|
||||
if (pos0[2] == '\r' && pos0[3] == '\n') {
|
||||
return 0;
|
||||
}
|
||||
@@ -593,7 +594,7 @@ int fastcgi_receive(fastcgi_cnx_t *conn, sock *client, unsigned long len) {
|
||||
while (rcv_len < len) {
|
||||
ret = sock_recv(client, buf, sizeof(buf), 0);
|
||||
if (ret <= 0) {
|
||||
error("Unable to receive: %s", sock_strerror(client));
|
||||
error("Unable to receive");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "geoip.h"
|
||||
#include "../logger.h"
|
||||
#include "error.h"
|
||||
#include <memory.h>
|
||||
#include <dirent.h>
|
||||
|
||||
@@ -101,7 +102,8 @@ int geoip_init(const char *directory) {
|
||||
|
||||
sprintf(buf, "%s/%s", directory, entry->d_name);
|
||||
if ((status = MMDB_open(buf, 0, &mmdbs[i])) != MMDB_SUCCESS) {
|
||||
critical("Unable to initialize geoip: Unable to open .mmdb file: %s", MMDB_strerror(status));
|
||||
error_mmdb(status);
|
||||
critical("Unable to initialize geoip: Unable to open .mmdb file");
|
||||
closedir(geoip_dir);
|
||||
return 1;
|
||||
}
|
||||
@@ -164,7 +166,8 @@ int geoip_lookup_json(struct sockaddr *addr, char *json, long len) {
|
||||
int mmdb_res;
|
||||
MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&mmdbs[i], addr, &mmdb_res);
|
||||
if (mmdb_res != MMDB_SUCCESS) {
|
||||
error("Unable to lookup geoip info: %s", MMDB_strerror(mmdb_res));
|
||||
error_mmdb(mmdb_res);
|
||||
error("Unable to lookup geoip info");
|
||||
continue;
|
||||
} else if (!result.found_entry) {
|
||||
continue;
|
||||
@@ -172,7 +175,8 @@ int geoip_lookup_json(struct sockaddr *addr, char *json, long len) {
|
||||
|
||||
MMDB_entry_data_list_s *list;
|
||||
if ((mmdb_res = MMDB_get_entry_data_list(&result.entry, &list)) != MMDB_SUCCESS) {
|
||||
error("Unable to lookup geoip info: %s", MMDB_strerror(mmdb_res));
|
||||
error_mmdb(mmdb_res);
|
||||
error("Unable to lookup geoip info");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -6,11 +6,11 @@
|
||||
* @date 2020-12-09
|
||||
*/
|
||||
|
||||
#include "../logger.h"
|
||||
#include "http.h"
|
||||
#include "utils.h"
|
||||
#include "compress.h"
|
||||
#include "list.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -90,23 +90,20 @@ void http_free_res(http_res *res) {
|
||||
int http_init_hdr(http_hdr *hdr) {
|
||||
hdr->fields = list_create(sizeof(http_field), HTTP_INIT_HEADER_FIELD_NUM);
|
||||
if (hdr->fields == NULL)
|
||||
return -1;
|
||||
return error_http(HTTP_ERROR_SYSCALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr, int flags) {
|
||||
if (hdr->last_field_num > list_size(hdr->fields)) {
|
||||
error("Unable to parse header: Invalid state");
|
||||
return 3;
|
||||
}
|
||||
if (hdr->last_field_num > list_size(hdr->fields))
|
||||
return error_http(HTTP_ERROR_GENERAL);
|
||||
|
||||
char *pos1 = (char *) buf, *pos2 = (char *) end_ptr;
|
||||
if (buf[0] == ' ' || buf[0] == '\t') {
|
||||
if (hdr->last_field_num == -1) {
|
||||
error("Unable to parse header");
|
||||
return 3;
|
||||
}
|
||||
if (hdr->last_field_num == -1)
|
||||
return error_http(HTTP_ERROR_GENERAL);
|
||||
|
||||
http_field *f = &hdr->fields[(int) hdr->last_field_num];
|
||||
|
||||
str_trim_lws(&pos1, &pos2);
|
||||
@@ -116,10 +113,9 @@ int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr,
|
||||
}
|
||||
|
||||
pos1 = memchr(buf, ':', end_ptr - buf);
|
||||
if (pos1 == NULL) {
|
||||
error("Unable to parse header");
|
||||
return 3;
|
||||
}
|
||||
if (pos1 == NULL)
|
||||
return error_http(HTTP_ERROR_GENERAL);
|
||||
|
||||
long len1 = pos1 - buf;
|
||||
|
||||
pos1++;
|
||||
@@ -129,10 +125,8 @@ int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr,
|
||||
int field_num = list_size(hdr->fields);
|
||||
int found = http_get_header_field_num_len(hdr, buf, len1);
|
||||
if (!(flags & HTTP_MERGE_FIELDS) || found == -1) {
|
||||
if (http_add_header_field_len(hdr, buf, len1, pos1, len2 < 0 ? 0 : len2) != 0) {
|
||||
error("Unable to parse header: Too many header fields");
|
||||
return 3;
|
||||
}
|
||||
if (http_add_header_field_len(hdr, buf, len1, pos1, len2 < 0 ? 0 : len2) != 0)
|
||||
return error_http(HTTP_ERROR_TOO_MANY_HEADER_FIELDS);
|
||||
} else {
|
||||
field_num = found;
|
||||
http_append_to_header_field(&hdr->fields[found], ", ", 2);
|
||||
@@ -148,62 +142,52 @@ int http_parse_request(char *buf, http_req *req) {
|
||||
long len;
|
||||
|
||||
unsigned long header_len = strstr(buf, "\r\n\r\n") - buf + 4;
|
||||
if (header_len <= 0) {
|
||||
error("Unable to parse http header: End of header not found");
|
||||
return -5;
|
||||
}
|
||||
if (header_len <= 0)
|
||||
return error_http(HTTP_ERROR_EOH_NOT_FOUND);
|
||||
|
||||
for (int i = 0; i < header_len; i++) {
|
||||
if ((buf[i] >= 0x00 && buf[i] <= 0x1F && buf[i] != '\r' && buf[i] != '\n') || buf[i] == 0x7F) {
|
||||
error("Unable to parse http header: Header contains illegal characters");
|
||||
return -4;
|
||||
}
|
||||
if ((buf[i] >= 0x00 && buf[i] <= 0x1F && buf[i] != '\r' && buf[i] != '\n') || buf[i] == 0x7F)
|
||||
return error_http(HTTP_ERROR_HEADER_MALFORMED);
|
||||
}
|
||||
|
||||
ptr = buf;
|
||||
while (header_len > (ptr - buf + 2)) {
|
||||
pos0 = strstr(ptr, "\r\n");
|
||||
if (pos0 == NULL) {
|
||||
error("Unable to parse http header: Invalid header format");
|
||||
return -1;
|
||||
}
|
||||
if (pos0 == NULL)
|
||||
return error_http(HTTP_ERROR_HEADER_MALFORMED);
|
||||
|
||||
if (req->version[0] == 0) {
|
||||
pos1 = (char *) strchr(ptr, ' ') + 1;
|
||||
if (pos1 == NULL) goto err_hdr_fmt;
|
||||
|
||||
if (pos1 - ptr - 1 >= sizeof(req->method)) {
|
||||
error("Unable to parse http header: Method name too long");
|
||||
return -2;
|
||||
}
|
||||
if (pos1 - ptr - 1 >= sizeof(req->method))
|
||||
return error_http(HTTP_ERROR_HEADER_MALFORMED);
|
||||
|
||||
for (int i = 0; i < (pos1 - ptr - 1); i++) {
|
||||
if (ptr[i] < 'A' || ptr[i] > 'Z') {
|
||||
error("Unable to parse http header: Invalid method");
|
||||
return -2;
|
||||
}
|
||||
if (ptr[i] < 'A' || ptr[i] > 'Z')
|
||||
return error_http(HTTP_ERROR_HEADER_MALFORMED);
|
||||
}
|
||||
snprintf(req->method, sizeof(req->method), "%.*s", (int) (pos1 - ptr - 1), ptr);
|
||||
|
||||
pos2 = (char *) strchr(pos1, ' ') + 1;
|
||||
if (pos2 == NULL) {
|
||||
err_hdr_fmt:
|
||||
error("Unable to parse http header: Invalid header format");
|
||||
return -1;
|
||||
return error_http(HTTP_ERROR_HEADER_MALFORMED);
|
||||
}
|
||||
|
||||
if (memcmp(pos2, "HTTP/", 5) != 0 || memcmp(pos2 + 8, "\r\n", 2) != 0) {
|
||||
error("Unable to parse http header: Invalid version");
|
||||
return -3;
|
||||
}
|
||||
if (memcmp(pos2, "HTTP/", 5) != 0 || memcmp(pos2 + 8, "\r\n", 2) != 0)
|
||||
return error_http(HTTP_ERROR_INVALID_VERSION);
|
||||
|
||||
len = pos2 - pos1 - 1;
|
||||
if (len >= 2048)
|
||||
return error_http(HTTP_ERROR_URI_TOO_LONG);
|
||||
|
||||
req->uri = malloc(len + 1);
|
||||
sprintf(req->uri, "%.*s", (int) len, pos1);
|
||||
sprintf(req->version, "%.3s", pos2 + 5);
|
||||
} else {
|
||||
int ret = http_parse_header_field(&req->hdr, ptr, pos0, HTTP_MERGE_FIELDS);
|
||||
if (ret != 0) return -ret;
|
||||
if (http_parse_header_field(&req->hdr, ptr, pos0, HTTP_MERGE_FIELDS) != 0)
|
||||
return -1;
|
||||
}
|
||||
ptr = pos0 + 2;
|
||||
}
|
||||
@@ -212,7 +196,7 @@ int http_parse_request(char *buf, http_req *req) {
|
||||
return (int) header_len;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return error_http(HTTP_ERROR_GENERAL);
|
||||
}
|
||||
|
||||
int http_receive_request(sock *client, http_req *req) {
|
||||
@@ -226,10 +210,9 @@ int http_receive_request(sock *client, http_req *req) {
|
||||
http_init_hdr(&req->hdr);
|
||||
|
||||
rcv_len = sock_recv(client, buf, CLIENT_MAX_HEADER_SIZE - 1, MSG_PEEK);
|
||||
if (rcv_len <= 0) {
|
||||
error("Unable to receive http header: %s", sock_strerror(client));
|
||||
if (rcv_len <= 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[rcv_len] = 0;
|
||||
|
||||
long header_len = http_parse_request(buf, req);
|
||||
@@ -351,9 +334,9 @@ int http_send_response(sock *client, http_res *res) {
|
||||
off += sprintf(buf + off, "%s: %s\r\n", http_field_get_name(f), http_field_get_value(f));
|
||||
}
|
||||
off += sprintf(buf + off, "\r\n");
|
||||
if (sock_send(client, buf, off, 0) < 0) {
|
||||
if (sock_send(client, buf, off, 0) != off)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -365,10 +348,9 @@ int http_send_request(sock *server, http_req *req) {
|
||||
off += sprintf(buf + off, "%s: %s\r\n", http_field_get_name(f), http_field_get_value(f));
|
||||
}
|
||||
off += sprintf(buf + off, "\r\n");
|
||||
long ret = sock_send(server, buf, off, 0);
|
||||
if (ret <= 0) {
|
||||
if (sock_send(server, buf, off, 0) != off)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -45,6 +45,15 @@
|
||||
#define HTTP_TYPE_CLIENT_ERROR 4
|
||||
#define HTTP_TYPE_SERVER_ERROR 5
|
||||
|
||||
#define HTTP_ERROR_GENERAL 1
|
||||
#define HTTP_ERROR_SYSCALL 2
|
||||
#define HTTP_ERROR_TOO_MANY_HEADER_FIELDS 3
|
||||
#define HTTP_ERROR_EOH_NOT_FOUND 4
|
||||
#define HTTP_ERROR_HEADER_MALFORMED 5
|
||||
#define HTTP_ERROR_INVALID_VERSION 6
|
||||
#define HTTP_ERROR_URI_TOO_LONG 7
|
||||
#define HTTP_ERROR_
|
||||
|
||||
#ifndef SERVER_STR
|
||||
# define SERVER_STR "sesimos"
|
||||
#endif
|
||||
|
@@ -24,7 +24,7 @@ const http_status http_statuses[] = {
|
||||
{206, HTTP_TYPE_SUCCESS, "Partial Content"},
|
||||
{207, HTTP_TYPE_SUCCESS, "Multi-Status"},
|
||||
{208, HTTP_TYPE_SUCCESS, "Already Reported"},
|
||||
{226, HTTP_TYPE_SUCCESS, "IM Used"},
|
||||
{226, HTTP_TYPE_SUCCESS, "Instance Manipulation Used"},
|
||||
|
||||
{300, HTTP_TYPE_REDIRECTION, "Multiple Choices"},
|
||||
{301, HTTP_TYPE_REDIRECTION, "Moved Permanently"},
|
||||
@@ -76,7 +76,6 @@ const http_status http_statuses[] = {
|
||||
{511, HTTP_TYPE_SERVER_ERROR, "Network Authentication Required"},
|
||||
};
|
||||
|
||||
// TODO add remaining descriptions
|
||||
const http_status_msg http_status_messages[] = {
|
||||
{100, "The client SHOULD continue with its request. The server MUST send a final response after the request "
|
||||
"has been completed."},
|
||||
@@ -146,15 +145,21 @@ const http_status_msg http_status_messages[] = {
|
||||
"next-hop server."},
|
||||
{421, "The server is not able to produce a response. The client MAY retry the request over a different "
|
||||
"connection."},
|
||||
{422, ""},
|
||||
{423, ""},
|
||||
{424, ""},
|
||||
{425, ""},
|
||||
{426, ""},
|
||||
{428, ""},
|
||||
{429, ""},
|
||||
{431, ""},
|
||||
{451, ""},
|
||||
{422, "The server understands the content type of the request content, and the syntax of the request content "
|
||||
"is correct, but the server was unable to process the contained information."},
|
||||
{423, "The source or destination resource of a method is locked."},
|
||||
{424, "The method could not be performed on the resource because the requested action depended on another "
|
||||
"action and that action failed."},
|
||||
{425, "The server is unwilling to risk processing a request that might be replayed."},
|
||||
{426, "The server refuses to perform the request using the current protocol but might be willing to do so "
|
||||
"after the client upgrades to a different protocol. The server MUST send an Upgrade header field to"
|
||||
"indicate the required protocol(s)."},
|
||||
{428, "The origin server requires the request to be conditional. By requiring requests to be conditional, the "
|
||||
"server can assure that clients are working with the correct copies and thus avoiding a lost update."},
|
||||
{429, "The client has sent too many requests in a given amount of time."},
|
||||
{431, "The server is unwilling to process the request because its header fields are too large. The request MAY "
|
||||
"be resubmitted after reducing the size of the request header fields."},
|
||||
{451, "The server is denying access to the resource as a consequence of a legal demand."},
|
||||
|
||||
{500, "The server encountered an unexpected condition which prevented it from fulfilling the request."},
|
||||
{501, "The server does not support the functionality required to fulfill the request."},
|
||||
@@ -167,10 +172,16 @@ const http_status_msg http_status_messages[] = {
|
||||
"complete the request."},
|
||||
{505, "The server does not support, or refuses to support, the HTTP protocol version that was used in the "
|
||||
"request message."},
|
||||
{506, ""},
|
||||
{507, ""},
|
||||
{508, ""},
|
||||
{511, ""},
|
||||
{506, "The server has an internal configuration error: the chosen variant resource is configured to engage in "
|
||||
"transparent content negotiation itself, and is therefore not a proper end point in the negotiation "
|
||||
"process."},
|
||||
{507, "The method could not be performed on the resource because the server is unable to store the "
|
||||
"representation needed to successfully complete the request. This condition is considered to be "
|
||||
"temporary."},
|
||||
{508, "The server terminated an operation because it encountered an infinite loop while processing the "
|
||||
"request."},
|
||||
{511, "The client needs to authenticate to gain network access. The response representation SHOULD contain a "
|
||||
"link to a resource that allows the user to submit credentials."},
|
||||
};
|
||||
|
||||
const int http_statuses_size = sizeof(http_statuses) / sizeof(http_status);
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "utils.h"
|
||||
#include "compress.h"
|
||||
#include "config.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <string.h>
|
||||
@@ -293,7 +294,7 @@ int proxy_response_header(http_req *req, http_res *res, host_config_t *conf) {
|
||||
}
|
||||
|
||||
int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_status_ctx *ctx, host_config_t *conf, sock *client, http_status *custom_status, char *err_msg) {
|
||||
char buffer[CHUNK_SIZE];
|
||||
char buffer[CHUNK_SIZE], err_buf[256];
|
||||
const char *connection, *upgrade, *ws_version;
|
||||
long ret;
|
||||
int tries = 0, retry = 0;
|
||||
@@ -329,7 +330,7 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
|
||||
if (host_ent == NULL) {
|
||||
host_ent = gethostbyname2(conf->proxy.hostname, AF_INET);
|
||||
if (host_ent == NULL) {
|
||||
res->status = http_get_status(504);
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_REQ;
|
||||
error("Unable to connect to server: Name or service not known");
|
||||
sprintf(err_msg, "Unable to connect to server: Name or service not known.");
|
||||
@@ -354,14 +355,14 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
|
||||
res->status = http_get_status(504);
|
||||
ctx->origin = SERVER_REQ;
|
||||
} else if (errno == ECONNREFUSED) {
|
||||
res->status = http_get_status(504);
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_REQ;
|
||||
} else {
|
||||
res->status = http_get_status(500);
|
||||
ctx->origin = INTERNAL;
|
||||
}
|
||||
error("Unable to connect to [%s]:%i: %s", buffer, conf->proxy.port, strerror(errno));
|
||||
sprintf(err_msg, "Unable to connect to server: %s.", strerror(errno));
|
||||
error("Unable to connect to [%s]:%i", buffer, conf->proxy.port);
|
||||
sprintf(err_msg, "Unable to connect to server: %s.", error_str(errno, err_buf, sizeof(err_buf)));
|
||||
goto proxy_err;
|
||||
}
|
||||
|
||||
@@ -370,7 +371,7 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
|
||||
res->status = http_get_status(500);
|
||||
ctx->origin = INTERNAL;
|
||||
error("Unable to set timeout for reverse proxy socket");
|
||||
sprintf(err_msg, "Unable to set timeout for reverse proxy socket: %s", strerror(errno));
|
||||
sprintf(err_msg, "Unable to set timeout for reverse proxy socket: %s", error_str(errno, err_buf, sizeof(err_buf)));
|
||||
goto proxy_err;
|
||||
}
|
||||
|
||||
@@ -380,17 +381,15 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
|
||||
SSL_set_connect_state(proxy->proxy.ssl);
|
||||
|
||||
ret = SSL_do_handshake(proxy->proxy.ssl);
|
||||
proxy->proxy._last_ret = ret;
|
||||
proxy->proxy._errno = errno;
|
||||
proxy->proxy._ssl_error = ERR_get_error();
|
||||
proxy->proxy.enc = 1;
|
||||
if (ret < 0) {
|
||||
if (ret != 1) {
|
||||
error_ssl(SSL_get_error(proxy->proxy.ssl, (int) ret));
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_REQ;
|
||||
error("Unable to perform handshake: %s", sock_strerror(&proxy->proxy));
|
||||
sprintf(err_msg, "Unable to perform handshake: %s.", sock_strerror(&proxy->proxy));
|
||||
error("Unable to perform handshake");
|
||||
sprintf(err_msg, "Unable to perform handshake: %s.", error_str(errno, err_buf, sizeof(err_buf)));
|
||||
goto proxy_err;
|
||||
}
|
||||
proxy->proxy.enc = 1;
|
||||
}
|
||||
|
||||
proxy->initialized = 1;
|
||||
@@ -425,8 +424,8 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
|
||||
if (ret < 0) {
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_REQ;
|
||||
error("Unable to send request to server (1): %s", sock_strerror(&proxy->proxy));
|
||||
sprintf(err_msg, "Unable to send request to server: %s.", sock_strerror(&proxy->proxy));
|
||||
error("Unable to send request to server (1)");
|
||||
sprintf(err_msg, "Unable to send request to server: %s.", error_str(errno, err_buf, sizeof(err_buf)));
|
||||
retry = tries < 4;
|
||||
goto proxy_err;
|
||||
}
|
||||
@@ -446,15 +445,15 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
|
||||
if (ret == -1) {
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_REQ;
|
||||
error("Unable to send request to server (2): %s", sock_strerror(&proxy->proxy));
|
||||
sprintf(err_msg, "Unable to send request to server: %s.", sock_strerror(&proxy->proxy));
|
||||
error("Unable to send request to server (2)");
|
||||
sprintf(err_msg, "Unable to send request to server: %s.", error_str(errno, err_buf, sizeof(err_buf)));
|
||||
retry = tries < 4;
|
||||
goto proxy_err;
|
||||
} else if (ret == -2) {
|
||||
res->status = http_get_status(400);
|
||||
ctx->origin = CLIENT_REQ;
|
||||
error("Unable to receive request from client: %s", sock_strerror(client));
|
||||
sprintf(err_msg, "Unable to receive request from client: %s.", sock_strerror(client));
|
||||
error("Unable to receive request from client");
|
||||
sprintf(err_msg, "Unable to receive request from client: %s.", error_str(errno, err_buf, sizeof(err_buf)));
|
||||
return -1;
|
||||
}
|
||||
res->status = http_get_status(500);
|
||||
@@ -465,18 +464,16 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
|
||||
|
||||
ret = sock_recv(&proxy->proxy, buffer, sizeof(buffer), MSG_PEEK);
|
||||
if (ret <= 0) {
|
||||
int enc_err = sock_enc_error(&proxy->proxy);
|
||||
if (errno == EAGAIN || errno == EINPROGRESS || enc_err == SSL_ERROR_WANT_READ ||
|
||||
enc_err == SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
int e_sys = error_get_sys(), e_ssl = error_get_ssl();
|
||||
if (e_sys == EAGAIN || e_sys == EINPROGRESS || e_ssl == SSL_ERROR_WANT_READ || e_ssl == SSL_ERROR_WANT_WRITE) {
|
||||
res->status = http_get_status(504);
|
||||
ctx->origin = SERVER_RES;
|
||||
} else {
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_RES;
|
||||
}
|
||||
error("Unable to receive response from server: %s", sock_strerror(&proxy->proxy));
|
||||
sprintf(err_msg, "Unable to receive response from server: %s.", sock_strerror(&proxy->proxy));
|
||||
error("Unable to receive response from server");
|
||||
sprintf(err_msg, "Unable to receive response from server: %s.", error_str(errno, err_buf, sizeof(err_buf)));
|
||||
retry = tries < 4;
|
||||
goto proxy_err;
|
||||
}
|
||||
@@ -536,8 +533,7 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu
|
||||
goto proxy_err;
|
||||
}
|
||||
} else {
|
||||
ret = http_parse_header_field(&res->hdr, ptr, pos0, 0);
|
||||
if (ret != 0) {
|
||||
if (http_parse_header_field(&res->hdr, ptr, pos0, 0) != 0) {
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_RES;
|
||||
error("Unable to parse header");
|
||||
@@ -595,7 +591,7 @@ int proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int
|
||||
if (ret == -1) {
|
||||
error("Unable to receive from server: Malformed chunk header");
|
||||
} else {
|
||||
error("Unable to receive from server: %s", sock_strerror(&proxy->proxy));
|
||||
error("Unable to receive from server");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -615,7 +611,7 @@ int proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int
|
||||
unsigned long avail_in, avail_out;
|
||||
ret = sock_recv(&proxy->proxy, buffer, CHUNK_SIZE < (len_to_send - snd_len) ? CHUNK_SIZE : len_to_send - snd_len, 0);
|
||||
if (ret <= 0) {
|
||||
error("Unable to receive from server: %s", sock_strerror(&proxy->proxy));
|
||||
error("Unable to receive from server");
|
||||
break;
|
||||
}
|
||||
len = ret;
|
||||
@@ -646,7 +642,7 @@ int proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int
|
||||
if (flags & PROXY_CHUNKED) ret = sock_send(client, "\r\n", 2, 0);
|
||||
if (ret <= 0) {
|
||||
err:
|
||||
error("Unable to send: %s", sock_strerror(client));
|
||||
error("Unable to send");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -663,7 +659,7 @@ int proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int
|
||||
if (flags & PROXY_CHUNKED) {
|
||||
ret = sock_send(client, "0\r\n\r\n", 5, 0);
|
||||
if (ret <= 0) {
|
||||
error("Unable to send: %s", sock_strerror(client));
|
||||
error("Unable to send");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@@ -8,58 +8,15 @@
|
||||
|
||||
#include "sock.h"
|
||||
#include "utils.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
int sock_enc_error(sock *s) {
|
||||
return (int) s->enc ? SSL_get_error(s->ssl, (int) s->_last_ret) : 0;
|
||||
}
|
||||
|
||||
const char *sock_strerror(sock *s) {
|
||||
// FIXME sock_strerror not Thread Safe!
|
||||
// (and ugly)
|
||||
errno = 0;
|
||||
if (s->_last_ret == 0) {
|
||||
return "closed";
|
||||
} else if (s->enc) {
|
||||
if (s->_last_ret > 0) {
|
||||
return NULL;
|
||||
}
|
||||
const char *err1 = ERR_reason_error_string(s->_ssl_error);
|
||||
const char *err2 = strerror(s->_errno);
|
||||
switch (sock_enc_error(s)) {
|
||||
case SSL_ERROR_NONE:
|
||||
return NULL;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return "closed";
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return "want read";
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return "want write";
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
return "want connect";
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
return "want accept";
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
return "want x509 lookup";
|
||||
case SSL_ERROR_SYSCALL:
|
||||
return ((s->_ssl_error == 0) ? ((s->_last_ret == 0) ? "protocol violation" : err2) : err1);
|
||||
case SSL_ERROR_SSL:
|
||||
return err1;
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
} else {
|
||||
return strerror(s->_errno);
|
||||
}
|
||||
}
|
||||
|
||||
int sock_set_timeout_micros(sock *s, long recv_micros, long send_micros) {
|
||||
int sock_set_socket_timeout_micros(sock *s, long recv_micros, long send_micros) {
|
||||
struct timeval recv_to = {.tv_sec = recv_micros / 1000000, .tv_usec = recv_micros % 1000000},
|
||||
send_to = {.tv_sec = send_micros / 1000000, .tv_usec = send_micros % 1000000};
|
||||
|
||||
@@ -72,21 +29,37 @@ int sock_set_timeout_micros(sock *s, long recv_micros, long send_micros) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sock_set_timeout(sock *s, int sec) {
|
||||
return sock_set_timeout_micros(s, sec * 1000000L, sec * 1000000L);
|
||||
int sock_set_socket_timeout(sock *s, double sec) {
|
||||
return sock_set_socket_timeout_micros(s, (long) (sec * 1000000L), (long) (sec * 1000000L));
|
||||
}
|
||||
|
||||
int sock_set_timeout_micros(sock *s, long micros) {
|
||||
if (micros < 0)
|
||||
return -1;
|
||||
|
||||
s->timeout_us = micros;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sock_set_timeout(sock *s, double sec) {
|
||||
return sock_set_timeout_micros(s, (long) (sec * 1000000));
|
||||
}
|
||||
|
||||
long sock_send(sock *s, void *buf, unsigned long len, int flags) {
|
||||
long ret;
|
||||
if (s->enc) {
|
||||
ret = SSL_write(s->ssl, buf, (int) len);
|
||||
s->_ssl_error = ERR_get_error();
|
||||
if (ret <= 0) error_ssl(SSL_get_error(s->ssl, (int) ret));
|
||||
} else {
|
||||
ret = send(s->socket, buf, len, flags);
|
||||
}
|
||||
s->_last_ret = ret;
|
||||
s->_errno = errno;
|
||||
return ret >= 0 ? ret : -1;
|
||||
|
||||
if (ret >= 0) {
|
||||
s->ts_last = clock_micros();
|
||||
return ret;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
long sock_recv(sock *s, void *buf, unsigned long len, int flags) {
|
||||
@@ -94,13 +67,17 @@ long sock_recv(sock *s, void *buf, unsigned long len, int flags) {
|
||||
if (s->enc) {
|
||||
int (*func)(SSL*, void*, int) = (flags & MSG_PEEK) ? SSL_peek : SSL_read;
|
||||
ret = func(s->ssl, buf, (int) len);
|
||||
s->_ssl_error = ERR_get_error();
|
||||
if (ret <= 0) error_ssl(SSL_get_error(s->ssl, (int) ret));
|
||||
} else {
|
||||
ret = recv(s->socket, buf, len, flags);
|
||||
}
|
||||
s->_last_ret = ret;
|
||||
s->_errno = errno;
|
||||
return ret >= 0 ? ret : -1;
|
||||
|
||||
if (ret >= 0) {
|
||||
s->ts_last = clock_micros();
|
||||
return ret;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigned long len) {
|
||||
@@ -142,7 +119,7 @@ long sock_splice_chunked(sock *dst, sock *src, void *buf, unsigned long buf_len)
|
||||
int sock_close(sock *s) {
|
||||
int e = errno;
|
||||
if (s->enc && s->ssl != NULL) {
|
||||
if (s->_last_ret >= 0) SSL_shutdown(s->ssl);
|
||||
SSL_shutdown(s->ssl);
|
||||
SSL_free(s->ssl);
|
||||
s->ssl = NULL;
|
||||
}
|
||||
|
@@ -23,18 +23,16 @@ typedef struct {
|
||||
char *addr, *s_addr;
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
long _last_ret;
|
||||
int _errno;
|
||||
unsigned long _ssl_error;
|
||||
long ts_start, ts_last, timeout_us;
|
||||
} sock;
|
||||
|
||||
int sock_enc_error(sock *s);
|
||||
int sock_set_socket_timeout_micros(sock *s, long recv_micros, long send_micros);
|
||||
|
||||
const char *sock_strerror(sock *s);
|
||||
int sock_set_socket_timeout(sock *s, double sec);
|
||||
|
||||
int sock_set_timeout_micros(sock *s, long recv_micros, long send_micros);
|
||||
int sock_set_timeout_micros(sock *s, long micros);
|
||||
|
||||
int sock_set_timeout(sock *s, int sec);
|
||||
int sock_set_timeout(sock *s, double sec);
|
||||
|
||||
long sock_send(sock *s, void *buf, unsigned long len, int flags);
|
||||
|
||||
|
@@ -211,7 +211,6 @@ long clock_micros(void) {
|
||||
return time.tv_sec * 1000000 + time.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
|
||||
long clock_cpu(void) {
|
||||
struct timespec time;
|
||||
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time);
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "logger.h"
|
||||
#include "lib/utils.h"
|
||||
#include "lib/error.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
@@ -59,8 +60,8 @@ static const char *level_keywords[] = {
|
||||
|
||||
static void err(const char *restrict msg) {
|
||||
char err_buf[64];
|
||||
strerror_r(errno, err_buf, sizeof(err_buf));
|
||||
fprintf(stderr, ERR_STR LOG_PREFIX " %s: %s" CLR_STR "\n", "logger", level_keywords[LOG_CRITICAL], msg, err_buf);
|
||||
fprintf(stderr, ERR_STR LOG_PREFIX " %s: %s" CLR_STR "\n", "logger",
|
||||
level_keywords[LOG_CRITICAL], msg, error_str(errno, err_buf, sizeof(err_buf)));
|
||||
}
|
||||
|
||||
void logmsgf(log_lvl_t level, const char *restrict format, ...) {
|
||||
@@ -71,8 +72,7 @@ void logmsgf(log_lvl_t level, const char *restrict format, ...) {
|
||||
|
||||
const char *color = (level <= LOG_ERROR) ? ERR_STR : ((level <= LOG_WARNING) ? WRN_STR : "");
|
||||
if (errno != 0) {
|
||||
strerror_r(errno, err_buf, sizeof(err_buf));
|
||||
snprintf(buf, sizeof(buf), "%s%s: %s" CLR_STR, color, format, err_buf);
|
||||
snprintf(buf, sizeof(buf), "%s%s: %s" CLR_STR, color, format, error_str(errno, err_buf, sizeof(err_buf)));
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%s%s" CLR_STR, color, format);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "workers.h"
|
||||
#include "worker/func.h"
|
||||
#include "lib/list.h"
|
||||
#include "lib/utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
@@ -98,6 +99,10 @@ static void accept_cb(void *arg) {
|
||||
|
||||
client->socket = client_fd;
|
||||
client->enc = (i == 1);
|
||||
client->ts_start = clock_micros();
|
||||
client->ts_last = client->ts_start;
|
||||
client_ctx->cnx_s = client->ts_start;
|
||||
client_ctx->cnx_e = -1, client_ctx->req_s = -1, client_ctx->req_e = -1, client_ctx->res_ts = -1;
|
||||
|
||||
tcp_accept(client_ctx);
|
||||
}
|
||||
@@ -301,12 +306,11 @@ int main(int argc, char *const argv[]) {
|
||||
workers_init();
|
||||
|
||||
for (int i = 0; i < NUM_SOCKETS; i++) {
|
||||
async_fd(sockets[i], ASYNC_WAIT_READ, ASYNC_KEEP, &sockets[i], accept_cb, accept_err_cb);
|
||||
async_fd(sockets[i], ASYNC_WAIT_READ, ASYNC_KEEP, &sockets[i], accept_cb, accept_err_cb, accept_err_cb);
|
||||
}
|
||||
|
||||
notice("Ready to accept connections");
|
||||
|
||||
// TODO handle timeouts in epoll
|
||||
async_thread();
|
||||
|
||||
notice("Goodbye!");
|
||||
|
@@ -58,6 +58,8 @@ int respond(client_ctx_t *ctx);
|
||||
|
||||
void request_complete(client_ctx_t *ctx);
|
||||
|
||||
void timeout_request(client_ctx_t *ctx);
|
||||
|
||||
void tcp_close(client_ctx_t *ctx);
|
||||
|
||||
void proxy_close(proxy_ctx_t *ctx);
|
||||
|
@@ -22,6 +22,8 @@ static int proxy_handler_2(client_ctx_t *ctx);
|
||||
void proxy_handler_func(client_ctx_t *ctx) {
|
||||
logger_set_prefix("[%s%*s%s]%s", BLD_STR, INET6_ADDRSTRLEN, ctx->req_host, CLR_STR, ctx->log_prefix);
|
||||
|
||||
// TODO handle 1xx responses
|
||||
|
||||
int ret = proxy_handler_1(ctx);
|
||||
respond(ctx);
|
||||
|
||||
|
@@ -14,9 +14,11 @@
|
||||
#include "../lib/utils.h"
|
||||
#include "../server.h"
|
||||
#include "../lib/res.h"
|
||||
#include "../lib/error.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
|
||||
static int request_handler(client_ctx_t *ctx);
|
||||
|
||||
@@ -41,15 +43,7 @@ void request_handler_func(client_ctx_t *ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
static int request_handler(client_ctx_t *ctx) {
|
||||
sock *client = &ctx->socket;
|
||||
char *err_msg = ctx->err_msg;
|
||||
|
||||
long ret;
|
||||
char buf0[1024], buf1[1024];
|
||||
|
||||
err_msg[0] = 0;
|
||||
|
||||
static void init_ctx(client_ctx_t *ctx) {
|
||||
ctx->conf = NULL;
|
||||
ctx->file = NULL;
|
||||
ctx->proxy = NULL;
|
||||
@@ -62,24 +56,35 @@ static int request_handler(client_ctx_t *ctx) {
|
||||
ctx->msg_buf_ptr = NULL;
|
||||
ctx->req_host[0] = 0;
|
||||
ctx->err_msg[0] = 0;
|
||||
ctx->req_s = ctx->socket.ts_last;
|
||||
|
||||
memset(&ctx->uri, 0, sizeof(ctx->uri));
|
||||
memset(&ctx->req, 0, sizeof(ctx->req));
|
||||
memset(&ctx->res, 0, sizeof(ctx->res));
|
||||
|
||||
http_res *res = &ctx->res;
|
||||
res->status = http_get_status(501);
|
||||
http_init_hdr(&res->hdr);
|
||||
res->hdr.last_field_num = -1;
|
||||
sprintf(res->version, "1.1");
|
||||
|
||||
http_status_ctx *status = &ctx->status;
|
||||
status->status = 0;
|
||||
status->origin = NONE;
|
||||
status->ws_key = NULL;
|
||||
ctx->res.status = http_get_status(501);
|
||||
http_init_hdr(&ctx->res.hdr);
|
||||
ctx->res.hdr.last_field_num = -1;
|
||||
sprintf(ctx->res.version, "1.1");
|
||||
|
||||
ctx->status.status = 0;
|
||||
ctx->status.origin = NONE;
|
||||
ctx->status.ws_key = NULL;
|
||||
}
|
||||
|
||||
static int request_handler(client_ctx_t *ctx) {
|
||||
sock *client = &ctx->socket;
|
||||
char *err_msg = ctx->err_msg;
|
||||
http_res *res = &ctx->res;
|
||||
|
||||
long ret;
|
||||
char buf0[1024], buf1[1024];
|
||||
|
||||
ctx->req_s = clock_micros();
|
||||
|
||||
init_ctx(ctx);
|
||||
|
||||
http_add_header_field(&res->hdr, "Date", http_get_date(buf0, sizeof(buf0)));
|
||||
http_add_header_field(&res->hdr, "Server", SERVER_STR);
|
||||
/*if (ret <= 0) {
|
||||
@@ -94,20 +99,11 @@ static int request_handler(client_ctx_t *ctx) {
|
||||
ret = http_receive_request(client, req);
|
||||
if (ret != 0) {
|
||||
ctx->c_keep_alive = 0;
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
} else if (ret == 1) {
|
||||
sprintf(err_msg, "Unable to parse http header: Invalid header format.");
|
||||
} else if (ret == 2) {
|
||||
sprintf(err_msg, "Unable to parse http header: Invalid method.");
|
||||
} else if (ret == 3) {
|
||||
sprintf(err_msg, "Unable to parse http header: Invalid version.");
|
||||
} else if (ret == 4) {
|
||||
sprintf(err_msg, "Unable to parse http header: Header contains illegal characters.");
|
||||
} else if (ret == 5) {
|
||||
sprintf(err_msg, "Unable to parse http header: End of header not found.");
|
||||
}
|
||||
res->status = http_get_status(400);
|
||||
error("Unable to receive http header");
|
||||
sprintf(err_msg, "Unable to receive http header: %s.", error_str(errno, buf0, sizeof(buf0)));
|
||||
int err = error_get_http();
|
||||
res->status = http_get_status(err == HTTP_ERROR_URI_TOO_LONG ? 414 : (err == HTTP_ERROR_TOO_MANY_HEADER_FIELDS ? 431 : 400));
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -170,6 +166,7 @@ static int request_handler(client_ctx_t *ctx) {
|
||||
ctx->conf = get_host_config(ctx->req_host);
|
||||
if (ctx->conf == NULL) {
|
||||
res->status = http_get_status(421);
|
||||
strcpy(ctx->err_msg, "The requested host name is not configured on the server.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -348,7 +345,7 @@ int respond(client_ctx_t *ctx) {
|
||||
if (ctx->msg_buf != NULL) {
|
||||
ret = sock_send(client, ctx->msg_buf, ctx->content_length, 0);
|
||||
if (ret <= 0) {
|
||||
error("Unable to send: %s", sock_strerror(client));
|
||||
error("Unable to send");
|
||||
}
|
||||
} else if (ctx->file != NULL) {
|
||||
unsigned long len, snd_len = 0;
|
||||
@@ -359,7 +356,7 @@ int respond(client_ctx_t *ctx) {
|
||||
}
|
||||
ret = sock_send(client, buffer, len, feof(ctx->file) ? 0 : MSG_MORE);
|
||||
if (ret <= 0) {
|
||||
error("Unable to send: %s", sock_strerror(client));
|
||||
error("Unable to send");
|
||||
break;
|
||||
}
|
||||
snd_len += ret;
|
||||
@@ -386,3 +383,14 @@ void request_complete(client_ctx_t *ctx) {
|
||||
http_free_req(&ctx->req);
|
||||
http_free_res(&ctx->res);
|
||||
}
|
||||
|
||||
void timeout_request(client_ctx_t *ctx) {
|
||||
init_ctx(ctx);
|
||||
logger_set_prefix("[%*s]%s", INET6_ADDRSTRLEN, ctx->socket.s_addr, ctx->log_prefix);
|
||||
|
||||
ctx->s_keep_alive = 0;
|
||||
ctx->res.status = http_get_status(408);
|
||||
|
||||
respond(ctx);
|
||||
tcp_close(ctx);
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "../lib/geoip.h"
|
||||
#include "../workers.h"
|
||||
#include "../server.h"
|
||||
#include "../lib/error.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
@@ -63,7 +64,7 @@ static int tcp_acceptor(client_ctx_t *ctx) {
|
||||
sprintf(buf, "dig @%s +short +time=1 -x %s", config.dns_server, ctx->socket.addr);
|
||||
FILE *dig = popen(buf, "r");
|
||||
if (dig == NULL) {
|
||||
error("Unable to start dig: %s", strerror(errno));
|
||||
error("Unable to start dig: %s");
|
||||
goto dig_err;
|
||||
}
|
||||
unsigned long read = fread(buf, 1, sizeof(buf), dig);
|
||||
@@ -90,7 +91,7 @@ static int tcp_acceptor(client_ctx_t *ctx) {
|
||||
ctx->host[0] != 0 ? ctx->host : "", ctx->host[0] != 0 ? ") " : "",
|
||||
ctx->cc[0] != 0 ? ctx->cc : "N/A");
|
||||
|
||||
if (sock_set_timeout(client, CLIENT_TIMEOUT)) {
|
||||
if (sock_set_socket_timeout(client, 1) != 0 || sock_set_timeout(client, CLIENT_TIMEOUT) != 0) {
|
||||
error("Unable to set timeout for socket");
|
||||
return -1;
|
||||
}
|
||||
@@ -101,13 +102,12 @@ static int tcp_acceptor(client_ctx_t *ctx) {
|
||||
SSL_set_accept_state(client->ssl);
|
||||
|
||||
ret = SSL_accept(client->ssl);
|
||||
client->_last_ret = ret;
|
||||
client->_errno = errno;
|
||||
client->_ssl_error = ERR_get_error();
|
||||
if (ret <= 0) {
|
||||
info("Unable to perform handshake: %s", sock_strerror(client));
|
||||
if (ret != 1) {
|
||||
error_ssl(SSL_get_error(client->ssl, ret));
|
||||
info("Unable to perform handshake");
|
||||
return - 1;
|
||||
}
|
||||
client->ts_last = clock_micros();
|
||||
}
|
||||
|
||||
ctx->req_num = 0;
|
||||
|
@@ -53,7 +53,10 @@ static int handle_request_cb(client_ctx_t *ctx) {
|
||||
|
||||
int handle_request(client_ctx_t *ctx) {
|
||||
if (ctx->c_keep_alive && ctx->s_keep_alive) {
|
||||
return async(&ctx->socket, ASYNC_WAIT_READ, 0, ctx, (void (*)(void *)) handle_request_cb, (void (*)(void *)) tcp_close);
|
||||
return async(&ctx->socket, ASYNC_WAIT_READ, 0, ctx,
|
||||
(void (*)(void *)) handle_request_cb,
|
||||
(void (*)(void *)) timeout_request,
|
||||
(void (*)(void *)) tcp_close);
|
||||
} else {
|
||||
tcp_close(ctx);
|
||||
return 0;
|
||||
@@ -77,5 +80,8 @@ static int ws_handle_frame_cb(ws_ctx_t *ctx) {
|
||||
}
|
||||
|
||||
int ws_handle_frame(ws_ctx_t *ctx) {
|
||||
return async(ctx->socket, ASYNC_WAIT_READ, 0, ctx, (void (*)(void *)) ws_handle_frame_cb, (void (*)(void *)) ws_close);
|
||||
return async(ctx->socket, ASYNC_WAIT_READ, 0, ctx,
|
||||
(void (*)(void *)) ws_handle_frame_cb,
|
||||
(void (*)(void *)) ws_close,
|
||||
(void (*)(void *)) ws_close);
|
||||
}
|
||||
|
Reference in New Issue
Block a user