27 Commits
v4.2 ... v4.3

Author SHA1 Message Date
1b44752f91 Changed icon order in default document 2021-03-19 18:13:00 +01:00
5eeb9ef3c1 Http document alternate icon 2021-03-19 18:10:18 +01:00
dd15b9d906 Http and proxy refactor 2021-03-19 17:55:52 +01:00
12922a0661 Updated version string to 4.3 2021-03-18 20:37:07 +01:00
c0799101b1 Removed TODO escape IPv6 addresses 2021-03-18 20:32:09 +01:00
c1d076db04 Refactor code to avoid warnings 2021-03-18 20:27:45 +01:00
10464f3f30 Added Reverse Proxy Header Support 2021-03-18 19:56:50 +01:00
63781472fa Bugfix for config post processing 2021-03-16 22:07:19 +01:00
81931d287d Cache debug messages improvements 2021-03-16 21:57:33 +01:00
531ddb4880 Caching debug messages 2021-03-16 21:54:49 +01:00
e0d8ab31d5 Improved cache idle performance 2021-03-16 20:22:36 +01:00
3a36d54e9d Added standard favicon /favicon.ico to error document 2021-03-16 19:27:03 +01:00
33d9aa3a5d Date header field fix 2021-03-16 19:15:26 +01:00
f4d30206b0 Fix hidden paths 2021-03-11 22:09:32 +01:00
5b094ba98d Hidden paths -> 403 2021-03-11 22:05:38 +01:00
f60cdc8228 Added TODO for 3xx Redirects 2021-03-11 20:30:03 +01:00
ab1c4d6fd4 Changed 203 -> 404 2021-03-11 20:25:07 +01:00
26d54e9968 Added error documents and 203 response if webroot does not exist 2021-03-11 20:19:14 +01:00
b6c7d8f58e URL UTF-8 Bugfix 2021-01-24 21:20:48 +01:00
53fcceeafb Add FIXME 2021-01-17 18:10:50 +01:00
96567909db FastCGI error bugfix 2021-01-17 18:06:03 +01:00
4b3c067a75 Fix includes 2021-01-17 17:56:16 +01:00
77b80ca67b Bugfix splice 2021-01-13 21:21:24 +01:00
70e76d8783 Error doc update 2 2021-01-10 12:22:48 +01:00
6b1bc54cf3 Error doc update 2021-01-10 12:18:44 +01:00
e1edb48a3c Redirect to https even on reverse proxy 2021-01-09 12:57:24 +01:00
dc5d1bebcc Add TODO for access/error log file 2021-01-09 12:39:55 +01:00
20 changed files with 453 additions and 108 deletions

View File

@ -7,11 +7,11 @@ packages:
compile:
@mkdir -p bin
gcc src/necronda-server.c -o bin/necronda-server -std=c11 -lssl -lcrypto -lmagic -lz -lmaxminddb
gcc src/necronda-server.c -o bin/necronda-server -std=c11 -lssl -lcrypto -lmagic -lz -lmaxminddb -Wall
compile-debian:
@mkdir -p bin
gcc src/necronda-server.c -o bin/necronda-server -std=c11 -lssl -lcrypto -lmagic -lz -lmaxminddb \
gcc src/necronda-server.c -o bin/necronda-server -std=c11 -lssl -lcrypto -lmagic -lz -lmaxminddb -Wall \
-D MAGIC_FILE="\"/usr/share/file/magic.mgc\"" \
-D PHP_FPM_SOCKET="\"/var/run/php/php7.3-fpm.sock\""

View File

@ -5,9 +5,8 @@
* Lorenz Stechauner, 2020-12-19
*/
#include <zlib.h>
#include "cache.h"
#include "uri.h"
int magic_init() {
magic = magic_open(MAGIC_MIME);
@ -69,10 +68,13 @@ int cache_process() {
int compress;
SHA_CTX ctx;
unsigned char hash[SHA_DIGEST_LENGTH];
int cache_changed = 0;
int p_len;
while (cache_continue) {
for (int i = 0; i < FILE_CACHE_SIZE; i++) {
if (cache[i].filename[0] != 0 && cache[i].meta.etag[0] == 0 && !cache[i].is_updating) {
cache[i].is_updating = 1;
fprintf(stdout, "[cache] Hashing file %s\n", cache[i].filename);
SHA1_Init(&ctx);
file = fopen(cache[i].filename, "rb");
compress = strncmp(cache[i].meta.type, "text/", 5) == 0 ||
@ -96,11 +98,19 @@ int cache_process() {
buf[j] = ch;
}
buf[strlen(rel_path)] = 0;
sprintf(filename_comp, "%.*s/.necronda-server/cache/%s.z", cache[i].webroot_len, cache[i].filename, buf);
p_len = snprintf(filename_comp, sizeof(filename_comp), "%.*s/.necronda-server/cache/%s.z",
cache[i].webroot_len, cache[i].filename, buf);
if (p_len < 0 || p_len >= sizeof(filename_comp)) {
fprintf(stderr, ERR_STR "Unable to open cached file: "
"File name for compressed file too long" CLR_STR "\n");
goto comp_err;
}
fprintf(stdout, "[cache] Compressing file %s\n", cache[i].filename);
comp_file = fopen(filename_comp, "wb");
if (comp_file == NULL) {
fprintf(stderr, ERR_STR "Unable to open cached file: %s" CLR_STR "\n", strerror(errno));
comp_err:
compress = 0;
fprintf(stderr, ERR_STR "Unable to open cache file: %s" CLR_STR "\n", strerror(errno));
} else {
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
@ -131,6 +141,7 @@ int cache_process() {
if (compress) {
deflateEnd(&strm);
fclose(comp_file);
fprintf(stdout, "[cache] Finished compressing file %s\n", cache[i].filename);
strcpy(cache[i].meta.filename_comp, filename_comp);
} else {
memset(cache[i].meta.filename_comp, 0, sizeof(cache[i].meta.filename_comp));
@ -141,14 +152,20 @@ int cache_process() {
sprintf(cache[i].meta.etag + j * 2, "%02x", hash[j]);
}
fclose(file);
fprintf(stdout, "[cache] Finished hashing file %s\n", cache[i].filename);
cache[i].is_updating = 0;
cache_changed = 1;
}
}
cache_file = fopen("/var/necronda-server/cache", "wb");
fwrite(cache, sizeof(cache_entry), FILE_CACHE_SIZE , cache_file);
fclose(cache_file);
sleep(1);
if (cache_changed) {
cache_changed = 0;
cache_file = fopen("/var/necronda-server/cache", "wb");
fwrite(cache, sizeof(cache_entry), FILE_CACHE_SIZE, cache_file);
fclose(cache_file);
} else {
sleep(1);
}
}
return 0;
}

View File

@ -8,10 +8,14 @@
#ifndef NECRONDA_SERVER_CACHE_H
#define NECRONDA_SERVER_CACHE_H
#include "uri.h"
#include <stdio.h>
#include <zlib.h>
#include <magic.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "uri.h"
magic_t magic;

View File

@ -5,18 +5,9 @@
* Lorenz Stechauner, 2020-12-03
*/
#include "necronda-server.h"
#include "utils.h"
#include "uri.h"
#include "http.h"
#include "fastcgi.h"
#include "client.h"
int server_keep_alive = 1;
char *log_client_prefix, *log_conn_prefix, *log_req_prefix, *client_geoip;
struct timeval client_timeout = {.tv_sec = CLIENT_TIMEOUT, .tv_usec = 0};
host_config *get_host_config(const char *host) {
for (int i = 0; i < MAX_HOST_CONFIG; i++) {
host_config *hc = &config[i];
@ -51,6 +42,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
int accept_if_modified_since = 0;
int use_fastcgi = 0;
int use_rev_proxy = 0;
int p_len;
fastcgi_conn php_fpm = {.socket = 0, .req_id = 0};
http_status custom_status;
@ -58,8 +50,6 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
sprintf(res.version, "1.1");
res.status = http_get_status(501);
res.hdr.field_num = 0;
http_add_header_field(&res.hdr, "Date", http_get_date(buf0, sizeof(buf0)));
http_add_header_field(&res.hdr, "Server", SERVER_STR);
clock_gettime(CLOCK_MONOTONIC, &begin);
@ -69,6 +59,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
client_timeout.tv_sec = CLIENT_TIMEOUT;
client_timeout.tv_usec = 0;
ret = select(client->socket + 1, &socket_fds, NULL, NULL, &client_timeout);
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) {
if (errno != 0) {
return 1;
@ -102,7 +94,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
hdr_connection = http_get_header_field(&req.hdr, "Connection");
client_keep_alive = hdr_connection != NULL &&
(strcmp(hdr_connection, "keep-alive") == 0 || strcmp(hdr_connection, "Keep-Alive") == 0);
(strcmp(hdr_connection, "keep-alive") == 0 || strcmp(hdr_connection, "Keep-Alive") == 0);
host_ptr = http_get_header_field(&req.hdr, "Host");
if (host_ptr != NULL && strlen(host_ptr) > 255) {
host[0] = 0;
@ -141,10 +133,16 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
if (ret != 0) {
if (ret == 1) {
sprintf(err_msg, "Invalid URI: has to start with slash.");
res.status = http_get_status(400);
} else if (ret == 2) {
sprintf(err_msg, "Invalid URI: contains relative path change (/../).");
res.status = http_get_status(400);
} else if (ret == 3) {
sprintf(err_msg, "The specified webroot directory does not exist.");
res.status = http_get_status(404);
} else {
res.status = http_get_status(500);
}
res.status = http_get_status(400);
goto respond;
}
@ -155,19 +153,33 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
if (strcmp(uri.uri, buf0) != 0 || change_proto) {
res.status = http_get_status(308);
size = sizeof(buf0);
encode_url(uri.uri, buf0, &size);
url_encode(uri.uri, buf0, &size);
if (change_proto) {
sprintf(buf1, "https://%s%s", host, buf0);
p_len = snprintf(buf1, sizeof(buf1), "https://%s%s", host, buf0);
if (p_len < 0 || p_len >= sizeof(buf1)) {
res.status = http_get_status(500);
print(ERR_STR "Header field 'Location' too long" CLR_STR);
goto respond;
}
http_add_header_field(&res.hdr, "Location", buf1);
} else {
http_add_header_field(&res.hdr, "Location", buf0);
}
goto respond;
}
} else if (!client->enc) {
res.status = http_get_status(308);
sprintf(buf0, "https://%s%s", host, req.uri);
http_add_header_field(&res.hdr, "Location", buf0);
goto respond;
}
if (conf->type == CONFIG_TYPE_LOCAL) {
if (uri.filename == NULL && (int) uri.is_static && (int) uri.is_dir && strlen(uri.pathinfo) == 0) {
if (strncmp(uri.req_path, "/.well-known/", 13) != 0 && strstr(uri.path, "/.") != NULL) {
res.status = http_get_status(403);
sprintf(err_msg, "Parts of this URI are hidden.");
goto respond;
} else if (uri.filename == NULL && (int) uri.is_static && (int) uri.is_dir && strlen(uri.pathinfo) == 0) {
res.status = http_get_status(403);
sprintf(err_msg, "It is not allowed to list the contents of this directory.");
goto respond;
@ -215,7 +227,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
char *if_modified_since = http_get_header_field(&req.hdr, "If-Modified-Since");
char *if_none_match = http_get_header_field(&req.hdr, "If-None-Match");
if ((if_none_match != NULL && strstr(if_none_match, uri.meta->etag) == NULL) ||
(accept_if_modified_since && if_modified_since != NULL && strcmp(if_modified_since, last_modified) == 0)) {
(accept_if_modified_since && if_modified_since != NULL &&
strcmp(if_modified_since, last_modified) == 0)) {
res.status = http_get_status(304);
goto respond;
}
@ -349,8 +362,10 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
http_add_header_field(&res.hdr, "Transfer-Encoding", "chunked");
}
}
} else if (conf->type != CONFIG_TYPE_LOCAL) {
} else if (conf->type == CONFIG_TYPE_REVERSE_PROXY) {
print("Reverse proxy for " BLD_STR "%s:%i" CLR_STR, conf->rev_proxy.hostname, conf->rev_proxy.port);
http_remove_header_field(&res.hdr, "Date", HTTP_REMOVE_ALL);
http_remove_header_field(&res.hdr, "Server", HTTP_REMOVE_ALL);
ret = rev_proxy_init(&req, &res, conf, client, &custom_status, err_msg);
use_rev_proxy = ret == 0;
} else {
@ -364,13 +379,20 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
http_add_header_field(&res.hdr, "Accept-Ranges", "none");
}
if (!use_fastcgi && !use_rev_proxy && file == NULL &&
res.status->code >= 400 && res.status->code < 600) {
http_error_msg *http_msg = http_get_error_msg(res.status->code);
sprintf(msg_pre_buf, http_error_document, res.status->code, res.status->msg,
http_msg != NULL ? http_msg->err_msg : "", err_msg[0] != 0 ? err_msg : "");
content_length = sprintf(msg_buf, http_default_document, res.status->code, res.status->msg,
msg_pre_buf, res.status->code >= 300 && res.status->code < 400 ? "info" : "error",
http_error_icon, "#C00000", host);
((res.status->code >= 400 && res.status->code < 600) || err_msg[0] != 0)) {
http_remove_header_field(&res.hdr, "Date", HTTP_REMOVE_ALL);
http_remove_header_field(&res.hdr, "Server", HTTP_REMOVE_ALL);
http_add_header_field(&res.hdr, "Date", http_get_date(buf0, sizeof(buf0)));
http_add_header_field(&res.hdr, "Server", SERVER_STR);
// TODO list Locations on 3xx Redirects
const http_doc_info *info = http_get_status_info(res.status);
const http_status_msg *http_msg = http_get_error_msg(res.status);
sprintf(msg_pre_buf, info->doc, res.status->code, res.status->msg,
http_msg != NULL ? http_msg->msg : "", err_msg[0] != 0 ? err_msg : "");
content_length = snprintf(msg_buf, sizeof(msg_buf), http_default_document, res.status->code,
res.status->msg, msg_pre_buf, info->mode, info->icon, info->color, host);
http_add_header_field(&res.hdr, "Content-Type", "text/html; charset=UTF-8");
}
if (content_length >= 0) {
@ -379,12 +401,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
} else if (http_get_header_field(&res.hdr, "Transfer-Encoding") == NULL) {
server_keep_alive = 0;
}
} else {
http_remove_header_field(&res.hdr, "Server", HTTP_REMOVE_ALL);
http_remove_header_field(&res.hdr, "Date", HTTP_REMOVE_ALL);
http_add_header_field(&res.hdr, "Date", http_get_date(buf0, sizeof(buf0)));
http_add_header_field(&res.hdr, "Server", SERVER_STR);
}
char *conn = http_get_header_field(&res.hdr, "Connection");
int close_proxy = conn == NULL || (strcmp(conn, "keep-alive") != 0 && strcmp(conn, "Keep-Alive") != 0);
http_remove_header_field(&res.hdr, "Connection", HTTP_REMOVE_ALL);
@ -405,6 +423,8 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
res.status->msg, location != NULL ? " -> " : "", location != NULL ? location : "",
format_duration(micros, buf0), CLR_STR);
// TODO access/error log file
if (strcmp(req.method, "HEAD") != 0) {
unsigned long snd_len = 0;
unsigned long len;

23
src/client.h Normal file
View File

@ -0,0 +1,23 @@
/**
* Necronda Web Server
* Client connection and request handlers (header file)
* src/client.h
* Lorenz Stechauner, 2021-01-17
*/
#ifndef NECRONDA_SERVER_CLIENT_H
#define NECRONDA_SERVER_CLIENT_H
#include "necronda-server.h"
#include "utils.h"
#include "uri.h"
#include "http.h"
#include "fastcgi.h"
int server_keep_alive = 1;
char *log_client_prefix, *log_conn_prefix, *log_req_prefix, *client_geoip;
struct timeval client_timeout = {.tv_sec = CLIENT_TIMEOUT, .tv_usec = 0};
#endif //NECRONDA_SERVER_CLIENT_H

View File

@ -6,9 +6,7 @@
*/
#include "config.h"
#include "uri.h"
#include <sys/ipc.h>
#include <sys/shm.h>
int config_init() {
int shm_id = shmget(SHM_KEY_CONFIG, MAX_HOST_CONFIG * sizeof(host_config), IPC_CREAT | IPC_EXCL | 0640);
@ -71,8 +69,7 @@ int config_load(const char *filename) {
int i = 0;
int mode = 0;
char *ptr = NULL;
char host[256], *source, *target;
host[0] = 0;
char *source, *target;
while ((ptr = strtok(ptr == NULL ? conf : NULL, "\n")) != NULL) {
char *comment = strchr(ptr, '#');
if (comment != NULL) comment[0] = 0;
@ -177,9 +174,17 @@ int config_load(const char *filename) {
tmp_config[i - 1].rev_proxy.port = (unsigned short) strtoul(source, NULL, 10);
}
}
free(conf);
for (int j = 0; j < i; j++) {
if (tmp_config[j].type == CONFIG_TYPE_LOCAL) {
char *webroot = tmp_config[j].local.webroot;
if (webroot[strlen(webroot) - 1] == '/') {
webroot[strlen(webroot) - 1] = 0;
}
}
}
int shm_id = shmget(SHM_KEY_CONFIG, 0, 0);
if (shm_id < 0) {
fprintf(stderr, ERR_STR "Unable to get shared memory id: %s" CLR_STR "\n", strerror(errno));

View File

@ -13,6 +13,12 @@
#define CONFIG_TYPE_LOCAL 1
#define CONFIG_TYPE_REVERSE_PROXY 2
#include "uri.h"
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
typedef struct {
int type;

View File

@ -6,9 +6,6 @@
*/
#include "fastcgi.h"
#include "necronda-server.h"
#include <sys/un.h>
char *fastcgi_add_param(char *buf, const char *key, const char *value) {
@ -133,7 +130,7 @@ int fastcgi_init(fastcgi_conn *conn, unsigned int client_num, unsigned int req_n
if (uri->pathinfo != NULL && strlen(uri->pathinfo) > 0) {
sprintf(buf0, "/%s", uri->pathinfo);
} else {
sprintf(buf0, "");
buf0[0] = 0;
}
param_ptr = fastcgi_add_param(param_ptr, "PATH_INFO", buf0);
@ -205,17 +202,21 @@ int fastcgi_close_stdin(fastcgi_conn *conn) {
return 0;
}
int fastcgi_php_error(char *msg, int msg_len, char *err_msg) {
int fastcgi_php_error(const char *msg, int msg_len, char *err_msg) {
char *msg_str = malloc(msg_len + 1);
char *ptr0 = msg_str;
strncpy(msg_str, msg, msg_len);
char *ptr1 = NULL;
int len;
int err = 0;
// FIXME *msg is part of a stream, handle fragmented lines
while (1) {
int msg_type = 0;
int msg_pre_len = 0;
ptr1 = strstr(ptr0, "PHP message: ");
if (ptr1 == NULL) {
len = (int) (msg_len - (ptr0 - msg_str));
if (ptr0 == msg_str) msg_type = 2;
} else {
len = (int) (ptr1 - ptr0);
}
@ -223,8 +224,6 @@ int fastcgi_php_error(char *msg, int msg_len, char *err_msg) {
goto next;
}
int msg_type = 0;
int msg_pre_len = 0;
if (len >= 14 && strncmp(ptr0, "PHP Warning: ", 14) == 0) {
msg_type = 1;
msg_pre_len = 14;
@ -248,7 +247,7 @@ int fastcgi_php_error(char *msg, int msg_len, char *err_msg) {
if (ptr3 != NULL && (ptr3 - ptr2) < len2) {
len2 = (int) (ptr3 - ptr2);
}
print("%s%.*s%s", msg_type == 1 ? WRN_STR : msg_type == 2 ? ERR_STR: "", len2, ptr2, msg_type != 0 ? CLR_STR : "");
print("%s%.*s%s", msg_type == 1 ? WRN_STR : msg_type == 2 ? ERR_STR : "", len2, ptr2, msg_type != 0 ? CLR_STR : "");
if (msg_type == 2 && ptr2 == ptr0) {
sprintf(err_msg, "%.*s", len2, ptr2);
err = 1;
@ -265,6 +264,7 @@ int fastcgi_php_error(char *msg, int msg_len, char *err_msg) {
}
ptr0 = ptr1 + 13;
}
free(msg_str);
return err;
}
@ -457,7 +457,7 @@ int fastcgi_send(fastcgi_conn *conn, sock *client, int flags) {
return 0;
} else if (header.type == FCGI_STDERR) {
print(ERR_STR "%.*s" CLR_STR, content_len, content);
fastcgi_php_error(content, content_len, buf0);
} else if (header.type == FCGI_STDOUT) {
out:
if (flags & FASTCGI_COMPRESS) {

View File

@ -11,6 +11,15 @@
#define FASTCGI_CHUNKED 1
#define FASTCGI_COMPRESS 2
#include "necronda-server.h"
#include "http.h"
#include "uri.h"
#include "client.h"
#include <sys/un.h>
#include <zlib.h>
typedef struct {
int socket;
unsigned short req_id;
@ -26,6 +35,8 @@ int fastcgi_init(fastcgi_conn *conn, unsigned int client_num, unsigned int req_n
int fastcgi_close_stdin(fastcgi_conn *conn);
int fastcgi_php_error(const char *msg, int msg_len, char *err_msg);
int fastcgi_header(fastcgi_conn *conn, http_res *res, char *err_msg);
int fastcgi_send(fastcgi_conn *conn, sock *client, int flags);

View File

@ -6,7 +6,6 @@
*/
#include "http.h"
#include "utils.h"
void http_to_camel_case(char *str, int mode) {
@ -50,9 +49,9 @@ int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr)
}
long len = pos1 - buf;
hdr->fields[hdr->field_num][0] = malloc(len + 1);
sprintf(hdr->fields[hdr->field_num][0], "%.*s", (int) len, buf);
http_to_camel_case(hdr->fields[hdr->field_num][0], HTTP_CAMEL);
hdr->fields[(int) hdr->field_num][0] = malloc(len + 1);
sprintf(hdr->fields[(int) hdr->field_num][0], "%.*s", (int) len, buf);
http_to_camel_case(hdr->fields[(int) hdr->field_num][0], HTTP_CAMEL);
pos1++;
pos2 = (char *) end_ptr - 1;
@ -61,11 +60,11 @@ int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr)
len = pos2 - pos1 + 1;
if (len <= 0) {
hdr->fields[hdr->field_num][1] = malloc(1);
hdr->fields[hdr->field_num][1][0] = 0;
hdr->fields[(int) hdr->field_num][1] = malloc(1);
hdr->fields[(int) hdr->field_num][1][0] = 0;
} else {
hdr->fields[hdr->field_num][1] = malloc(len + 1);
sprintf(hdr->fields[hdr->field_num][1], "%.*s", (int) len, pos1);
hdr->fields[(int) hdr->field_num][1] = malloc(len + 1);
sprintf(hdr->fields[(int) hdr->field_num][1], "%.*s", (int) len, pos1);
}
hdr->field_num++;
return 0;
@ -185,8 +184,8 @@ void http_add_header_field(http_hdr *hdr, const char *field_name, const char *fi
strcpy(_field_name, field_name);
strcpy(_field_value, field_value);
http_to_camel_case(_field_name, HTTP_PRESERVE);
hdr->fields[hdr->field_num][0] = _field_name;
hdr->fields[hdr->field_num][1] = _field_value;
hdr->fields[(int) hdr->field_num][0] = _field_name;
hdr->fields[(int) hdr->field_num][1] = _field_value;
hdr->field_num++;
}
@ -245,7 +244,7 @@ int http_send_request(sock *server, http_req *req) {
return 0;
}
http_status *http_get_status(unsigned short status_code) {
const http_status *http_get_status(unsigned short status_code) {
for (int i = 0; i < sizeof(http_statuses) / sizeof(http_status); i++) {
if (http_statuses[i].code == status_code) {
return &http_statuses[i];
@ -254,20 +253,21 @@ http_status *http_get_status(unsigned short status_code) {
return NULL;
}
http_error_msg *http_get_error_msg(unsigned short status_code) {
for (int i = 0; i < sizeof(http_error_messages) / sizeof(http_error_msg); i++) {
if (http_error_messages[i].code == status_code) {
return &http_error_messages[i];
const http_status_msg *http_get_error_msg(const http_status *status) {
unsigned short code = status->code;
for (int i = 0; i < sizeof(http_status_messages) / sizeof(http_status_msg); i++) {
if (http_status_messages[i].code == code) {
return &http_status_messages[i];
}
}
return NULL;
}
const char *http_get_status_color(http_status *status) {
const char *http_get_status_color(const http_status *status) {
unsigned short code = status->code;
if (code >= 100 && code < 200) {
return HTTP_1XX_STR;
} else if (code >= 200 && code < 300 || code == 304) {
} else if ((code >= 200 && code < 300) || code == 304) {
return HTTP_2XX_STR;
} else if (code >= 300 && code < 400) {
return HTTP_3XX_STR;
@ -290,3 +290,23 @@ char *http_get_date(char *buf, size_t size) {
time(&rawtime);
return http_format_date(rawtime, buf, size);
}
const http_doc_info *http_get_status_info(const http_status *status) {
unsigned short code = status->code;
static http_doc_info info[] = {
{"info", HTTP_COLOR_INFO, http_info_icon, http_info_document},
{"success", HTTP_COLOR_SUCCESS, http_success_icon, http_success_document},
{"warning", HTTP_COLOR_WARNING, http_warning_icon, http_warning_document},
{"error", HTTP_COLOR_ERROR, http_error_icon, http_error_document}
};
if (code >= 100 && code < 200) {
return &info[0];
} else if ((code >= 200 && code < 300) || code == 304) {
return &info[1];
} else if (code >= 300 && code < 400) {
return &info[2];
} else if (code >= 400 && code < 600) {
return &info[3];
}
return NULL;
}

View File

@ -16,6 +16,15 @@
#define HTTP_REMOVE_ALL 1
#define HTTP_REMOVE_LAST 2
#define HTTP_COLOR_SUCCESS "#008000"
#define HTTP_COLOR_INFO "#606060"
#define HTTP_COLOR_WARNING "#E0C000"
#define HTTP_COLOR_ERROR "#C00000"
#include "sock.h"
#include "utils.h"
typedef struct {
unsigned short code;
char type[16];
@ -24,8 +33,15 @@ typedef struct {
typedef struct {
unsigned short code;
char *err_msg;
} http_error_msg;
const char *msg;
} http_status_msg;
typedef struct {
char mode[8];
char color[8];
const char *icon;
const char *doc;
} http_doc_info;
typedef struct {
char field_num;
@ -40,12 +56,12 @@ typedef struct {
} http_req;
typedef struct {
http_status *status;
const http_status *status;
char version[3];
http_hdr hdr;
} http_res;
http_status http_statuses[] = {
static const http_status http_statuses[] = {
{100, "Informational", "Continue"},
{101, "Informational", "Switching Protocols"},
@ -61,7 +77,7 @@ http_status http_statuses[] = {
{301, "Redirection", "Moved Permanently"},
{302, "Redirection", "Found"},
{303, "Redirection", "See Other"},
{304, "Redirection", "Not Modified"},
{304, "Success", "Not Modified"},
{305, "Redirection", "Use Proxy"},
{307, "Redirection", "Temporary Redirect"},
{308, "Redirection", "Permanent Redirect"},
@ -93,7 +109,27 @@ http_status http_statuses[] = {
{505, "Server Error", "HTTP Version Not Supported"},
};
http_error_msg http_error_messages[] = {
static const http_status_msg http_status_messages[] = {
{100, "The client SHOULD continue with its request."},
{101, "The server understands and is willing to comply with the clients request, via the Upgrade message header field, for a change in the application protocol being used on this connection."},
{200, "The request has succeeded."},
{201, "The request has been fulfilled and resulted in a new resource being created."},
{202, "The request has been accepted for processing, but the processing has not been completed."},
{203, "The returned meta information in the entity-header is not the definitive set as available from the origin server, but is gathered from a local or a third-party copy."},
{204, "The server has fulfilled the request but does not need to return an entity-body, and might want to return updated meta information."},
{205, "The server has fulfilled the request and the user agent SHOULD reset the document view which caused the request to be sent."},
{206, "The server has fulfilled the partial GET request for the resource."},
{300, "The requested resource corresponds to any one of a set of representations, each with its own specific location, and agent-driven negotiation information is being provided so that the user (or user agent) can select a preferred representation and redirect its request to that location."},
{301, "The requested resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs."},
{302, "The requested resource resides temporarily under a different URI."},
{303, "The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource."},
{304, "The request has been fulfilled and the requested resource has not been modified."},
{305, "The requested resource MUST be accessed through the proxy given by the Location field."},
{307, "The requested resource resides temporarily under a different URI."},
{308, "The requested resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs."},
{400, "The request could not be understood by the server due to malformed syntax."},
{401, "The request requires user authentication."},
{403, "The server understood the request, but is refusing to fulfill it."},
@ -109,7 +145,7 @@ http_error_msg http_error_messages[] = {
{413, "The server is refusing to process a request because the request entity is larger than the server is willing or able to process."},
{414, "The server is refusing to service the request because the Request-URI is longer than the server is willing to interpret."},
{415, "The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method."},
{416, "None of the ranges in the request's Range header field overlap the current extent of the selected resource or that the set of ranges requested has been rejected due to invalid ranges or an excessive request of small or overlapping ranges."},
{416, "None of the ranges in the requests Range header field overlap the current extent of the selected resource or that the set of ranges requested has been rejected due to invalid ranges or an excessive request of small or overlapping ranges."},
{417, "The expectation given in an Expect request-header field could not be met by this server, or, if the server is a proxy, the server has unambiguous evidence that the request could not be met by the next-hop server."},
{500, "The server encountered an unexpected condition which prevented it from fulfilling the request."},
@ -120,7 +156,7 @@ http_error_msg http_error_messages[] = {
{505, "The server does not support, or refuses to support, the HTTP protocol version that was used in the request message."}
};
const char *http_default_document =
static const char http_default_document[] =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
@ -130,12 +166,13 @@ const char *http_default_document =
"\t<meta name=\"color-scheme\" content=\"light dark\"/>\n"
"\t<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\"/>\n"
"\t<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\"/>\n"
"\t<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/favicon.ico\"/>\n"
"%5$s"
"\t<style>\n"
"\t\thtml{font-family:\"Arial\",sans-serif;--error:#C00000;--info:#E0C000;--color:var(--%4$s);}\n"
"\t\tbody{background-color:#F0F0F0;margin:0.5em;}\n"
"\t\thtml{font-family:\"Arial\",sans-serif;--error:" HTTP_COLOR_ERROR ";--warning:" HTTP_COLOR_WARNING ";--success:" HTTP_COLOR_SUCCESS ";--info:" HTTP_COLOR_INFO ";--color:var(--%4$s);}\n"
"\t\tbody{background-color:#F0F0F0;margin:0;}\n"
"\t\tmain{max-width:650px;margin:2em auto;}\n"
"\t\tsection{margin:1em;background-color:#FFFFFF;border: 1px solid var(--color);border-radius:4px;padding:1em 2em;}\n"
"\t\tsection{margin:1em;background-color:#FFFFFF;border: 1px solid var(--color);border-radius:4px;padding:1em;}\n"
"\t\th1,h2,h3,h4,h5,h6,h7{text-align:center;color:var(--color);font-weight:normal;}\n"
"\t\th1{font-size:3em;margin:0.125em 0 0.125em 0;}\n"
"\t\th2{font-size:1.5em;margin:0.25em 0 1em 0;}\n"
@ -153,25 +190,64 @@ const char *http_default_document =
"\t<main>\n"
"\t\t<section>\n"
"%3$s"
"\t\t\t<div class=\"footer\"><a href=\"https://%7$s/\">%7$s</a> - Necronda web server " NECRONDA_VERSION "</div>\n"
"\t\t\t<div class=\"footer\"><a href=\"https://%7$s/\">%7$s</a> - Necronda&nbsp;web&nbsp;server&nbsp;" NECRONDA_VERSION "</div>\n"
"\t\t</section>\n"
"\t</main>\n"
"</body>\n"
"</html>\n";
const char *http_error_document =
static const char http_error_document[] =
"\t\t\t<h1>%1$i</h1>\n"
"\t\t\t<h2>%2$s :&#xFEFF;(</h2>\n"
"\t\t\t<p>%3$s</p>\n"
"\t\t\t<p>%4$s</p>\n";
const char *http_error_icon =
"\t<link rel=\"shortcut icon\" type=\"image/svg+xml\" sizes=\"any\" href=\"data:image/svg+xml;base64,"
static const char http_error_icon[] =
"\t<link rel=\"alternate icon\" type=\"image/svg+xml\" sizes=\"any\" href=\"data:image/svg+xml;base64,"
"PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAw"
"L3N2ZyI+PHRleHQgeD0iNCIgeT0iMTIiIGZpbGw9IiNDMDAwMDAiIHN0eWxlPSJmb250LWZhbWls"
"eTonQXJpYWwnLHNhbnMtc2VyaWYiPjooPC90ZXh0Pjwvc3ZnPgo=\"/>\n";
static const char http_warning_document[] =
"\t\t\t<h1>%1$i</h1>\n"
"\t\t\t<h2>%2$s :&#xFEFF;o</h2>\n"
"\t\t\t<p>%3$s</p>\n"
"\t\t\t<p>%4$s</p>\n";
static const char http_warning_icon[] =
"\t<link rel=\"alternate icon\" type=\"image/svg+xml\" sizes=\"any\" href=\"data:image/svg+xml;base64,"
"PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAw"
"L3N2ZyI+PHRleHQgeD0iNCIgeT0iMTIiIGZpbGw9IiNFMEMwMDAiIHN0eWxlPSJmb250LWZhbWls"
"eTonQXJpYWwnLHNhbnMtc2VyaWYiPjpvPC90ZXh0Pjwvc3ZnPgo=\"/>\n";
static const char http_success_document[] =
"\t\t\t<h1>%1$i</h1>\n"
"\t\t\t<h2>%2$s :&#xFEFF;)</h2>\n"
"\t\t\t<p>%3$s</p>\n"
"\t\t\t<p>%4$s</p>\n";
static const char http_success_icon[] =
"\t<link rel=\"alternate icon\" type=\"image/svg+xml\" sizes=\"any\" href=\"data:image/svg+xml;base64,"
"PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAw"
"L3N2ZyI+PHRleHQgeD0iNCIgeT0iMTIiIGZpbGw9IiMwMDgwMDAiIHN0eWxlPSJmb250LWZhbWls"
"eTonQXJpYWwnLHNhbnMtc2VyaWYiPjopPC90ZXh0Pjwvc3ZnPgo=\"/>\n";
static const char http_info_document[] =
"\t\t\t<h1>%1$i</h1>\n"
"\t\t\t<h2>%2$s :&#xFEFF;)</h2>\n"
"\t\t\t<p>%3$s</p>\n"
"\t\t\t<p>%4$s</p>\n";
static const char http_info_icon[] =
"\t<link rel=\"alternate icon\" type=\"image/svg+xml\" sizes=\"any\" href=\"data:image/svg+xml;base64,"
"PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAw"
"L3N2ZyI+PHRleHQgeD0iNCIgeT0iMTIiIGZpbGw9IiM2MDYwNjAiIHN0eWxlPSJmb250LWZhbWls"
"eTonQXJpYWwnLHNhbnMtc2VyaWYiPjopPC90ZXh0Pjwvc3ZnPgo=\"/>\n";
void http_to_camel_case(char *str, int mode);
void http_free_hdr(http_hdr *hdr);
@ -194,14 +270,16 @@ int http_send_response(sock *client, http_res *res);
int http_send_request(sock *server, http_req *req);
http_status *http_get_status(unsigned short status_code);
const http_status *http_get_status(unsigned short status_code);
http_error_msg *http_get_error_msg(unsigned short status_code);
const http_status_msg *http_get_error_msg(const http_status *status);
const char *http_get_status_color(http_status *status);
const char *http_get_status_color(const http_status *status);
char *http_format_date(time_t time, char *buf, size_t size);
char *http_get_date(char *buf, size_t size);
const http_doc_info *http_get_status_info(const http_status *status);
#endif //NECRONDA_SERVER_HTTP_H

View File

@ -60,7 +60,7 @@
#define HTTP_4XX_STR "\x1B[1;31m"
#define HTTP_5XX_STR "\x1B[1;31m"
#define NECRONDA_VERSION "4.2"
#define NECRONDA_VERSION "4.3"
#define SERVER_STR "Necronda/" NECRONDA_VERSION
#define NECRONDA_ZLIB_LEVEL 9

View File

@ -11,9 +11,134 @@ sock rev_proxy;
char *rev_proxy_host = NULL;
struct timeval server_timeout = {.tv_sec = SERVER_TIMEOUT, .tv_usec = 0};
int rev_proxy_request_header(http_req *req, int enc) {
char buf1[256];
char buf2[256];
int p_len;
http_remove_header_field(&req->hdr, "Connection", HTTP_REMOVE_ALL);
http_add_header_field(&req->hdr, "Connection", "keep-alive");
char *via = http_get_header_field(&req->hdr, "Via");
sprintf(buf1, "HTTP/%s %s", req->version, DEFAULT_HOST);
if (via == NULL) {
http_add_header_field(&req->hdr, "Via", buf1);
} else {
p_len = snprintf(buf2, sizeof(buf2), "%s, %s", via, buf1);
if (p_len < 0 || p_len >= sizeof(buf2)) {
print(ERR_STR "Header field 'Via' too long" CLR_STR);
return -1;
}
http_remove_header_field(&req->hdr, "Via", HTTP_REMOVE_ALL);
http_add_header_field(&req->hdr, "Via", buf2);
}
char *host = http_get_header_field(&req->hdr, "Host");
char *forwarded = http_get_header_field(&req->hdr, "Forwarded");
int client_ipv6 = strchr(client_addr_str, ':') != NULL;
int server_ipv6 = strchr(server_addr_str, ':') != NULL;
p_len = snprintf(buf1, sizeof(buf1), "by=%s%s%s;for=%s%s%s;host=%s;proto=%s",
server_ipv6 ? "\"[" : "", server_addr_str, server_ipv6 ? "]\"" : "",
client_ipv6 ? "\"[" : "", client_addr_str, client_ipv6 ? "]\"" : "",
host, enc ? "https" : "http");
if (p_len < 0 || p_len >= sizeof(buf1)) {
print(ERR_STR "Appended part of header field 'Forwarded' too long" CLR_STR);
return -1;
}
if (forwarded == NULL) {
http_add_header_field(&req->hdr, "Forwarded", buf1);
} else {
p_len = snprintf(buf2, sizeof(buf2), "%s, %s", forwarded, buf1);
if (p_len < 0 || p_len >= sizeof(buf2)) {
print(ERR_STR "Header field 'Forwarded' too long" CLR_STR);
return -1;
}
http_remove_header_field(&req->hdr, "Forwarded", HTTP_REMOVE_ALL);
http_add_header_field(&req->hdr, "Forwarded", buf2);
}
char *xff = http_get_header_field(&req->hdr, "X-Forwarded-For");
if (xff == NULL) {
http_add_header_field(&req->hdr, "X-Forwarded-For", client_addr_str);
} else {
sprintf(buf1, "%s, %s", xff, client_addr_str);
http_remove_header_field(&req->hdr, "X-Forwarded-For", HTTP_REMOVE_ALL);
http_add_header_field(&req->hdr, "X-Forwarded-For", buf1);
}
char *xfh = http_get_header_field(&req->hdr, "X-Forwarded-Host");
if (xfh == NULL) {
if (forwarded == NULL) {
http_add_header_field(&req->hdr, "X-Forwarded-Host", host);
} else {
char *ptr = strchr(forwarded, ',');
unsigned long len;
if (ptr != NULL) len = ptr - forwarded;
else len = strlen(forwarded);
ptr = strstr(forwarded, "host=");
if ((ptr - forwarded) < len) {
char *end = strchr(ptr, ';');
if (end == NULL) len -= (ptr - forwarded);
else len = (end - ptr);
len -= 5;
sprintf(buf1, "%.*s", (int) len, ptr + 5);
http_add_header_field(&req->hdr, "X-Forwarded-Host", buf1);
}
}
}
char *xfp = http_get_header_field(&req->hdr, "X-Forwarded-Proto");
if (xfp == NULL) {
if (forwarded == NULL) {
http_add_header_field(&req->hdr, "X-Forwarded-Proto", enc ? "https" : "http");
} else {
char *ptr = strchr(forwarded, ',');
unsigned long len;
if (ptr != NULL) len = ptr - forwarded;
else len = strlen(forwarded);
ptr = strstr(forwarded, "proto=");
if ((ptr - forwarded) < len) {
char *end = strchr(ptr, ';');
if (end == NULL) len -= (ptr - forwarded);
else len = (end - ptr);
len -= 6;
sprintf(buf1, "%.*s", (int) len, ptr + 6);
http_add_header_field(&req->hdr, "X-Forwarded-Proto", buf1);
}
}
}
return 0;
}
int rev_proxy_response_header(http_req *req, http_res *res) {
char buf1[256];
char buf2[256];
int p_len;
char *via = http_get_header_field(&res->hdr, "Via");
p_len = snprintf(buf1, sizeof(buf1), "HTTP/%s %s", req->version, DEFAULT_HOST);
if (p_len < 0 || p_len >= sizeof(buf1)) {
print(ERR_STR "Appended part of header field 'Via' too long" CLR_STR);
return -1;
}
if (via == NULL) {
http_add_header_field(&res->hdr, "Via", buf1);
} else {
p_len = snprintf(buf2, sizeof(buf2), "%s, %s", via, buf1);
if (p_len < 0 || p_len >= sizeof(buf2)) {
print(ERR_STR "Header field 'Via' too long" CLR_STR);
return -1;
}
http_remove_header_field(&res->hdr, "Via", HTTP_REMOVE_ALL);
http_add_header_field(&res->hdr, "Via", buf2);
}
return 0;
}
int rev_proxy_init(http_req *req, http_res *res, host_config *conf, sock *client, http_status *custom_status,
char * err_msg) {
char *err_msg) {
char buffer[CHUNK_SIZE];
long ret;
int tries = 0;
@ -97,10 +222,11 @@ int rev_proxy_init(http_req *req, http_res *res, host_config *conf, sock *client
print(BLUE_STR "Established new connection with " BLD_STR "[%s]:%i" CLR_STR, buffer, conf->rev_proxy.port);
rev_proxy:
http_remove_header_field(&req->hdr, "Connection", HTTP_REMOVE_ALL);
http_add_header_field(&req->hdr, "Connection", "keep-alive");
http_remove_header_field(&req->hdr, "X-Forwarded-For", HTTP_REMOVE_ALL);
http_add_header_field(&req->hdr, "X-Forwarded-For", client_addr_str);
ret = rev_proxy_request_header(req, (int) client->enc);
if (ret != 0) {
res->status = http_get_status(500);
return -1;
}
ret = http_send_request(&rev_proxy, req);
if (ret < 0) {
@ -222,6 +348,12 @@ int rev_proxy_init(http_req *req, http_res *res, host_config *conf, sock *client
}
sock_recv(&rev_proxy, buffer, header_len, 0);
ret = rev_proxy_response_header(req, res);
if (ret != 0) {
res->status = http_get_status(500);
return -1;
}
return 0;
proxy_err:

View File

@ -8,4 +8,13 @@
#ifndef NECRONDA_SERVER_REV_PROXY_H
#define NECRONDA_SERVER_REV_PROXY_H
int rev_proxy_request_header(http_req *req, int enc);
int rev_proxy_response_header(http_req *req, http_res *res);
int rev_proxy_init(http_req *req, http_res *res, host_config *conf, sock *client, http_status *custom_status,
char *err_msg);
int rev_proxy_send(sock *client, int chunked, unsigned long len_to_send);
#endif //NECRONDA_SERVER_REV_PROXY_H

View File

@ -81,7 +81,7 @@ long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigne
next_len = (buf_len < (len - send_len)) ? buf_len : (len - send_len);
ret = sock_recv(src, buf, next_len, 0);
if (ret < 0) return -2;
if (ret != next_len) return -3;
next_len = ret;
ret = sock_send(dst, buf, next_len, send_len + next_len < len ? MSG_MORE : 0);
if (ret < 0) return -1;
if (ret != next_len) return -3;

View File

@ -8,6 +8,13 @@
#ifndef NECRONDA_SERVER_SOCK_H
#define NECRONDA_SERVER_SOCK_H
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/dh.h>
typedef struct {
unsigned int enc:1;
int socket;

View File

@ -28,6 +28,7 @@ int uri_init(http_uri *uri, const char *webroot, const char *uri_str, int dir_mo
char buf1[1024];
char buf2[1024];
char buf3[1024];
int p_len;
uri->webroot = NULL;
uri->req_path = NULL;
uri->path = NULL;
@ -89,10 +90,17 @@ int uri_init(http_uri *uri, const char *webroot, const char *uri_str, int dir_mo
} else {
strcpy(uri->pathinfo, "");
}
if (!path_exists(uri->webroot)) {
return 3;
}
while (1) {
sprintf(buf0, "%s%s", uri->webroot, uri->path);
sprintf(buf1, "%s.php", buf0);
sprintf(buf2, "%s.html", buf0);
p_len = snprintf(buf1, sizeof(buf1), "%s.php", buf0);
if (p_len < 0 || p_len >= sizeof(buf1)) return -1;
p_len = snprintf(buf2, sizeof(buf2), "%s.html", buf0);
if (p_len < 0 || p_len >= sizeof(buf2)) return -1;
if (strlen(uri->path) <= 1 || path_exists(buf0) || path_is_file(buf1) || path_is_file(buf2)) {
break;

View File

@ -8,13 +8,14 @@
#ifndef NECRONDA_SERVER_URI_H
#define NECRONDA_SERVER_URI_H
#include <sys/stat.h>
#define URI_DIR_MODE_NO_VALIDATION 0
#define URI_DIR_MODE_FORBIDDEN 1
#define URI_DIR_MODE_LIST 2
#define URI_DIR_MODE_INFO 3
#include <sys/stat.h>
typedef struct {
char etag[64];
char type[24];

View File

@ -7,6 +7,7 @@
#include "utils.h"
char *format_duration(unsigned long micros, char *buf) {
if (micros < 10000) {
sprintf(buf, "%.1f ms", (double) micros / 1000);
@ -22,7 +23,7 @@ char *format_duration(unsigned long micros, char *buf) {
return buf;
}
int url_encode(const char *str, char *enc, ssize_t *size) {
int url_encode_component(const char *str, char *enc, ssize_t *size) {
char *ptr = enc;
char ch;
memset(enc, 0, *size);
@ -49,7 +50,7 @@ int url_encode(const char *str, char *enc, ssize_t *size) {
return 0;
}
int encode_url(const char *str, char *enc, ssize_t *size) {
int url_encode(const char *str, char *enc, ssize_t *size) {
char *ptr = enc;
unsigned char ch;
memset(enc, 0, *size);
@ -88,6 +89,9 @@ int url_decode(const char *str, char *dec, ssize_t *size) {
buf[2] = 0;
ch = (char) strtol(buf, NULL, 16);
i += 2;
} else if (ch == '?') {
strcpy(ptr, str + i);
break;
}
ptr[0] = ch;
}
@ -116,7 +120,7 @@ MMDB_entry_data_list_s *mmdb_json(MMDB_entry_data_list_s *list, char *str, long
*str_off += sprintf(str + *str_off, "%lu", list->entry_data.uint64);
break;
case MMDB_DATA_TYPE_UINT128:
*str_off += sprintf(str + *str_off, "%llu", list->entry_data.uint128);
*str_off += sprintf(str + *str_off, "%llu", (unsigned long long) list->entry_data.uint128);
break;
case MMDB_DATA_TYPE_INT32:
*str_off += sprintf(str + *str_off, "%i", list->entry_data.uint32);

View File

@ -22,9 +22,9 @@ char *log_prefix;
char *format_duration(unsigned long micros, char *buf);
int url_encode(const char *str, char *enc, ssize_t *size);
int url_encode_component(const char *str, char *enc, ssize_t *size);
int encode_url(const char *str, char *enc, ssize_t *size);
int url_encode(const char *str, char *enc, ssize_t *size);
int url_decode(const char *str, char *dec, ssize_t *size);