ohmu
·
2026-10-15
1#include "common/networking.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7static void verify(bool expression, const char* expressionStr, int lineNo) {
8 if (expression) {
9 return;
10 }
11
12 fprintf(stderr, "[%d] %s\n", lineNo, expressionStr);
13 exit(1);
14}
15
16#define VERIFY(expression) verify((expression), #expression, __LINE__)
17
18static FFNetworkingTransferEncoding parse(const char* value) {
19 return ffNetworkingParseTransferEncoding(value, (uint32_t) strlen(value));
20}
21
22int main(void) {
23 {
24 VERIFY(parse("chunked") == FF_NETWORKING_TE_CHUNKED);
25 VERIFY(parse("Chunked") == FF_NETWORKING_TE_CHUNKED);
26 VERIFY(parse(" chunked ") == FF_NETWORKING_TE_CHUNKED);
27 VERIFY(parse("chunked\t") == FF_NETWORKING_TE_CHUNKED);
28
29 // A coding chain leaves the payload encoded, so only a lone `chunked` is decodable
30 VERIFY(parse("gzip, chunked") == FF_NETWORKING_TE_UNSUPPORTED);
31 VERIFY(parse("gzip,chunked") == FF_NETWORKING_TE_UNSUPPORTED);
32 VERIFY(parse("chunked, gzip") == FF_NETWORKING_TE_UNSUPPORTED);
33 VERIFY(parse("gzip") == FF_NETWORKING_TE_UNSUPPORTED);
34 VERIFY(parse("x-chunked") == FF_NETWORKING_TE_UNSUPPORTED);
35 VERIFY(parse("chunkedx") == FF_NETWORKING_TE_UNSUPPORTED);
36
37 VERIFY(parse("") == FF_NETWORKING_TE_NONE);
38 VERIFY(parse(" , ") == FF_NETWORKING_TE_NONE);
39 }
40
41 {
42 // The lookup is restricted to the header block, so a body that happens to contain a
43 // `Transfer-Encoding:` line can never be mistaken for a header
44 const char* response = "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nTransfer-Encoding: chunked\r\n";
45 uint32_t headerEnd = (uint32_t) (strstr(response, "\r\n\r\n") - response);
46 uint32_t valueLen = 0;
47
48 VERIFY(ffNetworkingFindHeader(response, headerEnd, "Transfer-Encoding:", &valueLen) == nullptr);
49
50 const char* clHeader = ffNetworkingFindHeader(response, headerEnd, "Content-Length:", &valueLen);
51 VERIFY(clHeader != nullptr && valueLen == 1 && *clHeader == '4');
52 }
53
54 {
55 uint32_t consumed = 0;
56 const char* complete = "5\r\nhello\r\n0\r\n\r\n";
57 VERIFY(ffNetworkingChunkedComplete(complete, (uint32_t) strlen(complete), &consumed) == 1);
58 VERIFY(consumed == strlen(complete));
59
60 const char* withTrailer = "5\r\nhello\r\n0\r\nX-Foo: bar\r\n\r\n";
61 VERIFY(ffNetworkingChunkedComplete(withTrailer, (uint32_t) strlen(withTrailer), &consumed) == 1);
62 VERIFY(consumed == strlen(withTrailer));
63
64 const char* partial = "5\r\nhel";
65 VERIFY(ffNetworkingChunkedComplete(partial, (uint32_t) strlen(partial), &consumed) == 0);
66
67 const char* malformed = "5\r\nhelloXX0\r\n\r\n";
68 VERIFY(ffNetworkingChunkedComplete(malformed, (uint32_t) strlen(malformed), &consumed) == -1);
69 }
70
71 {
72 // Decoding replaces the framing header with a matching Content-Length
73 FFstrbuf response = ffStrbufCreateS("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n");
74 uint32_t headerEnd = (uint32_t) (strstr(response.chars, "\r\n\r\n") - response.chars);
75
76 VERIFY(ffNetworkingDecodeChunked(&response, &headerEnd));
77 VERIFY(headerEnd == (uint32_t) (strstr(response.chars, "\r\n\r\n") - response.chars));
78 VERIFY(ffStrbufContainS(&response, "Content-Length: 5"));
79 VERIFY(!ffStrbufContainS(&response, "Transfer-Encoding"));
80 VERIFY(ffStrbufEndsWithS(&response, "hello"));
81
82 ffStrbufDestroy(&response);
83 }
84
85 puts("All networking tests passed!");
86 return 0;
87}