Fri, 06 Feb 2026 14:06:04 +0100
refactor HttpParser to support parsing of Http responses
--- a/src/server/Makefile Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/Makefile Fri Feb 06 14:06:04 2026 +0100 @@ -44,6 +44,7 @@ include webdav/objs.mk include daemon/objs.mk include config/objs.mk +include proxy/objs.mk include admin/objs.mk include test/objs.mk @@ -52,14 +53,15 @@ include webdav/Makefile include daemon/Makefile include config/Makefile +include proxy/Makefile include admin/Makefile include test/Makefile -MAINOBJS = $(UTILOBJS) $(SAFOBJS) $(DAVOBJS) $(DAEMONOBJS) $(CONFOBJS) $(ADMINOBJS) +MAINOBJS = $(UTILOBJS) $(SAFOBJS) $(DAVOBJS) $(DAEMONOBJS) $(CONFOBJS) $(PROXYOBJS) $(ADMINOBJS) TESTOBJS += $(MAINOBJS) -OBJ_DIRS = daemon safs ucx util webdav config admin plugins test +OBJ_DIRS = daemon safs ucx util webdav config proxy admin plugins test MK_OBJ_DIRS = $(OBJ_DIRS:%=$(OBJ_DIR)server/%) WS_CFLAGS = -I../ucx/
--- a/src/server/daemon/httpparser.c Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/daemon/httpparser.c Fri Feb 06 14:06:04 2026 +0100 @@ -35,11 +35,17 @@ HttpParser* http_parser_new(HTTPRequest *request) { + return http_parser_new2(0, request->netbuf, request->headers); +} + +HttpParser* http_parser_new2(int type, netbuf *netbuf, HeaderArray *headers) { HttpParser *parser = calloc(1, sizeof(HttpParser)); - parser->request = request; + parser->type = type; + parser->netbuf = netbuf; + parser->headers = headers; parser->state = 0; - parser->start_line.ptr = (char*)request->netbuf->inbuf; + parser->start_line.ptr = (char*)netbuf->inbuf; parser->start_line.length = 0; parser->offset = 0; @@ -51,6 +57,12 @@ free(parser); } +void http_parser_update_request(HttpParser *parser, HTTPRequest *request) { + request->method = parser->method; + request->uri = parser->uri; + request->httpv = parser->httpv; +} + int http_parser_process(HttpParser *parser) { switch(parser->state) { case 0: { @@ -59,7 +71,16 @@ case 0: break; default: return r; } - parse_request_line(parser); + if(parser->type == 0) { + if(parse_request_line(parser)) { + return 2; + } + } else { + if(parse_response_line(parser)) { + return 2; + } + } + parser->state++; } case 1: { @@ -73,19 +94,27 @@ } int http_parser_validate(HttpParser *parser) { - HTTPRequest *req = parser->request; - if( - !req->method.ptr || req->method.length == 0 - || !req->uri.ptr || req->uri.length == 0 - || !req->httpv.ptr || req->httpv.length == 0) - { - return 0; + if(parser->type == 0) { + if (!parser->method.ptr || parser->method.length == 0 + || !parser->uri.ptr || parser->uri.length == 0 + || !parser->httpv.ptr || parser->httpv.length == 0) + { + return 0; + } + } else { + if (!parser->httpv.ptr || parser->httpv.length == 0 + || !parser->msg.ptr || parser->msg.length == 0 + || parser->status == 0) + { + return 0; + } } + return 1; } int get_start_line(HttpParser *parser) { - netbuf *buf = parser->request->netbuf; + netbuf *buf = parser->netbuf; while(buf->pos < buf->cursize) { unsigned char c = buf->inbuf[buf->pos]; if(c == '\n') { @@ -115,7 +144,7 @@ } int http_parser_parse_header(HttpParser *parser) { - netbuf *buf = parser->request->netbuf; + netbuf *buf = parser->netbuf; parser->offset = buf->pos; // line offset parser->name.ptr = NULL; @@ -154,8 +183,8 @@ parser->value.ptr = ""; } // add header - header_add( - parser->request->headers, + header_array_add( + parser->headers, parser->name, parser->value); } else { @@ -174,54 +203,117 @@ int parse_request_line(HttpParser *parser) { cxmutstr line = parser->start_line; - parser->request->request_line = line; - /* - * parse method, url and http version - */ + // parse method, url and http version int i = 0; int ns = 0; - parser->request->method.ptr = line.ptr; + parser->method.ptr = line.ptr; for(;i<line.length;i++) { if(!ns && line.ptr[i] == ' ') { ns = 1; - parser->request->method.length = i; + parser->method.length = i; } else if(ns) { if(line.ptr[i] != ' ') { break; } } } + if(i == line.length) { + return 1; + } - parser->request->uri.ptr = line.ptr + i; + parser->uri.ptr = line.ptr + i; ns = 0; int s = i; for(;i<line.length;i++) { if(!ns && isspace(line.ptr[i])) { ns = 1; - parser->request->uri.length = i - s; + parser->uri.length = i - s; } else if(ns) { if(line.ptr[i] > 32) { break; } } } + if(i == line.length) { + return 1; + } - parser->request->httpv.ptr = line.ptr + i; + parser->httpv.ptr = line.ptr + i; ns = 0; s = i; for(;i<line.length;i++) { if(!ns && isspace(line.ptr[i])) { ns = 1; - parser->request->httpv.length = i - s; + parser->httpv.length = i - s; + } else if(ns) { + if(line.ptr[i] > 32) { + return 1; // non-whitespace char after httpv + } + } + } + + return 0; +} + +int parse_response_line(HttpParser *parser) { + cxmutstr line = parser->start_line; + + // parse http version, status num, status message + + int i = 0; + int ns = 0; + + parser->httpv.ptr = line.ptr; + for(;i<line.length;i++) { + if(!ns && line.ptr[i] == ' ') { + ns = 1; + parser->httpv.length = i; + } else if(ns) { + if(line.ptr[i] != ' ') { + break; + } + } + } + + ns = 0; + int s = i; + cxmutstr num_str; + num_str.ptr = line.ptr + i; + num_str.length = 0; + for(;i<line.length;i++) { + if(!ns && isspace(line.ptr[i])) { + ns = 1; + num_str.length = i - s; } else if(ns) { if(line.ptr[i] > 32) { break; } } } - + + if(num_str.length != 3) { + return 1; + } + if(cx_strtoi(num_str, &parser->status, 10)) { + return 1; + } + + parser->msg.ptr = line.ptr + i; + ns = 1; + s = i; + for(;i<line.length;i++) { + char c = line.ptr[i]; + if(ns && c < 33) { + parser->msg.length = i - s; + ns = 0; + } else { + ns = 1; + } + } + return 0; } +
--- a/src/server/daemon/httpparser.h Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/daemon/httpparser.h Fri Feb 06 14:06:04 2026 +0100 @@ -37,19 +37,37 @@ extern "C" { #endif -/* - * http parser states - * - * 0: start line - * 1: header - * 2: finish - */ - + typedef struct _http_parser { - HTTPRequest *request; - + /* + * http parser type + * + * 0: request + * 1: response + */ + int type; + + /* + * http parser states + * + * 0: start line + * 1: header + * 2: finish + */ int state; + + /* + * first line (request/response line) + */ cxmutstr start_line; + + netbuf *netbuf; + HeaderArray *headers; + cxmutstr method; + cxmutstr uri; + cxmutstr httpv; + cxmutstr msg; + int status; /* local parser variables */ int wl; /* only white space */ @@ -62,9 +80,15 @@ } HttpParser; HttpParser* http_parser_new(HTTPRequest *request); +HttpParser* http_parser_new2(int type, netbuf *netbuf, HeaderArray *headers); void http_parser_free(HttpParser *parser); /* + * updates method, uri and httpv in an HTTPRequest object + */ +void http_parser_update_request(HttpParser *parser, HTTPRequest *request); + +/* * process http parsing * * return @@ -80,7 +104,7 @@ int http_parser_parse_header(HttpParser *parser); int parse_request_line(HttpParser *parser); - +int parse_response_line(HttpParser *parser); #ifdef __cplusplus
--- a/src/server/daemon/httprequest.c Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/daemon/httprequest.c Fri Feb 06 14:06:04 2026 +0100 @@ -471,15 +471,26 @@ } +HeaderArray* header_array_create(void) { + HeaderArray *array = malloc(sizeof(HeaderArray)); + if(!array) { + return NULL; + } + array->next = NULL; + array->len = 0; + array->alloc = 16; + array->headers = calloc(16, sizeof(Header)); + if(array->headers) { + free(array); + return NULL; + } + return array; +} -void header_add(HeaderArray *hd, cxmutstr name, cxmutstr value) { +void header_array_add(HeaderArray *hd, cxmutstr name, cxmutstr value) { while(hd->len >= hd->alloc) { if(hd->next == NULL) { - HeaderArray *block = malloc(sizeof(HeaderArray)); - block->next = NULL; - block->len = 0; - block->headers = calloc(16, sizeof(Header)); - block->alloc = 16; + HeaderArray *block = header_array_create(); hd->next = block; } hd = hd->next;
--- a/src/server/daemon/httprequest.h Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/daemon/httprequest.h Fri Feb 06 14:06:04 2026 +0100 @@ -93,7 +93,8 @@ pool_handle_t *pool); -void header_add(HeaderArray *hd, cxmutstr name, cxmutstr value); +HeaderArray* header_array_create(void); +void header_array_add(HeaderArray *hd, cxmutstr name, cxmutstr value); void header_array_free(HeaderArray *hd); int nsapi_handle_request(NSAPISession *sn, NSAPIRequest *rq);
--- a/src/server/daemon/sessionhandler.c Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/daemon/sessionhandler.c Fri Feb 06 14:06:04 2026 +0100 @@ -188,6 +188,7 @@ if(!err) { if(http_parser_validate(parser)) { + http_parser_update_request(parser, request); // process request r = handle_request(request, NULL, NULL); // TODO: use correct thread pool } else { @@ -506,6 +507,7 @@ event->finish = evt_request_error; return 0; } + http_parser_update_request(parser, request); /* * process request
--- a/src/server/daemon/ws-fn.c Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/daemon/ws-fn.c Fri Feb 06 14:06:04 2026 +0100 @@ -39,6 +39,7 @@ #include "../safs/addlog.h" #include "../safs/cgi.h" #include "../safs/ldap.h" +#include "../safs/proxy.h" #include "../webdav/webdav.h" #include "../admin/admin.h" @@ -77,5 +78,6 @@ { "ldap-search", service_ldap_search, NULL, NULL, 0}, { "webdav-init", webdav_init, NULL, NULL, 0}, { "webdav-service", webdav_service, NULL, NULL, 0}, + { "reverse-proxy-service", http_reverse_proxy_service, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, 0} };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/proxy/Makefile Fri Feb 06 14:06:04 2026 +0100 @@ -0,0 +1,33 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2026 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +PROXY_CFLAGS = + +$(PROXY_OBJPRE)%.o: proxy/%.c + $(CC) -o $@ -c $(WS_CFLAGS) $(PROXY_CFLAGS) $(CFLAGS) $< +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/proxy/httpclient.c Fri Feb 06 14:06:04 2026 +0100 @@ -0,0 +1,5 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/cFiles/file.c to edit this template + */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/proxy/httpclient.h Fri Feb 06 14:06:04 2026 +0100 @@ -0,0 +1,46 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PROXY_HTTPCLIENT_H +#define PROXY_HTTPCLIENT_H + +#include "../public/nsapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* PROXY_HTTPCLIENT_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/proxy/objs.mk Fri Feb 06 14:06:04 2026 +0100 @@ -0,0 +1,37 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2026 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +PROXY_SRC_DIR = server/proxy/ + +PROXY_OBJPRE = $(OBJ_DIR)$(PROXY_SRC_DIR) + +PROXYOBJ = httpclient.o + +PROXYOBJS = $(PROXYOBJ:%=$(PROXY_OBJPRE)%) +PROXYSOURCE = $(PROXYOBJ:%.o=proxy/%.c) +
--- a/src/server/safs/objs.mk Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/safs/objs.mk Fri Feb 06 14:06:04 2026 +0100 @@ -42,6 +42,7 @@ SAFOBJ += cgi.o SAFOBJ += cgiutils.o SAFOBJ += ldap.o +SAFOBJ += proxy.o SAFOBJS = $(SAFOBJ:%=$(SAFS_OBJPRE)%) SAFSOURCE = $(SAFOBJ:%.o=safs/%.c)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/safs/proxy.c Fri Feb 06 14:06:04 2026 +0100 @@ -0,0 +1,37 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "proxy.h" + +#include "../util/pblock.h" + +int http_reverse_proxy_service(pblock *param, Session *sn, Request *rq) { + + + return REQ_ABORTED; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/safs/proxy.h Fri Feb 06 14:06:04 2026 +0100 @@ -0,0 +1,46 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SAF_PROXY_H +#define SAF_PROXY_H + +#include "../public/nsapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int http_reverse_proxy_service(pblock *param, Session *sn, Request *rq); + + +#ifdef __cplusplus +} +#endif + +#endif /* SAF_PROXY_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/test/httpparser.c Fri Feb 06 14:06:04 2026 +0100 @@ -0,0 +1,136 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "httpparser.h" + +#include "../daemon/httpparser.h" + +CX_TEST(test_parse_request_line) { + CX_TEST_DO { + HttpParser parser; + memset(&parser, 0, sizeof(HttpParser)); + parser.start_line = cx_mutstr("GET / HTTP/1.1\r\n"); + + int ret1 = parse_request_line(&parser); + CX_TEST_ASSERT(!ret1); + CX_TEST_ASSERT(!cx_strcmp(parser.method, "GET")); + CX_TEST_ASSERT(!cx_strcmp(parser.uri, "/")); + CX_TEST_ASSERT(!cx_strcmp(parser.httpv, "HTTP/1.1")); + + memset(&parser, 0, sizeof(HttpParser)); + parser.start_line = cx_mutstr("POST /longer/url/test/path/ HTTP/1.0\r\n"); + int ret2 = parse_request_line(&parser); + CX_TEST_ASSERT(!ret2); + CX_TEST_ASSERT(!cx_strcmp(parser.method, "POST")); + CX_TEST_ASSERT(!cx_strcmp(parser.uri, "/longer/url/test/path/")); + CX_TEST_ASSERT(!cx_strcmp(parser.httpv, "HTTP/1.0")); + + memset(&parser, 0, sizeof(HttpParser)); + parser.start_line = cx_mutstr("G / v\r\n"); + int ret3 = parse_request_line(&parser); + CX_TEST_ASSERT(!ret3); + CX_TEST_ASSERT(!cx_strcmp(parser.method, "G")); + CX_TEST_ASSERT(!cx_strcmp(parser.uri, "/")); + CX_TEST_ASSERT(!cx_strcmp(parser.httpv, "v")); + + memset(&parser, 0, sizeof(HttpParser)); + parser.start_line = cx_mutstr("HEAD /space HTTP/0.9 \r\n"); + int ret4 = parse_request_line(&parser); + CX_TEST_ASSERT(!ret4); + CX_TEST_ASSERT(!cx_strcmp(parser.method, "HEAD")); + CX_TEST_ASSERT(!cx_strcmp(parser.uri, "/space")); + CX_TEST_ASSERT(!cx_strcmp(parser.httpv, "HTTP/0.9")); + + // unix-style line break tests + memset(&parser, 0, sizeof(HttpParser)); + parser.start_line = cx_mutstr("PROPFIND /collection/ HTTP/1.1\n"); + int uret1 = parse_request_line(&parser); + CX_TEST_ASSERT(!uret1); + CX_TEST_ASSERT(!cx_strcmp(parser.method, "PROPFIND")); + CX_TEST_ASSERT(!cx_strcmp(parser.uri, "/collection/")); + CX_TEST_ASSERT(!cx_strcmp(parser.httpv, "HTTP/1.1")); + + // negative tests + parser.start_line = cx_mutstr("\r\n"); + int nret1 = parse_request_line(&parser); + CX_TEST_ASSERT(nret1); + + parser.start_line = cx_mutstr("GET\r\n"); + int nret2 = parse_request_line(&parser); + CX_TEST_ASSERT(nret2); + + parser.start_line = cx_mutstr("GET /test\r\n"); + int nret3 = parse_request_line(&parser); + CX_TEST_ASSERT(nret3); + + parser.start_line = cx_mutstr("GET /test \r\n"); + int nret4 = parse_request_line(&parser); + CX_TEST_ASSERT(nret4); + + parser.start_line = cx_mutstr("/test HTTP/1.1\r\n"); + int nret5 = parse_request_line(&parser); + CX_TEST_ASSERT(nret5); + + parser.start_line = cx_mutstr("GET /uri HTTP/1.1 test\r\n"); + int nret6 = parse_request_line(&parser); + CX_TEST_ASSERT(nret6); + } +} + +CX_TEST(test_parse_response_line) { + CX_TEST_DO { + HttpParser parser; + memset(&parser, 0, sizeof(HttpParser)); + parser.start_line = cx_mutstr("HTTP/1.1 200 OK\r\n"); + parser.type = 1; + + int ret1 = parse_response_line(&parser); + CX_TEST_ASSERT(!ret1); + CX_TEST_ASSERT(!cx_strcmp(parser.httpv, "HTTP/1.1")); + CX_TEST_ASSERT(!cx_strcmp(parser.msg, "OK")); + CX_TEST_ASSERT(parser.status == 200); + + memset(&parser, 0, sizeof(HttpParser)); + parser.start_line = cx_mutstr("HTTP/1.0 201 Created\r\n"); + parser.type = 1; + int ret2 = parse_response_line(&parser); + CX_TEST_ASSERT(!ret2); + CX_TEST_ASSERT(!cx_strcmp(parser.httpv, "HTTP/1.0")); + CX_TEST_ASSERT(!cx_strcmp(parser.msg, "Created")); + CX_TEST_ASSERT(parser.status == 201); + + memset(&parser, 0, sizeof(HttpParser)); + parser.start_line = cx_mutstr("HTTP/0.9 204 No Content\r\n"); + parser.type = 1; + int ret3 = parse_response_line(&parser); + CX_TEST_ASSERT(!ret3); + CX_TEST_ASSERT(!cx_strcmp(parser.httpv, "HTTP/0.9")); + CX_TEST_ASSERT(!cx_strcmp(parser.msg, "No Content")); + CX_TEST_ASSERT(parser.status == 204); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/test/httpparser.h Fri Feb 06 14:06:04 2026 +0100 @@ -0,0 +1,47 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_HTTPPARSER_H +#define TEST_HTTPPARSER_H + +#include "test.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CX_TEST(test_parse_request_line); +CX_TEST(test_parse_response_line); + + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_HTTPPARSER_H */ +
--- a/src/server/test/main.c Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/test/main.c Fri Feb 06 14:06:04 2026 +0100 @@ -42,6 +42,7 @@ #include "test.h" +#include "httpparser.h" #include "vfs.h" #include "writer.h" #include "xml.h" @@ -82,6 +83,10 @@ cx_test_register(suite, test_util_uri_escape_latin); cx_test_register(suite, test_util_uri_escape_kanji); + // httpparser tests + cx_test_register(suite, test_parse_request_line); + cx_test_register(suite, test_parse_response_line); + // event tests cx_test_register(suite, test_evhandler_create); cx_test_register(suite, test_event_send);
--- a/src/server/test/objs.mk Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/test/objs.mk Fri Feb 06 14:06:04 2026 +0100 @@ -32,6 +32,7 @@ TESTOBJ = test.o TESTOBJ += main.o +TESTOBJ += httpparser.o TESTOBJ += testutils.o TESTOBJ += webdav.o TESTOBJ += vfs.o
--- a/src/server/util/objs.mk Tue Feb 03 19:09:53 2026 +0100 +++ b/src/server/util/objs.mk Fri Feb 06 14:06:04 2026 +0100 @@ -46,13 +46,8 @@ UTILOBJ += writer.o UTILOBJ += libxattr.o UTILOBJ += hashing.o +UTILOBJ += pblock.o +UTILOBJ += uri.o UTILOBJS = $(UTILOBJ:%=$(UTIL_OBJPRE)%) UTILSOURCE = $(UTILOBJ:%.o=util/%.c) - -# add cpp files -UTILOBJS += $(UTIL_OBJPRE)pblock.o -UTILOBJS += $(UTIL_OBJPRE)uri.o - -UTILSOURCE += util/pblock.cpp -UTILSOURCE += util/uri.cpp