diff options
Diffstat (limited to 'web/server/h2o/libh2o/deps/picohttpparser')
11 files changed, 0 insertions, 1374 deletions
diff --git a/web/server/h2o/libh2o/deps/picohttpparser/.clang-format b/web/server/h2o/libh2o/deps/picohttpparser/.clang-format deleted file mode 100644 index 9640123c7..000000000 --- a/web/server/h2o/libh2o/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/web/server/h2o/libh2o/deps/picohttpparser/.gitattributes b/web/server/h2o/libh2o/deps/picohttpparser/.gitattributes deleted file mode 100644 index 03d9eec36..000000000 --- a/web/server/h2o/libh2o/deps/picohttpparser/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -picohttpparser.* ident diff --git a/web/server/h2o/libh2o/deps/picohttpparser/.gitmodules b/web/server/h2o/libh2o/deps/picohttpparser/.gitmodules deleted file mode 100644 index e1434dacc..000000000 --- a/web/server/h2o/libh2o/deps/picohttpparser/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "picotest"] - path = picotest - url = https://github.com/h2o/picotest.git diff --git a/web/server/h2o/libh2o/deps/picohttpparser/.travis.yml b/web/server/h2o/libh2o/deps/picohttpparser/.travis.yml deleted file mode 100644 index 78af54bc2..000000000 --- a/web/server/h2o/libh2o/deps/picohttpparser/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: c -compiler: - - gcc - - clang -script: - - make test diff --git a/web/server/h2o/libh2o/deps/picohttpparser/Jamfile b/web/server/h2o/libh2o/deps/picohttpparser/Jamfile deleted file mode 100644 index 5acbe55d0..000000000 --- a/web/server/h2o/libh2o/deps/picohttpparser/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -project picohttpparser ; - -lib picohttpparser : picohttpparser.c ; - -unit-test test - : picohttpparser picotest/picotest.c test.c - : <testing.launcher>prove ; diff --git a/web/server/h2o/libh2o/deps/picohttpparser/Makefile b/web/server/h2o/libh2o/deps/picohttpparser/Makefile deleted file mode 100644 index 9e42298d3..000000000 --- a/web/server/h2o/libh2o/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/web/server/h2o/libh2o/deps/picohttpparser/README.md b/web/server/h2o/libh2o/deps/picohttpparser/README.md deleted file mode 100644 index cb32f58e1..000000000 --- a/web/server/h2o/libh2o/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/web/server/h2o/libh2o/deps/picohttpparser/bench.c b/web/server/h2o/libh2o/deps/picohttpparser/bench.c deleted file mode 100644 index 8dec06c4e..000000000 --- a/web/server/h2o/libh2o/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 <assert.h> -#include <stdio.h> -#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/web/server/h2o/libh2o/deps/picohttpparser/picohttpparser.c b/web/server/h2o/libh2o/deps/picohttpparser/picohttpparser.c deleted file mode 100644 index a707070d1..000000000 --- a/web/server/h2o/libh2o/deps/picohttpparser/picohttpparser.c +++ /dev/null @@ -1,620 +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 <assert.h> -#include <stddef.h> -#include <string.h> -#ifdef __SSE4_2__ -#ifdef _MSC_VER -#include <nmmintrin.h> -#else -#include <x86intrin.h> -#endif -#endif -#include "picohttpparser.h" - -/* $Id$ */ - -#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[] = "\000\040\177\177"; \ - int found2; \ - buf = findchar_fast(buf, buf_end, ranges2, sizeof(ranges2) - 1, &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 ranges1[] = "\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, sizeof(ranges1) - 1, &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_http_version(const char *buf, const char *buf_end, int *minor_version, int *ret) -{ - /* we want at least [HTTP/1.<two chars>] 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 */ - headers[*num_headers].name = buf; - static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */ - "\"\"" /* 0x22 */ - "()" /* 0x28,0x29 */ - ",," /* 0x2c */ - "//" /* 0x2f */ - ":@" /* 0x3a-0x40 */ - "[]" /* 0x5b-0x5d */ - "{\377"; /* 0x7b-0xff */ - int found; - buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); - if (!found) { - CHECK_EOF(); - } - while (1) { - if (*buf == ':') { - break; - } else if (!token_char_map[(unsigned char)*buf]) { - *ret = -1; - return NULL; - } - ++buf; - CHECK_EOF(); - } - if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 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; - } - if ((buf = get_token_to_eol(buf, buf_end, &headers[*num_headers].value, &headers[*num_headers].value_len, ret)) == NULL) { - return NULL; - } - } - 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 */ - ADVANCE_TOKEN(*method, *method_len); - ++buf; - ADVANCE_TOKEN(*path, *path_len); - ++buf; - 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; - } - /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */ - if (buf_end - buf < 4) { - *ret = -2; - return NULL; - } - PARSE_INT_3(status); - - /* skip space */ - if (*buf++ != ' ') { - *ret = -1; - return NULL; - } - /* get message */ - if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) { - 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 */ - - 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; - } - 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; - 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/web/server/h2o/libh2o/deps/picohttpparser/picohttpparser.h b/web/server/h2o/libh2o/deps/picohttpparser/picohttpparser.h deleted file mode 100644 index 67fd3ee74..000000000 --- a/web/server/h2o/libh2o/deps/picohttpparser/picohttpparser.h +++ /dev/null @@ -1,89 +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 <sys/types.h> - -#ifdef _MSC_VER -#define ssize_t intptr_t -#endif - -/* $Id$ */ - -#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; -}; - -/* 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 at the tail of the supplied buffer. 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/web/server/h2o/libh2o/deps/picohttpparser/test.c b/web/server/h2o/libh2o/deps/picohttpparser/test.c deleted file mode 100644 index 8f808fdfc..000000000 --- a/web/server/h2o/libh2o/deps/picohttpparser/test.c +++ /dev/null @@ -1,419 +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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#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 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 { \ - note(comment); \ - num_headers = sizeof(headers) / sizeof(headers[0]); \ - ok(phr_parse_request(s, sizeof(s) - 1, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, \ - last_len) == (exp == 0 ? strlen(s) : 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("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 /\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 {"); - -#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 { \ - note(comment); \ - num_headers = sizeof(headers) / sizeof(headers[0]); \ - ok(phr_parse_response(s, strlen(s), &minor_version, &status, &msg, &msg_len, headers, &num_headers, last_len) == \ - (exp == 0 ? strlen(s) : 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"); - -#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 ? 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\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); - } -} - -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); - } -} - -int main(int argc, char **argv) -{ - subtest("request", test_request); - subtest("response", test_response); - subtest("headers", test_headers); - subtest("chunked", test_chunked); - subtest("chunked-consume-trailer", test_chunked_consume_trailer); - return done_testing(); -} |