summaryrefslogtreecommitdiff
path: root/deps/http_parser
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2018-03-27 16:45:33 +0200
committerMyles Borins <mylesborins@google.com>2018-03-28 12:24:20 -0400
commit32050065f15de0f2e68adb2387694c094da28ca2 (patch)
treed055a81fde061c74b02f19194e0cc65a55737d1c /deps/http_parser
parent80310e916aff24dc6b3477ad52a697dff84fc78e (diff)
downloadandroid-node-v8-32050065f15de0f2e68adb2387694c094da28ca2.tar.gz
android-node-v8-32050065f15de0f2e68adb2387694c094da28ca2.tar.bz2
android-node-v8-32050065f15de0f2e68adb2387694c094da28ca2.zip
deps: upgrade http-parser to v2.8.0
PR-URL: https://github.com/nodejs-private/http-parser-private/pull/1 Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rod Vagg <rod@vagg.org>
Diffstat (limited to 'deps/http_parser')
-rw-r--r--deps/http_parser/.gitignore2
-rw-r--r--deps/http_parser/LICENSE-MIT6
-rw-r--r--deps/http_parser/Makefile39
-rw-r--r--deps/http_parser/README.md10
-rw-r--r--deps/http_parser/contrib/parsertrace.c5
-rw-r--r--deps/http_parser/http_parser.c208
-rw-r--r--deps/http_parser/http_parser.h77
-rw-r--r--deps/http_parser/test.c267
8 files changed, 450 insertions, 164 deletions
diff --git a/deps/http_parser/.gitignore b/deps/http_parser/.gitignore
index 32cb51b2d3..c122e76fb9 100644
--- a/deps/http_parser/.gitignore
+++ b/deps/http_parser/.gitignore
@@ -12,6 +12,8 @@ parsertrace_g
*.mk
*.Makefile
*.so.*
+*.exe.*
+*.exe
*.a
diff --git a/deps/http_parser/LICENSE-MIT b/deps/http_parser/LICENSE-MIT
index 58010b3889..1ec0ab4e17 100644
--- a/deps/http_parser/LICENSE-MIT
+++ b/deps/http_parser/LICENSE-MIT
@@ -1,8 +1,4 @@
-http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
-Igor Sysoev.
-
-Additional changes are licensed under the same terms as NGINX and
-copyright Joyent, Inc. and other Node contributors. All rights reserved.
+Copyright Joyent, Inc. and other Node contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
diff --git a/deps/http_parser/Makefile b/deps/http_parser/Makefile
index 5f4eb2252f..6cf63bd35e 100644
--- a/deps/http_parser/Makefile
+++ b/deps/http_parser/Makefile
@@ -21,16 +21,22 @@
PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"')
HELPER ?=
BINEXT ?=
+SOLIBNAME = libhttp_parser
+SOMAJOR = 2
+SOMINOR = 8
+SOREV = 0
ifeq (darwin,$(PLATFORM))
-SONAME ?= libhttp_parser.2.7.0.dylib
SOEXT ?= dylib
+SONAME ?= $(SOLIBNAME).$(SOMAJOR).$(SOMINOR).$(SOEXT)
+LIBNAME ?= $(SOLIBNAME).$(SOMAJOR).$(SOMINOR).$(SOREV).$(SOEXT)
else ifeq (wine,$(PLATFORM))
CC = winegcc
BINEXT = .exe.so
HELPER = wine
else
-SONAME ?= libhttp_parser.so.2.7.0
SOEXT ?= so
+SONAME ?= $(SOLIBNAME).$(SOEXT).$(SOMAJOR).$(SOMINOR)
+LIBNAME ?= $(SOLIBNAME).$(SOEXT).$(SOMAJOR).$(SOMINOR).$(SOREV)
endif
CC?=gcc
@@ -55,11 +61,13 @@ CFLAGS_LIB = $(CFLAGS_FAST) -fPIC
LDFLAGS_LIB = $(LDFLAGS) -shared
INSTALL ?= install
-PREFIX ?= $(DESTDIR)/usr/local
+PREFIX ?= /usr/local
LIBDIR = $(PREFIX)/lib
INCLUDEDIR = $(PREFIX)/include
-ifneq (darwin,$(PLATFORM))
+ifeq (darwin,$(PLATFORM))
+LDFLAGS_LIB += -Wl,-install_name,$(LIBDIR)/$(SONAME)
+else
# TODO(bnoordhuis) The native SunOS linker expects -h rather than -soname...
LDFLAGS_LIB += -Wl,-soname=$(SONAME)
endif
@@ -102,7 +110,7 @@ libhttp_parser.o: http_parser.c http_parser.h Makefile
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_LIB) -c http_parser.c -o libhttp_parser.o
library: libhttp_parser.o
- $(CC) $(LDFLAGS_LIB) -o $(SONAME) $<
+ $(CC) $(LDFLAGS_LIB) -o $(LIBNAME) $<
package: http_parser.o
$(AR) rcs libhttp_parser.a http_parser.o
@@ -123,19 +131,22 @@ tags: http_parser.c http_parser.h test.c
ctags $^
install: library
- $(INSTALL) -D http_parser.h $(INCLUDEDIR)/http_parser.h
- $(INSTALL) -D $(SONAME) $(LIBDIR)/$(SONAME)
- ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.$(SOEXT)
+ $(INSTALL) -D http_parser.h $(DESTDIR)$(INCLUDEDIR)/http_parser.h
+ $(INSTALL) -D $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(LIBNAME)
+ ln -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SONAME)
+ ln -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SOLIBNAME).$(SOEXT)
install-strip: library
- $(INSTALL) -D http_parser.h $(INCLUDEDIR)/http_parser.h
- $(INSTALL) -D -s $(SONAME) $(LIBDIR)/$(SONAME)
- ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.$(SOEXT)
+ $(INSTALL) -D http_parser.h $(DESTDIR)$(INCLUDEDIR)/http_parser.h
+ $(INSTALL) -D -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(LIBNAME)
+ ln -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SONAME)
+ ln -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SOLIBNAME).$(SOEXT)
uninstall:
- rm $(INCLUDEDIR)/http_parser.h
- rm $(LIBDIR)/$(SONAME)
- rm $(LIBDIR)/libhttp_parser.so
+ rm $(DESTDIR)$(INCLUDEDIR)/http_parser.h
+ rm $(DESTDIR)$(LIBDIR)/$(SOLIBNAME).$(SOEXT)
+ rm $(DESTDIR)$(LIBDIR)/$(SONAME)
+ rm $(DESTDIR)$(LIBDIR)/$(LIBNAME)
clean:
rm -f *.o *.a tags test test_fast test_g \
diff --git a/deps/http_parser/README.md b/deps/http_parser/README.md
index eedd7f8c9a..9c4c9999c2 100644
--- a/deps/http_parser/README.md
+++ b/deps/http_parser/README.md
@@ -72,9 +72,9 @@ if (parser->upgrade) {
}
```
-HTTP needs to know where the end of the stream is. For example, sometimes
+`http_parser` needs to know where the end of the stream is. For example, sometimes
servers send responses without Content-Length and expect the client to
-consume input (for the body) until EOF. To tell http_parser about EOF, give
+consume input (for the body) until EOF. To tell `http_parser` about EOF, give
`0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors
can still be encountered during an EOF, so one must still be prepared
to receive them.
@@ -93,7 +93,7 @@ the on_body callback.
The Special Problem of Upgrade
------------------------------
-HTTP supports upgrading the connection to a different protocol. An
+`http_parser` supports upgrading the connection to a different protocol. An
increasingly common example of this is the WebSocket protocol which sends
a request like
@@ -144,7 +144,7 @@ parse a request, and then give a response over that socket. By instantiation
of a thread-local struct containing relevant data (e.g. accepted socket,
allocated memory for callbacks to write into, etc), a parser's callbacks are
able to communicate data between the scope of the thread and the scope of the
-callback in a threadsafe manner. This allows http-parser to be used in
+callback in a threadsafe manner. This allows `http_parser` to be used in
multi-threaded contexts.
Example:
@@ -202,7 +202,7 @@ void http_parser_thread(socket_t sock) {
In case you parse HTTP message in chunks (i.e. `read()` request line
from socket, parse, read half headers, parse, etc) your data callbacks
-may be called more than once. Http-parser guarantees that data pointer is only
+may be called more than once. `http_parser` guarantees that data pointer is only
valid for the lifetime of callback. You can also `read()` into a heap allocated
buffer to avoid copying memory around if this fits your application.
diff --git a/deps/http_parser/contrib/parsertrace.c b/deps/http_parser/contrib/parsertrace.c
index e7153680f4..3daa7f46a1 100644
--- a/deps/http_parser/contrib/parsertrace.c
+++ b/deps/http_parser/contrib/parsertrace.c
@@ -1,7 +1,4 @@
-/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
- *
- * Additional changes are licensed under the same terms as NGINX and
- * copyright Joyent, Inc. and other Node contributors. All rights reserved.
+/* Copyright Joyent, Inc. and other Node contributors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c
index 719617549d..7a9c688b1c 100644
--- a/deps/http_parser/http_parser.c
+++ b/deps/http_parser/http_parser.c
@@ -1,7 +1,4 @@
-/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
- *
- * Additional changes are licensed under the same terms as NGINX and
- * copyright Joyent, Inc. and other Node contributors. All rights reserved.
+/* Copyright Joyent, Inc. and other Node contributors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@@ -25,7 +22,6 @@
#include <assert.h>
#include <stddef.h>
#include <ctype.h>
-#include <stdlib.h>
#include <string.h>
#include <limits.h>
@@ -286,10 +282,10 @@ enum state
, s_res_HT
, s_res_HTT
, s_res_HTTP
- , s_res_first_http_major
, s_res_http_major
- , s_res_first_http_minor
+ , s_res_http_dot
, s_res_http_minor
+ , s_res_http_end
, s_res_first_status_code
, s_res_status_code
, s_res_status_start
@@ -316,10 +312,10 @@ enum state
, s_req_http_HT
, s_req_http_HTT
, s_req_http_HTTP
- , s_req_first_http_major
, s_req_http_major
- , s_req_first_http_minor
+ , s_req_http_dot
, s_req_http_minor
+ , s_req_http_end
, s_req_line_almost_done
, s_header_field_start
@@ -795,75 +791,48 @@ reexecute:
case s_res_HTTP:
STRICT_CHECK(ch != '/');
- UPDATE_STATE(s_res_first_http_major);
+ UPDATE_STATE(s_res_http_major);
break;
- case s_res_first_http_major:
- if (UNLIKELY(ch < '0' || ch > '9')) {
+ case s_res_http_major:
+ if (UNLIKELY(!IS_NUM(ch))) {
SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
parser->http_major = ch - '0';
- UPDATE_STATE(s_res_http_major);
+ UPDATE_STATE(s_res_http_dot);
break;
- /* major HTTP version or dot */
- case s_res_http_major:
+ case s_res_http_dot:
{
- if (ch == '.') {
- UPDATE_STATE(s_res_first_http_minor);
- break;
- }
-
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- parser->http_major *= 10;
- parser->http_major += ch - '0';
-
- if (UNLIKELY(parser->http_major > 999)) {
+ if (UNLIKELY(ch != '.')) {
SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
+ UPDATE_STATE(s_res_http_minor);
break;
}
- /* first digit of minor HTTP version */
- case s_res_first_http_minor:
+ case s_res_http_minor:
if (UNLIKELY(!IS_NUM(ch))) {
SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
parser->http_minor = ch - '0';
- UPDATE_STATE(s_res_http_minor);
+ UPDATE_STATE(s_res_http_end);
break;
- /* minor HTTP version or end of request line */
- case s_res_http_minor:
+ case s_res_http_end:
{
- if (ch == ' ') {
- UPDATE_STATE(s_res_first_status_code);
- break;
- }
-
- if (UNLIKELY(!IS_NUM(ch))) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- parser->http_minor *= 10;
- parser->http_minor += ch - '0';
-
- if (UNLIKELY(parser->http_minor > 999)) {
+ if (UNLIKELY(ch != ' ')) {
SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
+ UPDATE_STATE(s_res_first_status_code);
break;
}
@@ -890,10 +859,9 @@ reexecute:
UPDATE_STATE(s_res_status_start);
break;
case CR:
- UPDATE_STATE(s_res_line_almost_done);
- break;
case LF:
- UPDATE_STATE(s_header_field_start);
+ UPDATE_STATE(s_res_status_start);
+ REEXECUTE();
break;
default:
SET_ERRNO(HPE_INVALID_STATUS);
@@ -915,19 +883,13 @@ reexecute:
case s_res_status_start:
{
- if (ch == CR) {
- UPDATE_STATE(s_res_line_almost_done);
- break;
- }
-
- if (ch == LF) {
- UPDATE_STATE(s_header_field_start);
- break;
- }
-
MARK(status);
UPDATE_STATE(s_res_status);
parser->index = 0;
+
+ if (ch == CR || ch == LF)
+ REEXECUTE();
+
break;
}
@@ -980,7 +942,7 @@ reexecute:
/* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
break;
case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break;
- case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;
+ case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH, SOURCE */ break;
case 'T': parser->method = HTTP_TRACE; break;
case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
default:
@@ -1007,7 +969,7 @@ reexecute:
UPDATE_STATE(s_req_spaces_before_url);
} else if (ch == matcher[parser->index]) {
; /* nada */
- } else if (IS_ALPHA(ch)) {
+ } else if ((ch >= 'A' && ch <= 'Z') || ch == '-') {
switch (parser->method << 16 | parser->index << 8 | ch) {
#define XX(meth, pos, ch, new_meth) \
@@ -1016,31 +978,28 @@ reexecute:
XX(POST, 1, 'U', PUT)
XX(POST, 1, 'A', PATCH)
+ XX(POST, 1, 'R', PROPFIND)
+ XX(PUT, 2, 'R', PURGE)
XX(CONNECT, 1, 'H', CHECKOUT)
XX(CONNECT, 2, 'P', COPY)
XX(MKCOL, 1, 'O', MOVE)
XX(MKCOL, 1, 'E', MERGE)
+ XX(MKCOL, 1, '-', MSEARCH)
XX(MKCOL, 2, 'A', MKACTIVITY)
XX(MKCOL, 3, 'A', MKCALENDAR)
XX(SUBSCRIBE, 1, 'E', SEARCH)
+ XX(SUBSCRIBE, 1, 'O', SOURCE)
XX(REPORT, 2, 'B', REBIND)
- XX(POST, 1, 'R', PROPFIND)
XX(PROPFIND, 4, 'P', PROPPATCH)
- XX(PUT, 2, 'R', PURGE)
XX(LOCK, 1, 'I', LINK)
XX(UNLOCK, 2, 'S', UNSUBSCRIBE)
XX(UNLOCK, 2, 'B', UNBIND)
XX(UNLOCK, 3, 'I', UNLINK)
#undef XX
-
default:
SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
- } else if (ch == '-' &&
- parser->index == 1 &&
- parser->method == HTTP_MKCOL) {
- parser->method = HTTP_MSEARCH;
} else {
SET_ERRNO(HPE_INVALID_METHOD);
goto error;
@@ -1153,57 +1112,41 @@ reexecute:
case s_req_http_HTTP:
STRICT_CHECK(ch != '/');
- UPDATE_STATE(s_req_first_http_major);
- break;
-
- /* first digit of major HTTP version */
- case s_req_first_http_major:
- if (UNLIKELY(ch < '1' || ch > '9')) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- parser->http_major = ch - '0';
UPDATE_STATE(s_req_http_major);
break;
- /* major HTTP version or dot */
case s_req_http_major:
- {
- if (ch == '.') {
- UPDATE_STATE(s_req_first_http_minor);
- break;
- }
-
if (UNLIKELY(!IS_NUM(ch))) {
SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
- parser->http_major *= 10;
- parser->http_major += ch - '0';
+ parser->http_major = ch - '0';
+ UPDATE_STATE(s_req_http_dot);
+ break;
- if (UNLIKELY(parser->http_major > 999)) {
+ case s_req_http_dot:
+ {
+ if (UNLIKELY(ch != '.')) {
SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
+ UPDATE_STATE(s_req_http_minor);
break;
}
- /* first digit of minor HTTP version */
- case s_req_first_http_minor:
+ case s_req_http_minor:
if (UNLIKELY(!IS_NUM(ch))) {
SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
parser->http_minor = ch - '0';
- UPDATE_STATE(s_req_http_minor);
+ UPDATE_STATE(s_req_http_end);
break;
- /* minor HTTP version or end of request line */
- case s_req_http_minor:
+ case s_req_http_end:
{
if (ch == CR) {
UPDATE_STATE(s_req_line_almost_done);
@@ -1215,21 +1158,8 @@ reexecute:
break;
}
- /* XXX allow spaces after digit? */
-
- if (UNLIKELY(!IS_NUM(ch))) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- parser->http_minor *= 10;
- parser->http_minor += ch - '0';
-
- if (UNLIKELY(parser->http_minor > 999)) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
break;
}
@@ -1366,12 +1296,7 @@ reexecute:
|| c != CONTENT_LENGTH[parser->index]) {
parser->header_state = h_general;
} else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
- if (parser->flags & F_CONTENTLENGTH) {
- SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
- goto error;
- }
parser->header_state = h_content_length;
- parser->flags |= F_CONTENTLENGTH;
}
break;
@@ -1474,6 +1399,12 @@ reexecute:
goto error;
}
+ if (parser->flags & F_CONTENTLENGTH) {
+ SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
+ goto error;
+ }
+
+ parser->flags |= F_CONTENTLENGTH;
parser->content_length = ch - '0';
break;
@@ -1793,10 +1724,17 @@ reexecute:
UPDATE_STATE(s_headers_done);
/* Set this here so that on_headers_complete() callbacks can see it */
- parser->upgrade =
- ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) ==
- (F_UPGRADE | F_CONNECTION_UPGRADE) ||
- parser->method == HTTP_CONNECT);
+ if ((parser->flags & F_UPGRADE) &&
+ (parser->flags & F_CONNECTION_UPGRADE)) {
+ /* For responses, "Upgrade: foo" and "Connection: upgrade" are
+ * mandatory only when it is a 101 Switching Protocols response,
+ * otherwise it is purely informational, to announce support.
+ */
+ parser->upgrade =
+ (parser->type == HTTP_REQUEST || parser->status_code == 101);
+ } else {
+ parser->upgrade = (parser->method == HTTP_CONNECT);
+ }
/* Here we call the headers_complete callback. This is somewhat
* different than other callbacks because if the user returns 1, we
@@ -1815,6 +1753,7 @@ reexecute:
case 2:
parser->upgrade = 1;
+ /* FALLTHROUGH */
case 1:
parser->flags |= F_SKIPBODY;
break;
@@ -2373,7 +2312,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
case s_req_server_with_at:
found_at = 1;
- /* FALLTROUGH */
+ /* FALLTHROUGH */
case s_req_server:
uf = UF_HOST;
break;
@@ -2427,12 +2366,27 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
}
if (u->field_set & (1 << UF_PORT)) {
- /* Don't bother with endp; we've already validated the string */
- unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
-
- /* Ports have a max value of 2^16 */
- if (v > 0xffff) {
- return 1;
+ uint16_t off;
+ uint16_t len;
+ const char* p;
+ const char* end;
+ unsigned long v;
+
+ off = u->field_data[UF_PORT].off;
+ len = u->field_data[UF_PORT].len;
+ end = buf + off + len;
+
+ /* NOTE: The characters are already validated and are in the [0-9] range */
+ assert(off + len <= buflen && "Port number overflow");
+ v = 0;
+ for (p = buf + off; p < end; p++) {
+ v *= 10;
+ v += *p - '0';
+
+ /* Ports have a max value of 2^16 */
+ if (v > 0xffff) {
+ return 1;
+ }
}
u->port = (uint16_t) v;
diff --git a/deps/http_parser/http_parser.h b/deps/http_parser/http_parser.h
index 105ae510a8..1fbf30e2b4 100644
--- a/deps/http_parser/http_parser.h
+++ b/deps/http_parser/http_parser.h
@@ -26,14 +26,13 @@ extern "C" {
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
-#define HTTP_PARSER_VERSION_MINOR 7
+#define HTTP_PARSER_VERSION_MINOR 8
#define HTTP_PARSER_VERSION_PATCH 0
-#include <sys/types.h>
+#include <stddef.h>
#if defined(_WIN32) && !defined(__MINGW32__) && \
(!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
#include <BaseTsd.h>
-#include <stddef.h>
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
@@ -90,6 +89,76 @@ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*);
+/* Status Codes */
+#define HTTP_STATUS_MAP(XX) \
+ XX(100, CONTINUE, Continue) \
+ XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
+ XX(102, PROCESSING, Processing) \
+ XX(200, OK, OK) \
+ XX(201, CREATED, Created) \
+ XX(202, ACCEPTED, Accepted) \
+ XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
+ XX(204, NO_CONTENT, No Content) \
+ XX(205, RESET_CONTENT, Reset Content) \
+ XX(206, PARTIAL_CONTENT, Partial Content) \
+ XX(207, MULTI_STATUS, Multi-Status) \
+ XX(208, ALREADY_REPORTED, Already Reported) \
+ XX(226, IM_USED, IM Used) \
+ XX(300, MULTIPLE_CHOICES, Multiple Choices) \
+ XX(301, MOVED_PERMANENTLY, Moved Permanently) \
+ XX(302, FOUND, Found) \
+ XX(303, SEE_OTHER, See Other) \
+ XX(304, NOT_MODIFIED, Not Modified) \
+ XX(305, USE_PROXY, Use Proxy) \
+ XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
+ XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
+ XX(400, BAD_REQUEST, Bad Request) \
+ XX(401, UNAUTHORIZED, Unauthorized) \
+ XX(402, PAYMENT_REQUIRED, Payment Required) \
+ XX(403, FORBIDDEN, Forbidden) \
+ XX(404, NOT_FOUND, Not Found) \
+ XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
+ XX(406, NOT_ACCEPTABLE, Not Acceptable) \
+ XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
+ XX(408, REQUEST_TIMEOUT, Request Timeout) \
+ XX(409, CONFLICT, Conflict) \
+ XX(410, GONE, Gone) \
+ XX(411, LENGTH_REQUIRED, Length Required) \
+ XX(412, PRECONDITION_FAILED, Precondition Failed) \
+ XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
+ XX(414, URI_TOO_LONG, URI Too Long) \
+ XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
+ XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
+ XX(417, EXPECTATION_FAILED, Expectation Failed) \
+ XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
+ XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
+ XX(423, LOCKED, Locked) \
+ XX(424, FAILED_DEPENDENCY, Failed Dependency) \
+ XX(426, UPGRADE_REQUIRED, Upgrade Required) \
+ XX(428, PRECONDITION_REQUIRED, Precondition Required) \
+ XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
+ XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
+ XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
+ XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
+ XX(501, NOT_IMPLEMENTED, Not Implemented) \
+ XX(502, BAD_GATEWAY, Bad Gateway) \
+ XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
+ XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
+ XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
+ XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
+ XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
+ XX(508, LOOP_DETECTED, Loop Detected) \
+ XX(510, NOT_EXTENDED, Not Extended) \
+ XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
+
+enum http_status
+ {
+#define XX(num, name, string) HTTP_STATUS_##name = num,
+ HTTP_STATUS_MAP(XX)
+#undef XX
+ };
+
+
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
@@ -132,6 +201,8 @@ typedef int (*http_cb) (http_parser*);
/* RFC-2068, section 19.6.1.2 */ \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
+ /* icecast */ \
+ XX(33, SOURCE, SOURCE) \
enum http_method
{
diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c
index 456a78add0..bc4e664f52 100644
--- a/deps/http_parser/test.c
+++ b/deps/http_parser/test.c
@@ -78,6 +78,7 @@ struct message {
int message_begin_cb_called;
int headers_complete_cb_called;
int message_complete_cb_called;
+ int status_cb_called;
int message_complete_on_eof;
int body_is_final;
};
@@ -1131,7 +1132,7 @@ const struct message requests[] =
}
#define UNLINK_REQUEST 41
-, {.name = "link request"
+, {.name = "unlink request"
,.type= HTTP_REQUEST
,.raw= "UNLINK /images/my_dog.jpg HTTP/1.1\r\n"
"Host: example.com\r\n"
@@ -1153,6 +1154,26 @@ const struct message requests[] =
,.body= ""
}
+#define SOURCE_REQUEST 42
+, {.name = "source request"
+ ,.type= HTTP_REQUEST
+ ,.raw= "SOURCE /music/sweet/music HTTP/1.1\r\n"
+ "Host: example.com\r\n"
+ "\r\n"
+ ,.should_keep_alive= TRUE
+ ,.message_complete_on_eof= FALSE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.method= HTTP_SOURCE
+ ,.request_path= "/music/sweet/music"
+ ,.request_url= "/music/sweet/music"
+ ,.query_string= ""
+ ,.fragment= ""
+ ,.num_headers= 1
+ ,.headers= { { "Host", "example.com" } }
+ ,.body= ""
+ }
+
, {.name= NULL } /* sentinel */
};
@@ -1745,6 +1766,193 @@ const struct message responses[] =
,.body= ""
}
+#define CONTENT_LENGTH_X 21
+, {.name= "Content-Length-X"
+ ,.type= HTTP_RESPONSE
+ ,.raw= "HTTP/1.1 200 OK\r\n"
+ "Content-Length-X: 0\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "2\r\n"
+ "OK\r\n"
+ "0\r\n"
+ "\r\n"
+ ,.should_keep_alive= TRUE
+ ,.message_complete_on_eof= FALSE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.status_code= 200
+ ,.response_status= "OK"
+ ,.num_headers= 2
+ ,.headers= { { "Content-Length-X", "0" }
+ , { "Transfer-Encoding", "chunked" }
+ }
+ ,.body= "OK"
+ ,.num_chunks_complete= 2
+ ,.chunk_lengths= { 2 }
+ }
+
+#define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER 22
+, {.name= "HTTP 101 response with Upgrade header"
+ ,.type= HTTP_RESPONSE
+ ,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
+ "Connection: upgrade\r\n"
+ "Upgrade: h2c\r\n"
+ "\r\n"
+ "proto"
+ ,.should_keep_alive= TRUE
+ ,.message_complete_on_eof= FALSE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.status_code= 101
+ ,.response_status= "Switching Protocols"
+ ,.upgrade= "proto"
+ ,.num_headers= 2
+ ,.headers=
+ { { "Connection", "upgrade" }
+ , { "Upgrade", "h2c" }
+ }
+ }
+
+#define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER_AND_CONTENT_LENGTH 23
+, {.name= "HTTP 101 response with Upgrade and Content-Length header"
+ ,.type= HTTP_RESPONSE
+ ,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
+ "Connection: upgrade\r\n"
+ "Upgrade: h2c\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"
+ "body"
+ "proto"
+ ,.should_keep_alive= TRUE
+ ,.message_complete_on_eof= FALSE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.status_code= 101
+ ,.response_status= "Switching Protocols"
+ ,.body= "body"
+ ,.upgrade= "proto"
+ ,.num_headers= 3
+ ,.headers=
+ { { "Connection", "upgrade" }
+ , { "Upgrade", "h2c" }
+ , { "Content-Length", "4" }
+ }
+ }
+
+#define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER_AND_TRANSFER_ENCODING 24
+, {.name= "HTTP 101 response with Upgrade and Transfer-Encoding header"
+ ,.type= HTTP_RESPONSE
+ ,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
+ "Connection: upgrade\r\n"
+ "Upgrade: h2c\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "2\r\n"
+ "bo\r\n"
+ "2\r\n"
+ "dy\r\n"
+ "0\r\n"
+ "\r\n"
+ "proto"
+ ,.should_keep_alive= TRUE
+ ,.message_complete_on_eof= FALSE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.status_code= 101
+ ,.response_status= "Switching Protocols"
+ ,.body= "body"
+ ,.upgrade= "proto"
+ ,.num_headers= 3
+ ,.headers=
+ { { "Connection", "upgrade" }
+ , { "Upgrade", "h2c" }
+ , { "Transfer-Encoding", "chunked" }
+ }
+ ,.num_chunks_complete= 3
+ ,.chunk_lengths= { 2, 2 }
+ }
+
+#define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER 25
+, {.name= "HTTP 200 response with Upgrade header"
+ ,.type= HTTP_RESPONSE
+ ,.raw= "HTTP/1.1 200 OK\r\n"
+ "Connection: upgrade\r\n"
+ "Upgrade: h2c\r\n"
+ "\r\n"
+ "body"
+ ,.should_keep_alive= FALSE
+ ,.message_complete_on_eof= TRUE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.status_code= 200
+ ,.response_status= "OK"
+ ,.body= "body"
+ ,.upgrade= NULL
+ ,.num_headers= 2
+ ,.headers=
+ { { "Connection", "upgrade" }
+ , { "Upgrade", "h2c" }
+ }
+ }
+
+#define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER_AND_CONTENT_LENGTH 26
+, {.name= "HTTP 200 response with Upgrade and Content-Length header"
+ ,.type= HTTP_RESPONSE
+ ,.raw= "HTTP/1.1 200 OK\r\n"
+ "Connection: upgrade\r\n"
+ "Upgrade: h2c\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"
+ "body"
+ ,.should_keep_alive= TRUE
+ ,.message_complete_on_eof= FALSE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.status_code= 200
+ ,.response_status= "OK"
+ ,.num_headers= 3
+ ,.body= "body"
+ ,.upgrade= NULL
+ ,.headers=
+ { { "Connection", "upgrade" }
+ , { "Upgrade", "h2c" }
+ , { "Content-Length", "4" }
+ }
+ }
+
+#define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER_AND_TRANSFER_ENCODING 27
+, {.name= "HTTP 200 response with Upgrade and Transfer-Encoding header"
+ ,.type= HTTP_RESPONSE
+ ,.raw= "HTTP/1.1 200 OK\r\n"
+ "Connection: upgrade\r\n"
+ "Upgrade: h2c\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "2\r\n"
+ "bo\r\n"
+ "2\r\n"
+ "dy\r\n"
+ "0\r\n"
+ "\r\n"
+ ,.should_keep_alive= TRUE
+ ,.message_complete_on_eof= FALSE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.status_code= 200
+ ,.response_status= "OK"
+ ,.num_headers= 3
+ ,.body= "body"
+ ,.upgrade= NULL
+ ,.headers=
+ { { "Connection", "upgrade" }
+ , { "Upgrade", "h2c" }
+ , { "Transfer-Encoding", "chunked" }
+ }
+ ,.num_chunks_complete= 3
+ ,.chunk_lengths= { 2, 2 }
+ }
+
, {.name= NULL } /* sentinel */
};
@@ -1955,6 +2163,9 @@ int
response_status_cb (http_parser *p, const char *buf, size_t len)
{
assert(p == parser);
+
+ messages[num_messages].status_cb_called = TRUE;
+
strlncat(messages[num_messages].response_status,
sizeof(messages[num_messages].response_status),
buf,
@@ -2379,6 +2590,7 @@ message_eq (int index, int connect, const struct message *expected)
} else {
MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
MESSAGE_CHECK_STR_EQ(expected, m, response_status);
+ assert(m->status_cb_called);
}
if (!connect) {
@@ -2450,7 +2662,9 @@ message_eq (int index, int connect, const struct message *expected)
if (!r) return 0;
}
- MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
+ if (!connect) {
+ MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
+ }
return 1;
}
@@ -3287,9 +3501,11 @@ test_message_count_body (const struct message *message)
}
void
-test_simple (const char *buf, enum http_errno err_expected)
+test_simple_type (const char *buf,
+ enum http_errno err_expected,
+ enum http_parser_type type)
{
- parser_init(HTTP_REQUEST);
+ parser_init(type);
enum http_errno err;
@@ -3314,6 +3530,12 @@ test_simple (const char *buf, enum http_errno err_expected)
}
void
+test_simple (const char *buf, enum http_errno err_expected)
+{
+ test_simple_type(buf, err_expected, HTTP_REQUEST);
+}
+
+void
test_invalid_header_content (int req, const char* str)
{
http_parser parser;
@@ -3463,6 +3685,30 @@ test_header_cr_no_lf_error (int req)
}
void
+test_no_overflow_parse_url (void)
+{
+ int rv;
+ struct http_parser_url u;
+
+ http_parser_url_init(&u);
+ rv = http_parser_parse_url("http://example.com:8001", 22, 0, &u);
+
+ if (rv != 0) {
+ fprintf(stderr,
+ "\n*** test_no_overflow_parse_url invalid return value=%d\n",
+ rv);
+ abort();
+ }
+
+ if (u.port != 800) {
+ fprintf(stderr,
+ "\n*** test_no_overflow_parse_url invalid port number=%d\n",
+ u.port);
+ abort();
+ }
+}
+
+void
test_header_overflow_error (int req)
{
http_parser parser;
@@ -3850,11 +4096,10 @@ test_message_connect (const struct message *msg)
{
char *buf = (char*) msg->raw;
size_t buflen = strlen(msg->raw);
- size_t nread;
parser_init(msg->type);
- nread = parse_connect(buf, buflen);
+ parse_connect(buf, buflen);
if (num_messages != 1) {
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
@@ -3898,6 +4143,7 @@ main (void)
test_header_nread_value();
//// OVERFLOW CONDITIONS
+ test_no_overflow_parse_url();
test_header_overflow_error(HTTP_REQUEST);
test_no_overflow_long_body(HTTP_REQUEST, 1000);
@@ -3924,6 +4170,12 @@ main (void)
//// RESPONSES
+ test_simple_type("HTP/1.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
+ test_simple_type("HTTP/01.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
+ test_simple_type("HTTP/11.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
+ test_simple_type("HTTP/1.01 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
+ test_simple_type("HTTP/1.1\t200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
+
for (i = 0; i < response_count; i++) {
test_message(&responses[i]);
}
@@ -4001,6 +4253,9 @@ main (void)
/// REQUESTS
test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
+ test_simple("GET / HTTP/01.1\r\n\r\n", HPE_INVALID_VERSION);
+ test_simple("GET / HTTP/11.1\r\n\r\n", HPE_INVALID_VERSION);
+ test_simple("GET / HTTP/1.01\r\n\r\n", HPE_INVALID_VERSION);
// Extended characters - see nodejs/test/parallel/test-http-headers-obstext.js
test_simple("GET / HTTP/1.1\r\n"