--- /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); + } +}