diff --git a/deps/picohttpparser/.clang-format b/deps/picohttpparser/.clang-format deleted file mode 100644 index 9640123c..00000000 --- a/deps/picohttpparser/.clang-format +++ /dev/null @@ -1,7 +0,0 @@ -# requires clang-format >= 3.6 -BasedOnStyle: "LLVM" -IndentWidth: 4 -ColumnLimit: 132 -BreakBeforeBraces: Linux -AllowShortFunctionsOnASingleLine: None -SortIncludes: false diff --git a/deps/picohttpparser/.gitignore b/deps/picohttpparser/.gitignore deleted file mode 100644 index 37450cbc..00000000 --- a/deps/picohttpparser/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -test-bin -xcuserdata -*.xccheckout -.DS_Store diff --git a/deps/picohttpparser/.gitmodules b/deps/picohttpparser/.gitmodules deleted file mode 100644 index e1434dac..00000000 --- a/deps/picohttpparser/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "picotest"] - path = picotest - url = https://github.com/h2o/picotest.git diff --git a/deps/picohttpparser/.travis.yml b/deps/picohttpparser/.travis.yml deleted file mode 100644 index 78af54bc..00000000 --- a/deps/picohttpparser/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: c -compiler: - - gcc - - clang -script: - - make test diff --git a/deps/picohttpparser/Jamfile b/deps/picohttpparser/Jamfile deleted file mode 100644 index 5acbe55d..00000000 --- a/deps/picohttpparser/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -project picohttpparser ; - -lib picohttpparser : picohttpparser.c ; - -unit-test test - : picohttpparser picotest/picotest.c test.c - : prove ; diff --git a/deps/picohttpparser/Makefile b/deps/picohttpparser/Makefile deleted file mode 100644 index 9e42298d..00000000 --- a/deps/picohttpparser/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, -# Shigeo Mitsunari -# -# The software is licensed under either the MIT License (below) or the Perl -# license. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. - -CC?=gcc -PROVE?=prove - -all: - -test: test-bin - $(PROVE) -v ./test-bin - -test-bin: picohttpparser.c picotest/picotest.c test.c - $(CC) -Wall $(CFLAGS) $(LDFLAGS) -o $@ $^ - -clean: - rm -f test-bin - -.PHONY: test diff --git a/deps/picohttpparser/README.md b/deps/picohttpparser/README.md deleted file mode 100644 index cb32f58e..00000000 --- a/deps/picohttpparser/README.md +++ /dev/null @@ -1,116 +0,0 @@ -PicoHTTPParser -============= - -Copyright (c) 2009-2014 [Kazuho Oku](https://github.com/kazuho), [Tokuhiro Matsuno](https://github.com/tokuhirom), [Daisuke Murase](https://github.com/typester), [Shigeo Mitsunari](https://github.com/herumi) - -PicoHTTPParser is a tiny, primitive, fast HTTP request/response parser. - -Unlike most parsers, it is stateless and does not allocate memory by itself. -All it does is accept pointer to buffer and the output structure, and setups the pointers in the latter to point at the necessary portions of the buffer. - -The code is widely deployed within Perl applications through popular modules that use it, including [Plack](https://metacpan.org/pod/Plack), [Starman](https://metacpan.org/pod/Starman), [Starlet](https://metacpan.org/pod/Starlet), [Furl](https://metacpan.org/pod/Furl). It is also the HTTP/1 parser of [H2O](https://github.com/h2o/h2o). - -Check out [test.c] to find out how to use the parser. - -The software is dual-licensed under the Perl License or the MIT License. - -Usage ------ - -The library exposes four functions: `phr_parse_request`, `phr_parse_response`, `phr_parse_headers`, `phr_decode_chunked`. - -### phr_parse_request - -The example below reads an HTTP request from socket `sock` using `read(2)`, parses it using `phr_parse_request`, and prints the details. - -```c -char buf[4096], *method, *path; -int pret, minor_version; -struct phr_header headers[100]; -size_t buflen = 0, prevbuflen = 0, method_len, path_len, num_headers; -ssize_t rret; - -while (1) { - /* read the request */ - while ((rret = read(sock, buf + buflen, sizeof(buf) - buflen)) == -1 && errno == EINTR) - ; - if (rret <= 0) - return IOError; - prevbuflen = buflen; - buflen += rret; - /* parse the request */ - num_headers = sizeof(headers) / sizeof(headers[0]); - pret = phr_parse_request(buf, buflen, &method, &method_len, &path, &path_len, - &minor_version, headers, &num_headers, prevbuflen); - if (pret > 0) - break; /* successfully parsed the request */ - else if (pret == -1) - return ParseError; - /* request is incomplete, continue the loop */ - assert(pret == -2); - if (buflen == sizeof(buf)) - return RequestIsTooLongError; -} - -printf("request is %d bytes long\n", pret); -printf("method is %.*s\n", (int)method_len, method); -printf("path is %.*s\n", (int)path_len, path); -printf("HTTP version is 1.%d\n", minor_version); -printf("headers:\n"); -for (i = 0; i != num_headers; ++i) { - printf("%.*s: %.*s\n", (int)headers[i].name_len, headers[i].name, - (int)headers[i].value_len, headers[i].value); -} -``` - -### phr_parse_response, phr_parse_headers - -`phr_parse_response` and `phr_parse_headers` provide similar interfaces as `phr_parse_request`. `phr_parse_response` parses an HTTP response, and `phr_parse_headers` parses the headers only. - -### phr_decode_chunked - -The example below decodes incoming data in chunked-encoding. The data is decoded in-place. - -```c -struct phr_chunked_decoder decoder = {}; /* zero-clear */ -char *buf = malloc(4096); -size_t size = 0, capacity = 4096, rsize; -ssize_t rret, pret; - -/* set consume_trailer to 1 to discard the trailing header, or the application - * should call phr_parse_headers to parse the trailing header */ -decoder.consume_trailer = 1; - -do { - /* expand the buffer if necessary */ - if (size == capacity) { - capacity *= 2; - buf = realloc(buf, capacity); - assert(buf != NULL); - } - /* read */ - while ((rret = read(sock, buf + size, capacity - size)) == -1 && errno == EINTR) - ; - if (rret <= 0) - return IOError; - /* decode */ - rsize = rret; - pret = phr_decode_chunked(&decoder, buf + size, &rsize); - if (pret == -1) - return ParseError; - size += rsize; -} while (pret == -2); - -/* successfully decoded the chunked data */ -assert(pret >= 0); -printf("decoded data is at %p (%zu bytes)\n", buf, size); -``` - -Benchmark ---------- - -![benchmark results](http://i.gyazo.com/a85c18d3162dfb46b485bb41e0ad443a.png) - -The benchmark code is from [fukamachi/fast-http@6b91103](https://github.com/fukamachi/fast-http/tree/6b9110347c7a3407310c08979aefd65078518478). - -The internals of picohttpparser has been described to some extent in [my blog entry]( http://blog.kazuhooku.com/2014/11/the-internals-h2o-or-how-to-write-fast.html). diff --git a/deps/picohttpparser/bench.c b/deps/picohttpparser/bench.c deleted file mode 100644 index 8dec06c4..00000000 --- a/deps/picohttpparser/bench.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, - * Shigeo Mitsunari - * - * The software is licensed under either the MIT License (below) or the Perl - * license. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include -#include -#include "picohttpparser.h" - -#define REQ \ - "GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n" \ - "Host: www.kittyhell.com\r\n" \ - "User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 " \ - "Pathtraq/0.9\r\n" \ - "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" \ - "Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n" \ - "Accept-Encoding: gzip,deflate\r\n" \ - "Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n" \ - "Keep-Alive: 115\r\n" \ - "Connection: keep-alive\r\n" \ - "Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; " \ - "__utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; " \ - "__utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral\r\n" \ - "\r\n" - -int main(void) -{ - const char *method; - size_t method_len; - const char *path; - size_t path_len; - int minor_version; - struct phr_header headers[32]; - size_t num_headers; - int i, ret; - - for (i = 0; i < 10000000; i++) { - num_headers = sizeof(headers) / sizeof(headers[0]); - ret = phr_parse_request(REQ, sizeof(REQ) - 1, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, - 0); - assert(ret == sizeof(REQ) - 1); - } - - return 0; -} diff --git a/deps/picohttpparser/picohttpparser.c b/deps/picohttpparser/picohttpparser.c deleted file mode 100644 index 680039b4..00000000 --- a/deps/picohttpparser/picohttpparser.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, - * Shigeo Mitsunari - * - * The software is licensed under either the MIT License (below) or the Perl - * license. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include -#include -#include -#ifdef __SSE4_2__ -#ifdef _MSC_VER -#include -#else -#include -#endif -#endif -#include "picohttpparser.h" - -#if __GNUC__ >= 3 -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#else -#define likely(x) (x) -#define unlikely(x) (x) -#endif - -#ifdef _MSC_VER -#define ALIGNED(n) _declspec(align(n)) -#else -#define ALIGNED(n) __attribute__((aligned(n))) -#endif - -#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u) - -#define CHECK_EOF() \ - if (buf == buf_end) { \ - *ret = -2; \ - return NULL; \ - } - -#define EXPECT_CHAR_NO_CHECK(ch) \ - if (*buf++ != ch) { \ - *ret = -1; \ - return NULL; \ - } - -#define EXPECT_CHAR(ch) \ - CHECK_EOF(); \ - EXPECT_CHAR_NO_CHECK(ch); - -#define ADVANCE_TOKEN(tok, toklen) \ - do { \ - const char *tok_start = buf; \ - static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \ - int found2; \ - buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \ - if (!found2) { \ - CHECK_EOF(); \ - } \ - while (1) { \ - if (*buf == ' ') { \ - break; \ - } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \ - if ((unsigned char)*buf < '\040' || *buf == '\177') { \ - *ret = -1; \ - return NULL; \ - } \ - } \ - ++buf; \ - CHECK_EOF(); \ - } \ - tok = tok_start; \ - toklen = buf - tok_start; \ - } while (0) - -static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" - "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" - "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - -static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) -{ - *found = 0; -#if __SSE4_2__ - if (likely(buf_end - buf >= 16)) { - __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges); - - size_t left = (buf_end - buf) & ~15; - do { - __m128i b16 = _mm_loadu_si128((const __m128i *)buf); - int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); - if (unlikely(r != 16)) { - buf += r; - *found = 1; - break; - } - buf += 16; - left -= 16; - } while (likely(left != 0)); - } -#else - /* suppress unused parameter warning */ - (void)buf_end; - (void)ranges; - (void)ranges_size; -#endif - return buf; -} - -static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) -{ - const char *token_start = buf; - -#ifdef __SSE4_2__ - static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */ - "\012\037" /* allow SP and up to but not including DEL */ - "\177\177"; /* allow chars w. MSB set */ - int found; - buf = findchar_fast(buf, buf_end, ranges1, 6, &found); - if (found) - goto FOUND_CTL; -#else - /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ - while (likely(buf_end - buf >= 8)) { -#define DOIT() \ - do { \ - if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ - goto NonPrintable; \ - ++buf; \ - } while (0) - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); -#undef DOIT - continue; - NonPrintable: - if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { - goto FOUND_CTL; - } - ++buf; - } -#endif - for (;; ++buf) { - CHECK_EOF(); - if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { - if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { - goto FOUND_CTL; - } - } - } -FOUND_CTL: - if (likely(*buf == '\015')) { - ++buf; - EXPECT_CHAR('\012'); - *token_len = buf - 2 - token_start; - } else if (*buf == '\012') { - *token_len = buf - token_start; - ++buf; - } else { - *ret = -1; - return NULL; - } - *token = token_start; - - return buf; -} - -static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) -{ - int ret_cnt = 0; - buf = last_len < 3 ? buf : buf + last_len - 3; - - while (1) { - CHECK_EOF(); - if (*buf == '\015') { - ++buf; - CHECK_EOF(); - EXPECT_CHAR('\012'); - ++ret_cnt; - } else if (*buf == '\012') { - ++buf; - ++ret_cnt; - } else { - ++buf; - ret_cnt = 0; - } - if (ret_cnt == 2) { - return buf; - } - } - - *ret = -2; - return NULL; -} - -#define PARSE_INT(valp_, mul_) \ - if (*buf < '0' || '9' < *buf) { \ - buf++; \ - *ret = -1; \ - return NULL; \ - } \ - *(valp_) = (mul_) * (*buf++ - '0'); - -#define PARSE_INT_3(valp_) \ - do { \ - int res_ = 0; \ - PARSE_INT(&res_, 100) \ - *valp_ = res_; \ - PARSE_INT(&res_, 10) \ - *valp_ += res_; \ - PARSE_INT(&res_, 1) \ - *valp_ += res_; \ - } while (0) - -/* returned pointer is always within [buf, buf_end), or null */ -static const char *parse_token(const char *buf, const char *buf_end, const char **token, size_t *token_len, char next_char, - int *ret) -{ - /* We use pcmpestri to detect non-token characters. This instruction can take no more than eight character ranges (8*2*8=128 - * bits that is the size of a SSE register). Due to this restriction, characters `|` and `~` are handled in the slow loop. */ - static const char ALIGNED(16) ranges[] = "\x00 " /* control chars and up to SP */ - "\"\"" /* 0x22 */ - "()" /* 0x28,0x29 */ - ",," /* 0x2c */ - "//" /* 0x2f */ - ":@" /* 0x3a-0x40 */ - "[]" /* 0x5b-0x5d */ - "{\xff"; /* 0x7b-0xff */ - const char *buf_start = buf; - int found; - buf = findchar_fast(buf, buf_end, ranges, sizeof(ranges) - 1, &found); - if (!found) { - CHECK_EOF(); - } - while (1) { - if (*buf == next_char) { - break; - } else if (!token_char_map[(unsigned char)*buf]) { - *ret = -1; - return NULL; - } - ++buf; - CHECK_EOF(); - } - *token = buf_start; - *token_len = buf - buf_start; - return buf; -} - -/* returned pointer is always within [buf, buf_end), or null */ -static const char *parse_http_version(const char *buf, const char *buf_end, int *minor_version, int *ret) -{ - /* we want at least [HTTP/1.] to try to parse */ - if (buf_end - buf < 9) { - *ret = -2; - return NULL; - } - EXPECT_CHAR_NO_CHECK('H'); - EXPECT_CHAR_NO_CHECK('T'); - EXPECT_CHAR_NO_CHECK('T'); - EXPECT_CHAR_NO_CHECK('P'); - EXPECT_CHAR_NO_CHECK('/'); - EXPECT_CHAR_NO_CHECK('1'); - EXPECT_CHAR_NO_CHECK('.'); - PARSE_INT(minor_version, 1); - return buf; -} - -static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, - size_t max_headers, int *ret) -{ - for (;; ++*num_headers) { - CHECK_EOF(); - if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); - break; - } else if (*buf == '\012') { - ++buf; - break; - } - if (*num_headers == max_headers) { - *ret = -1; - return NULL; - } - if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { - /* parsing name, but do not discard SP before colon, see - * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ - if ((buf = parse_token(buf, buf_end, &headers[*num_headers].name, &headers[*num_headers].name_len, ':', ret)) == NULL) { - return NULL; - } - if (headers[*num_headers].name_len == 0) { - *ret = -1; - return NULL; - } - ++buf; - for (;; ++buf) { - CHECK_EOF(); - if (!(*buf == ' ' || *buf == '\t')) { - break; - } - } - } else { - headers[*num_headers].name = NULL; - headers[*num_headers].name_len = 0; - } - const char *value; - size_t value_len; - if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) { - return NULL; - } - /* remove trailing SPs and HTABs */ - const char *value_end = value + value_len; - for (; value_end != value; --value_end) { - const char c = *(value_end - 1); - if (!(c == ' ' || c == '\t')) { - break; - } - } - headers[*num_headers].value = value; - headers[*num_headers].value_len = value_end - value; - } - return buf; -} - -static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path, - size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, - size_t max_headers, int *ret) -{ - /* skip first empty line (some clients add CRLF after POST content) */ - CHECK_EOF(); - if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); - } else if (*buf == '\012') { - ++buf; - } - - /* parse request line */ - if ((buf = parse_token(buf, buf_end, method, method_len, ' ', ret)) == NULL) { - return NULL; - } - do { - ++buf; - CHECK_EOF(); - } while (*buf == ' '); - ADVANCE_TOKEN(*path, *path_len); - do { - ++buf; - CHECK_EOF(); - } while (*buf == ' '); - if (*method_len == 0 || *path_len == 0) { - *ret = -1; - return NULL; - } - if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { - return NULL; - } - if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); - } else if (*buf == '\012') { - ++buf; - } else { - *ret = -1; - return NULL; - } - - return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); -} - -int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, - size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf_start + len; - size_t max_headers = *num_headers; - int r; - - *method = NULL; - *method_len = 0; - *path = NULL; - *path_len = 0; - *minor_version = -1; - *num_headers = 0; - - /* if last_len != 0, check if the request is complete (a fast countermeasure - againt slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } - - if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers, - &r)) == NULL) { - return r; - } - - return (int)(buf - buf_start); -} - -static const char *parse_response(const char *buf, const char *buf_end, int *minor_version, int *status, const char **msg, - size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) -{ - /* parse "HTTP/1.x" */ - if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { - return NULL; - } - /* skip space */ - if (*buf != ' ') { - *ret = -1; - return NULL; - } - do { - ++buf; - CHECK_EOF(); - } while (*buf == ' '); - /* parse status code, we want at least [:digit:][:digit:][:digit:] to try to parse */ - if (buf_end - buf < 4) { - *ret = -2; - return NULL; - } - PARSE_INT_3(status); - - /* get message including preceding space */ - if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) { - return NULL; - } - if (*msg_len == 0) { - /* ok */ - } else if (**msg == ' ') { - /* Remove preceding space. Successful return from `get_token_to_eol` guarantees that we would hit something other than SP - * before running past the end of the given buffer. */ - do { - ++*msg; - --*msg_len; - } while (**msg == ' '); - } else { - /* garbage found after status code */ - *ret = -1; - return NULL; - } - - return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); -} - -int phr_parse_response(const char *buf_start, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len, - struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf + len; - size_t max_headers = *num_headers; - int r; - - *minor_version = -1; - *status = 0; - *msg = NULL; - *msg_len = 0; - *num_headers = 0; - - /* if last_len != 0, check if the response is complete (a fast countermeasure - against slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } - - if ((buf = parse_response(buf, buf_end, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) { - return r; - } - - return (int)(buf - buf_start); -} - -int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf + len; - size_t max_headers = *num_headers; - int r; - - *num_headers = 0; - - /* if last_len != 0, check if the response is complete (a fast countermeasure - against slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } - - if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) { - return r; - } - - return (int)(buf - buf_start); -} - -enum { - CHUNKED_IN_CHUNK_SIZE, - CHUNKED_IN_CHUNK_EXT, - CHUNKED_IN_CHUNK_DATA, - CHUNKED_IN_CHUNK_CRLF, - CHUNKED_IN_TRAILERS_LINE_HEAD, - CHUNKED_IN_TRAILERS_LINE_MIDDLE -}; - -static int decode_hex(int ch) -{ - if ('0' <= ch && ch <= '9') { - return ch - '0'; - } else if ('A' <= ch && ch <= 'F') { - return ch - 'A' + 0xa; - } else if ('a' <= ch && ch <= 'f') { - return ch - 'a' + 0xa; - } else { - return -1; - } -} - -ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) -{ - size_t dst = 0, src = 0, bufsz = *_bufsz; - ssize_t ret = -2; /* incomplete */ - - decoder->_total_read += bufsz; - - while (1) { - switch (decoder->_state) { - case CHUNKED_IN_CHUNK_SIZE: - for (;; ++src) { - int v; - if (src == bufsz) - goto Exit; - if ((v = decode_hex(buf[src])) == -1) { - if (decoder->_hex_count == 0) { - ret = -1; - goto Exit; - } - /* the only characters that may appear after the chunk size are BWS, semicolon, or CRLF */ - switch (buf[src]) { - case ' ': - case '\011': - case ';': - case '\012': - case '\015': - break; - default: - ret = -1; - goto Exit; - } - break; - } - if (decoder->_hex_count == sizeof(size_t) * 2) { - ret = -1; - goto Exit; - } - decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; - ++decoder->_hex_count; - } - decoder->_hex_count = 0; - decoder->_state = CHUNKED_IN_CHUNK_EXT; - /* fallthru */ - case CHUNKED_IN_CHUNK_EXT: - /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] == '\012') - break; - } - ++src; - if (decoder->bytes_left_in_chunk == 0) { - if (decoder->consume_trailer) { - decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; - break; - } else { - goto Complete; - } - } - decoder->_state = CHUNKED_IN_CHUNK_DATA; - /* fallthru */ - case CHUNKED_IN_CHUNK_DATA: { - size_t avail = bufsz - src; - if (avail < decoder->bytes_left_in_chunk) { - if (dst != src) - memmove(buf + dst, buf + src, avail); - src += avail; - dst += avail; - decoder->bytes_left_in_chunk -= avail; - goto Exit; - } - if (dst != src) - memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); - src += decoder->bytes_left_in_chunk; - dst += decoder->bytes_left_in_chunk; - decoder->bytes_left_in_chunk = 0; - decoder->_state = CHUNKED_IN_CHUNK_CRLF; - } - /* fallthru */ - case CHUNKED_IN_CHUNK_CRLF: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] != '\015') - break; - } - if (buf[src] != '\012') { - ret = -1; - goto Exit; - } - ++src; - decoder->_state = CHUNKED_IN_CHUNK_SIZE; - break; - case CHUNKED_IN_TRAILERS_LINE_HEAD: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] != '\015') - break; - } - if (buf[src++] == '\012') - goto Complete; - decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; - /* fallthru */ - case CHUNKED_IN_TRAILERS_LINE_MIDDLE: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] == '\012') - break; - } - ++src; - decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; - break; - default: - assert(!"decoder is corrupt"); - } - } - -Complete: - ret = bufsz - src; -Exit: - if (dst != src) - memmove(buf + dst, buf + src, bufsz - src); - *_bufsz = dst; - /* if incomplete but the overhead of the chunked encoding is >=100KB and >80%, signal an error */ - if (ret == -2) { - decoder->_total_overhead += bufsz - dst; - if (decoder->_total_overhead >= 100 * 1024 && decoder->_total_read - decoder->_total_overhead < decoder->_total_read / 4) - ret = -1; - } - return ret; -} - -int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) -{ - return decoder->_state == CHUNKED_IN_CHUNK_DATA; -} - -#undef CHECK_EOF -#undef EXPECT_CHAR -#undef ADVANCE_TOKEN diff --git a/deps/picohttpparser/picohttpparser.h b/deps/picohttpparser/picohttpparser.h deleted file mode 100644 index 13bc855b..00000000 --- a/deps/picohttpparser/picohttpparser.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, - * Shigeo Mitsunari - * - * The software is licensed under either the MIT License (below) or the Perl - * license. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef picohttpparser_h -#define picohttpparser_h - -#include -#include - -#ifdef _MSC_VER -#define ssize_t intptr_t -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* contains name and value of a header (name == NULL if is a continuing line - * of a multiline header */ -struct phr_header { - const char *name; - size_t name_len; - const char *value; - size_t value_len; -}; - -/* returns number of bytes consumed if successful, -2 if request is partial, - * -1 if failed */ -int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, - int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len); - -/* ditto */ -int phr_parse_response(const char *_buf, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len, - struct phr_header *headers, size_t *num_headers, size_t last_len); - -/* ditto */ -int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len); - -/* should be zero-filled before start */ -struct phr_chunked_decoder { - size_t bytes_left_in_chunk; /* number of bytes left in current chunk */ - char consume_trailer; /* if trailing headers should be consumed */ - char _hex_count; - char _state; - uint64_t _total_read; - uint64_t _total_overhead; -}; - -/* the function rewrites the buffer given as (buf, bufsz) removing the chunked- - * encoding headers. When the function returns without an error, bufsz is - * updated to the length of the decoded data available. Applications should - * repeatedly call the function while it returns -2 (incomplete) every time - * supplying newly arrived data. If the end of the chunked-encoded data is - * found, the function returns a non-negative number indicating the number of - * octets left undecoded, that starts from the offset returned by `*bufsz`. - * Returns -1 on error. - */ -ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *bufsz); - -/* returns if the chunked decoder is in middle of chunked data */ -int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/picohttpparser/picohttpparser.xcodeproj/project.pbxproj b/deps/picohttpparser/picohttpparser.xcodeproj/project.pbxproj deleted file mode 100644 index cc466721..00000000 --- a/deps/picohttpparser/picohttpparser.xcodeproj/project.pbxproj +++ /dev/null @@ -1,290 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 50; - objects = { - -/* Begin PBXBuildFile section */ - E98BADCF24BBFCA10040C7D4 /* picohttpparser.c in Sources */ = {isa = PBXBuildFile; fileRef = E98BADCD24BBFCA10040C7D4 /* picohttpparser.c */; }; - E98BADD024BBFCA10040C7D4 /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = E98BADCE24BBFCA10040C7D4 /* test.c */; }; - E98BADD424BBFCB40040C7D4 /* picotest.c in Sources */ = {isa = PBXBuildFile; fileRef = E98BADD224BBFCB40040C7D4 /* picotest.c */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - E98BADC024BBFC4E0040C7D4 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - E98BADC224BBFC4E0040C7D4 /* test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test; sourceTree = BUILT_PRODUCTS_DIR; }; - E98BADCC24BBFCA10040C7D4 /* picohttpparser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = picohttpparser.h; sourceTree = ""; }; - E98BADCD24BBFCA10040C7D4 /* picohttpparser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = picohttpparser.c; sourceTree = ""; }; - E98BADCE24BBFCA10040C7D4 /* test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = test.c; sourceTree = ""; }; - E98BADD224BBFCB40040C7D4 /* picotest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = picotest.c; sourceTree = ""; }; - E98BADD324BBFCB40040C7D4 /* picotest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = picotest.h; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - E98BADBF24BBFC4E0040C7D4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - E98BADB924BBFC4E0040C7D4 = { - isa = PBXGroup; - children = ( - E98BADD124BBFCA50040C7D4 /* picotest */, - E98BADCD24BBFCA10040C7D4 /* picohttpparser.c */, - E98BADCC24BBFCA10040C7D4 /* picohttpparser.h */, - E98BADCE24BBFCA10040C7D4 /* test.c */, - E98BADC324BBFC4E0040C7D4 /* Products */, - ); - sourceTree = ""; - }; - E98BADC324BBFC4E0040C7D4 /* Products */ = { - isa = PBXGroup; - children = ( - E98BADC224BBFC4E0040C7D4 /* test */, - ); - name = Products; - sourceTree = ""; - }; - E98BADD124BBFCA50040C7D4 /* picotest */ = { - isa = PBXGroup; - children = ( - E98BADD224BBFCB40040C7D4 /* picotest.c */, - E98BADD324BBFCB40040C7D4 /* picotest.h */, - ); - path = picotest; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - E98BADC124BBFC4E0040C7D4 /* test */ = { - isa = PBXNativeTarget; - buildConfigurationList = E98BADC924BBFC4E0040C7D4 /* Build configuration list for PBXNativeTarget "test" */; - buildPhases = ( - E98BADBE24BBFC4E0040C7D4 /* Sources */, - E98BADBF24BBFC4E0040C7D4 /* Frameworks */, - E98BADC024BBFC4E0040C7D4 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = test; - productName = picohttpparser; - productReference = E98BADC224BBFC4E0040C7D4 /* test */; - productType = "com.apple.product-type.tool"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - E98BADBA24BBFC4E0040C7D4 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1150; - ORGANIZATIONNAME = H2O; - TargetAttributes = { - E98BADC124BBFC4E0040C7D4 = { - CreatedOnToolsVersion = 11.5; - }; - }; - }; - buildConfigurationList = E98BADBD24BBFC4E0040C7D4 /* Build configuration list for PBXProject "picohttpparser" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = E98BADB924BBFC4E0040C7D4; - productRefGroup = E98BADC324BBFC4E0040C7D4 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - E98BADC124BBFC4E0040C7D4 /* test */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - E98BADBE24BBFC4E0040C7D4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E98BADD424BBFCB40040C7D4 /* picotest.c in Sources */, - E98BADCF24BBFCA10040C7D4 /* picohttpparser.c in Sources */, - E98BADD024BBFCA10040C7D4 /* test.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - E98BADC724BBFC4E0040C7D4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - }; - name = Debug; - }; - E98BADC824BBFC4E0040C7D4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = macosx; - }; - name = Release; - }; - E98BADCA24BBFC4E0040C7D4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - E98BADCB24BBFC4E0040C7D4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - E98BADBD24BBFC4E0040C7D4 /* Build configuration list for PBXProject "picohttpparser" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E98BADC724BBFC4E0040C7D4 /* Debug */, - E98BADC824BBFC4E0040C7D4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E98BADC924BBFC4E0040C7D4 /* Build configuration list for PBXNativeTarget "test" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E98BADCA24BBFC4E0040C7D4 /* Debug */, - E98BADCB24BBFC4E0040C7D4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = E98BADBA24BBFC4E0040C7D4 /* Project object */; -} diff --git a/deps/picohttpparser/picohttpparser.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/deps/picohttpparser/picohttpparser.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/deps/picohttpparser/picohttpparser.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/deps/picohttpparser/picohttpparser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/deps/picohttpparser/picohttpparser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/deps/picohttpparser/picohttpparser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/deps/picohttpparser/picohttpparser.xcodeproj/xcshareddata/xcschemes/test.xcscheme b/deps/picohttpparser/picohttpparser.xcodeproj/xcshareddata/xcschemes/test.xcscheme deleted file mode 100644 index 08382840..00000000 --- a/deps/picohttpparser/picohttpparser.xcodeproj/xcshareddata/xcschemes/test.xcscheme +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/deps/picohttpparser/test.c b/deps/picohttpparser/test.c deleted file mode 100644 index dff02ed6..00000000 --- a/deps/picohttpparser/test.c +++ /dev/null @@ -1,529 +0,0 @@ -/* use `make test` to run the test */ -/* - * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, - * Shigeo Mitsunari - * - * The software is licensed under either the MIT License (below) or the Perl - * license. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include "picotest/picotest.h" -#include "picohttpparser.h" - -static int bufis(const char *s, size_t l, const char *t) -{ - return strlen(t) == l && memcmp(s, t, l) == 0; -} - -static char *inputbuf; /* point to the end of the buffer */ - -static void test_request(void) -{ - const char *method; - size_t method_len; - const char *path; - size_t path_len; - int minor_version; - struct phr_header headers[4]; - size_t num_headers; - -#define PARSE(s, last_len, exp, comment) \ - do { \ - size_t slen = sizeof(s) - 1; \ - note(comment); \ - num_headers = sizeof(headers) / sizeof(headers[0]); \ - memcpy(inputbuf - slen, s, slen); \ - ok(phr_parse_request(inputbuf - slen, slen, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, \ - last_len) == (exp == 0 ? (int)slen : exp)); \ - } while (0) - - PARSE("GET / HTTP/1.0\r\n\r\n", 0, 0, "simple"); - ok(num_headers == 0); - ok(bufis(method, method_len, "GET")); - ok(bufis(path, path_len, "/")); - ok(minor_version == 0); - - PARSE("GET / HTTP/1.0\r\n\r", 0, -2, "partial"); - - PARSE("GET /hoge HTTP/1.1\r\nHost: example.com\r\nCookie: \r\n\r\n", 0, 0, "parse headers"); - ok(num_headers == 2); - ok(bufis(method, method_len, "GET")); - ok(bufis(path, path_len, "/hoge")); - ok(minor_version == 1); - ok(bufis(headers[0].name, headers[0].name_len, "Host")); - ok(bufis(headers[0].value, headers[0].value_len, "example.com")); - ok(bufis(headers[1].name, headers[1].name_len, "Cookie")); - ok(bufis(headers[1].value, headers[1].value_len, "")); - - PARSE("GET /hoge HTTP/1.1\r\nHost: example.com\r\nUser-Agent: \343\201\262\343/1.0\r\n\r\n", 0, 0, "multibyte included"); - ok(num_headers == 2); - ok(bufis(method, method_len, "GET")); - ok(bufis(path, path_len, "/hoge")); - ok(minor_version == 1); - ok(bufis(headers[0].name, headers[0].name_len, "Host")); - ok(bufis(headers[0].value, headers[0].value_len, "example.com")); - ok(bufis(headers[1].name, headers[1].name_len, "User-Agent")); - ok(bufis(headers[1].value, headers[1].value_len, "\343\201\262\343/1.0")); - - PARSE("GET / HTTP/1.0\r\nfoo: \r\nfoo: b\r\n \tc\r\n\r\n", 0, 0, "parse multiline"); - ok(num_headers == 3); - ok(bufis(method, method_len, "GET")); - ok(bufis(path, path_len, "/")); - ok(minor_version == 0); - ok(bufis(headers[0].name, headers[0].name_len, "foo")); - ok(bufis(headers[0].value, headers[0].value_len, "")); - ok(bufis(headers[1].name, headers[1].name_len, "foo")); - ok(bufis(headers[1].value, headers[1].value_len, "b")); - ok(headers[2].name == NULL); - ok(bufis(headers[2].value, headers[2].value_len, " \tc")); - - PARSE("GET / HTTP/1.0\r\nfoo : ab\r\n\r\n", 0, -1, "parse header name with trailing space"); - - PARSE("GET", 0, -2, "incomplete 1"); - ok(method == NULL); - PARSE("GET ", 0, -2, "incomplete 2"); - ok(bufis(method, method_len, "GET")); - PARSE("GET /", 0, -2, "incomplete 3"); - ok(path == NULL); - PARSE("GET / ", 0, -2, "incomplete 4"); - ok(bufis(path, path_len, "/")); - PARSE("GET / H", 0, -2, "incomplete 5"); - PARSE("GET / HTTP/1.", 0, -2, "incomplete 6"); - PARSE("GET / HTTP/1.0", 0, -2, "incomplete 7"); - ok(minor_version == -1); - PARSE("GET / HTTP/1.0\r", 0, -2, "incomplete 8"); - ok(minor_version == 0); - - PARSE("GET /hoge HTTP/1.0\r\n\r", strlen("GET /hoge HTTP/1.0\r\n\r") - 1, -2, "slowloris (incomplete)"); - PARSE("GET /hoge HTTP/1.0\r\n\r\n", strlen("GET /hoge HTTP/1.0\r\n\r\n") - 1, 0, "slowloris (complete)"); - - PARSE(" / HTTP/1.0\r\n\r\n", 0, -1, "empty method"); - PARSE("GET HTTP/1.0\r\n\r\n", 0, -1, "empty request-target"); - - PARSE("GET / HTTP/1.0\r\n:a\r\n\r\n", 0, -1, "empty header name"); - PARSE("GET / HTTP/1.0\r\n :a\r\n\r\n", 0, -1, "header name (space only)"); - - PARSE("G\0T / HTTP/1.0\r\n\r\n", 0, -1, "NUL in method"); - PARSE("G\tT / HTTP/1.0\r\n\r\n", 0, -1, "tab in method"); - PARSE(":GET / HTTP/1.0\r\n\r\n", 0, -1, "invalid method"); - PARSE("GET /\x7fhello HTTP/1.0\r\n\r\n", 0, -1, "DEL in uri-path"); - PARSE("GET / HTTP/1.0\r\na\0b: c\r\n\r\n", 0, -1, "NUL in header name"); - PARSE("GET / HTTP/1.0\r\nab: c\0d\r\n\r\n", 0, -1, "NUL in header value"); - PARSE("GET / HTTP/1.0\r\na\033b: c\r\n\r\n", 0, -1, "CTL in header name"); - PARSE("GET / HTTP/1.0\r\nab: c\033\r\n\r\n", 0, -1, "CTL in header value"); - PARSE("GET / HTTP/1.0\r\n/: 1\r\n\r\n", 0, -1, "invalid char in header value"); - PARSE("GET /\xa0 HTTP/1.0\r\nh: c\xa2y\r\n\r\n", 0, 0, "accept MSB chars"); - ok(num_headers == 1); - ok(bufis(method, method_len, "GET")); - ok(bufis(path, path_len, "/\xa0")); - ok(minor_version == 0); - ok(bufis(headers[0].name, headers[0].name_len, "h")); - ok(bufis(headers[0].value, headers[0].value_len, "c\xa2y")); - - PARSE("GET / HTTP/1.0\r\n\x7c\x7e: 1\r\n\r\n", 0, 0, "accept |~ (though forbidden by SSE)"); - ok(num_headers == 1); - ok(bufis(headers[0].name, headers[0].name_len, "\x7c\x7e")); - ok(bufis(headers[0].value, headers[0].value_len, "1")); - - PARSE("GET / HTTP/1.0\r\n\x7b: 1\r\n\r\n", 0, -1, "disallow {"); - - PARSE("GET / HTTP/1.0\r\nfoo: a \t \r\n\r\n", 0, 0, "exclude leading and trailing spaces in header value"); - ok(bufis(headers[0].value, headers[0].value_len, "a")); - - PARSE("GET / HTTP/1.0\r\n\r\n", 0, 0, "accept multiple spaces between tokens"); - -#undef PARSE -} - -static void test_response(void) -{ - int minor_version; - int status; - const char *msg; - size_t msg_len; - struct phr_header headers[4]; - size_t num_headers; - -#define PARSE(s, last_len, exp, comment) \ - do { \ - size_t slen = sizeof(s) - 1; \ - note(comment); \ - num_headers = sizeof(headers) / sizeof(headers[0]); \ - memcpy(inputbuf - slen, s, slen); \ - ok(phr_parse_response(inputbuf - slen, slen, &minor_version, &status, &msg, &msg_len, headers, &num_headers, last_len) == \ - (exp == 0 ? (int)slen : exp)); \ - } while (0) - - PARSE("HTTP/1.0 200 OK\r\n\r\n", 0, 0, "simple"); - ok(num_headers == 0); - ok(status == 200); - ok(minor_version == 0); - ok(bufis(msg, msg_len, "OK")); - - PARSE("HTTP/1.0 200 OK\r\n\r", 0, -2, "partial"); - - PARSE("HTTP/1.1 200 OK\r\nHost: example.com\r\nCookie: \r\n\r\n", 0, 0, "parse headers"); - ok(num_headers == 2); - ok(minor_version == 1); - ok(status == 200); - ok(bufis(msg, msg_len, "OK")); - ok(bufis(headers[0].name, headers[0].name_len, "Host")); - ok(bufis(headers[0].value, headers[0].value_len, "example.com")); - ok(bufis(headers[1].name, headers[1].name_len, "Cookie")); - ok(bufis(headers[1].value, headers[1].value_len, "")); - - PARSE("HTTP/1.0 200 OK\r\nfoo: \r\nfoo: b\r\n \tc\r\n\r\n", 0, 0, "parse multiline"); - ok(num_headers == 3); - ok(minor_version == 0); - ok(status == 200); - ok(bufis(msg, msg_len, "OK")); - ok(bufis(headers[0].name, headers[0].name_len, "foo")); - ok(bufis(headers[0].value, headers[0].value_len, "")); - ok(bufis(headers[1].name, headers[1].name_len, "foo")); - ok(bufis(headers[1].value, headers[1].value_len, "b")); - ok(headers[2].name == NULL); - ok(bufis(headers[2].value, headers[2].value_len, " \tc")); - - PARSE("HTTP/1.0 500 Internal Server Error\r\n\r\n", 0, 0, "internal server error"); - ok(num_headers == 0); - ok(minor_version == 0); - ok(status == 500); - ok(bufis(msg, msg_len, "Internal Server Error")); - ok(msg_len == sizeof("Internal Server Error") - 1); - - PARSE("H", 0, -2, "incomplete 1"); - PARSE("HTTP/1.", 0, -2, "incomplete 2"); - PARSE("HTTP/1.1", 0, -2, "incomplete 3"); - ok(minor_version == -1); - PARSE("HTTP/1.1 ", 0, -2, "incomplete 4"); - ok(minor_version == 1); - PARSE("HTTP/1.1 2", 0, -2, "incomplete 5"); - PARSE("HTTP/1.1 200", 0, -2, "incomplete 6"); - ok(status == 0); - PARSE("HTTP/1.1 200 ", 0, -2, "incomplete 7"); - ok(status == 200); - PARSE("HTTP/1.1 200 O", 0, -2, "incomplete 8"); - PARSE("HTTP/1.1 200 OK\r", 0, -2, "incomplete 9"); - ok(msg == NULL); - PARSE("HTTP/1.1 200 OK\r\n", 0, -2, "incomplete 10"); - ok(bufis(msg, msg_len, "OK")); - PARSE("HTTP/1.1 200 OK\n", 0, -2, "incomplete 11"); - ok(bufis(msg, msg_len, "OK")); - - PARSE("HTTP/1.1 200 OK\r\nA: 1\r", 0, -2, "incomplete 11"); - ok(num_headers == 0); - PARSE("HTTP/1.1 200 OK\r\nA: 1\r\n", 0, -2, "incomplete 12"); - ok(num_headers == 1); - ok(bufis(headers[0].name, headers[0].name_len, "A")); - ok(bufis(headers[0].value, headers[0].value_len, "1")); - - PARSE("HTTP/1.0 200 OK\r\n\r", strlen("HTTP/1.0 200 OK\r\n\r") - 1, -2, "slowloris (incomplete)"); - PARSE("HTTP/1.0 200 OK\r\n\r\n", strlen("HTTP/1.0 200 OK\r\n\r\n") - 1, 0, "slowloris (complete)"); - - PARSE("HTTP/1. 200 OK\r\n\r\n", 0, -1, "invalid http version"); - PARSE("HTTP/1.2z 200 OK\r\n\r\n", 0, -1, "invalid http version 2"); - PARSE("HTTP/1.1 OK\r\n\r\n", 0, -1, "no status code"); - - PARSE("HTTP/1.1 200\r\n\r\n", 0, 0, "accept missing trailing whitespace in status-line"); - ok(bufis(msg, msg_len, "")); - PARSE("HTTP/1.1 200X\r\n\r\n", 0, -1, "garbage after status 1"); - PARSE("HTTP/1.1 200X \r\n\r\n", 0, -1, "garbage after status 2"); - PARSE("HTTP/1.1 200X OK\r\n\r\n", 0, -1, "garbage after status 3"); - - PARSE("HTTP/1.1 200 OK\r\nbar: \t b\t \t\r\n\r\n", 0, 0, "exclude leading and trailing spaces in header value"); - ok(bufis(headers[0].value, headers[0].value_len, "b")); - - PARSE("HTTP/1.1 200 OK\r\n\r\n", 0, 0, "accept multiple spaces between tokens"); - -#undef PARSE -} - -static void test_headers(void) -{ - /* only test the interface; the core parser is tested by the tests above */ - - struct phr_header headers[4]; - size_t num_headers; - -#define PARSE(s, last_len, exp, comment) \ - do { \ - note(comment); \ - num_headers = sizeof(headers) / sizeof(headers[0]); \ - ok(phr_parse_headers(s, strlen(s), headers, &num_headers, last_len) == (exp == 0 ? (int)strlen(s) : exp)); \ - } while (0) - - PARSE("Host: example.com\r\nCookie: \r\n\r\n", 0, 0, "simple"); - ok(num_headers == 2); - ok(bufis(headers[0].name, headers[0].name_len, "Host")); - ok(bufis(headers[0].value, headers[0].value_len, "example.com")); - ok(bufis(headers[1].name, headers[1].name_len, "Cookie")); - ok(bufis(headers[1].value, headers[1].value_len, "")); - - PARSE("Host: example.com\r\nCookie: \r\n\r\n", 1, 0, "slowloris"); - ok(num_headers == 2); - ok(bufis(headers[0].name, headers[0].name_len, "Host")); - ok(bufis(headers[0].value, headers[0].value_len, "example.com")); - ok(bufis(headers[1].name, headers[1].name_len, "Cookie")); - ok(bufis(headers[1].value, headers[1].value_len, "")); - - PARSE("Host: example.com\r\nCookie: \r\n\r", 0, -2, "partial"); - - PARSE("Host: e\7fample.com\r\nCookie: \r\n\r", 0, -1, "error"); - -#undef PARSE -} - -static void test_chunked_at_once(int line, int consume_trailer, const char *encoded, const char *decoded, ssize_t expected) -{ - struct phr_chunked_decoder dec = {0}; - char *buf; - size_t bufsz; - ssize_t ret; - - dec.consume_trailer = consume_trailer; - - note("testing at-once, source at line %d", line); - - buf = strdup(encoded); - bufsz = strlen(buf); - - ret = phr_decode_chunked(&dec, buf, &bufsz); - - ok(ret == expected); - ok(bufsz == strlen(decoded)); - ok(bufis(buf, bufsz, decoded)); - if (expected >= 0) { - if (ret == expected) - ok(bufis(buf + bufsz, ret, encoded + strlen(encoded) - ret)); - else - ok(0); - } - - free(buf); -} - -static void test_chunked_per_byte(int line, int consume_trailer, const char *encoded, const char *decoded, ssize_t expected) -{ - struct phr_chunked_decoder dec = {0}; - char *buf = malloc(strlen(encoded) + 1); - size_t bytes_to_consume = strlen(encoded) - (expected >= 0 ? expected : 0), bytes_ready = 0, bufsz, i; - ssize_t ret; - - dec.consume_trailer = consume_trailer; - - note("testing per-byte, source at line %d", line); - - for (i = 0; i < bytes_to_consume - 1; ++i) { - buf[bytes_ready] = encoded[i]; - bufsz = 1; - ret = phr_decode_chunked(&dec, buf + bytes_ready, &bufsz); - if (ret != -2) { - ok(0); - goto cleanup; - } - bytes_ready += bufsz; - } - strcpy(buf + bytes_ready, encoded + bytes_to_consume - 1); - bufsz = strlen(buf + bytes_ready); - ret = phr_decode_chunked(&dec, buf + bytes_ready, &bufsz); - ok(ret == expected); - bytes_ready += bufsz; - ok(bytes_ready == strlen(decoded)); - ok(bufis(buf, bytes_ready, decoded)); - if (expected >= 0) { - if (ret == expected) - ok(bufis(buf + bytes_ready, expected, encoded + bytes_to_consume)); - else - ok(0); - } - -cleanup: - free(buf); -} - -static void test_chunked_failure(int line, const char *encoded, ssize_t expected) -{ - struct phr_chunked_decoder dec = {0}; - char *buf = strdup(encoded); - size_t bufsz, i; - ssize_t ret; - - note("testing failure at-once, source at line %d", line); - bufsz = strlen(buf); - ret = phr_decode_chunked(&dec, buf, &bufsz); - ok(ret == expected); - - note("testing failure per-byte, source at line %d", line); - memset(&dec, 0, sizeof(dec)); - for (i = 0; encoded[i] != '\0'; ++i) { - buf[0] = encoded[i]; - bufsz = 1; - ret = phr_decode_chunked(&dec, buf, &bufsz); - if (ret == -1) { - ok(ret == expected); - goto cleanup; - } else if (ret == -2) { - /* continue */ - } else { - ok(0); - goto cleanup; - } - } - ok(ret == expected); - -cleanup: - free(buf); -} - -static void (*chunked_test_runners[])(int, int, const char *, const char *, ssize_t) = {test_chunked_at_once, test_chunked_per_byte, - NULL}; - -static void test_chunked(void) -{ - size_t i; - - for (i = 0; chunked_test_runners[i] != NULL; ++i) { - chunked_test_runners[i](__LINE__, 0, "b\r\nhello world\r\n0\r\n", "hello world", 0); - chunked_test_runners[i](__LINE__, 0, "6\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", 0); - chunked_test_runners[i](__LINE__, 0, "6;comment=hi\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", 0); - chunked_test_runners[i](__LINE__, 0, "6 ; comment\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", 0); - chunked_test_runners[i](__LINE__, 0, "6\r\nhello \r\n5\r\nworld\r\n0\r\na: b\r\nc: d\r\n\r\n", "hello world", - sizeof("a: b\r\nc: d\r\n\r\n") - 1); - chunked_test_runners[i](__LINE__, 0, "b\r\nhello world\r\n0\r\n", "hello world", 0); - } - - note("failures"); - test_chunked_failure(__LINE__, "z\r\nabcdefg", -1); - if (sizeof(size_t) == 8) { - test_chunked_failure(__LINE__, "6\r\nhello \r\nffffffffffffffff\r\nabcdefg", -2); - test_chunked_failure(__LINE__, "6\r\nhello \r\nfffffffffffffffff\r\nabcdefg", -1); - } - test_chunked_failure(__LINE__, "1x\r\na\r\n0\r\n", -1); -} - -static void test_chunked_consume_trailer(void) -{ - size_t i; - - for (i = 0; chunked_test_runners[i] != NULL; ++i) { - chunked_test_runners[i](__LINE__, 1, "b\r\nhello world\r\n0\r\n", "hello world", -2); - chunked_test_runners[i](__LINE__, 1, "6\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", -2); - chunked_test_runners[i](__LINE__, 1, "6;comment=hi\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", -2); - chunked_test_runners[i](__LINE__, 1, "b\r\nhello world\r\n0\r\n\r\n", "hello world", 0); - chunked_test_runners[i](__LINE__, 1, "b\nhello world\n0\n\n", "hello world", 0); - chunked_test_runners[i](__LINE__, 1, "6\r\nhello \r\n5\r\nworld\r\n0\r\na: b\r\nc: d\r\n\r\n", "hello world", 0); - } -} - -static void test_chunked_leftdata(void) -{ -#define NEXT_REQ "GET / HTTP/1.1\r\n\r\n" - - struct phr_chunked_decoder dec = {0}; - dec.consume_trailer = 1; - char buf[] = "5\r\nabcde\r\n0\r\n\r\n" NEXT_REQ; - size_t bufsz = sizeof(buf) - 1; - - ssize_t ret = phr_decode_chunked(&dec, buf, &bufsz); - ok(ret >= 0); - ok(bufsz == 5); - ok(memcmp(buf, "abcde", 5) == 0); - ok(ret == sizeof(NEXT_REQ) - 1); - ok(memcmp(buf + bufsz, NEXT_REQ, sizeof(NEXT_REQ) - 1) == 0); - -#undef NEXT_REQ -} - -static ssize_t do_test_chunked_overhead(size_t chunk_len, size_t chunk_count, const char *extra) -{ - struct phr_chunked_decoder dec = {0}; - char buf[1024]; - size_t bufsz; - ssize_t ret; - - for (size_t i = 0; i < chunk_count; ++i) { - /* build and feed the chunk header */ - bufsz = (size_t)sprintf(buf, "%zx%s\r\n", chunk_len, extra); - if ((ret = phr_decode_chunked(&dec, buf, &bufsz)) != -2) - goto Exit; - assert(bufsz == 0); - /* build and feed the chunk boby */ - memset(buf, 'A', chunk_len); - bufsz = chunk_len; - if ((ret = phr_decode_chunked(&dec, buf, &bufsz)) != -2) - goto Exit; - assert(bufsz == chunk_len); - /* build and feed the chunk end (CRLF) */ - strcpy(buf, "\r\n"); - bufsz = 2; - if ((ret = phr_decode_chunked(&dec, buf, &bufsz)) != -2) - goto Exit; - assert(bufsz == 0); - } - - /* build and feed the end chunk */ - strcpy(buf, "0\r\n\r\n"); - bufsz = 5; - ret = phr_decode_chunked(&dec, buf, &bufsz); - assert(bufsz == 0); - -Exit: - return ret; -} - -static void test_chunked_overhead(void) -{ - ok(do_test_chunked_overhead(100, 10000, "") == 2 /* consume trailer is not set */); - ok(do_test_chunked_overhead(10, 100000, "") == 2 /* consume trailer is not set */); - ok(do_test_chunked_overhead(1, 1000000, "") == -1); - - ok(do_test_chunked_overhead(10, 100000, "; tiny=1") == 2 /* consume trailer is not set */); - ok(do_test_chunked_overhead(10, 100000, "; large=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") == -1); -} - -int main(void) -{ - long pagesize = sysconf(_SC_PAGESIZE); - assert(pagesize >= 1); - - inputbuf = mmap(NULL, pagesize * 3, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); - assert(inputbuf != MAP_FAILED); - inputbuf += pagesize * 2; - ok(mprotect(inputbuf - pagesize, pagesize, PROT_READ | PROT_WRITE) == 0); - - subtest("request", test_request); - subtest("response", test_response); - subtest("headers", test_headers); - subtest("chunked", test_chunked); - subtest("chunked-consume-trailer", test_chunked_consume_trailer); - subtest("chunked-leftdata", test_chunked_leftdata); - subtest("chunked-overhead", test_chunked_overhead); - - munmap(inputbuf - pagesize * 2, pagesize * 3); - - return done_testing(); -}