Commit 7a960813 authored by Witold Krecicki's avatar Witold Krecicki Committed by Ondřej Surý
Browse files

nghttp2-based HTTP layer in netmgr

This commit includes work-in-progress implementation of
DNS-over-HTTP(S).

Server-side code remains mostly untested, and there is only support
for POST requests.
parent cdf9d217
......@@ -285,6 +285,7 @@ stages:
"with-openssl=C:/OpenSSL"
"with-libxml2=C:/libxml2"
"with-libuv=C:/libuv"
"with-nghttp2=C:/nghttp2"
"without-python"
"with-system-tests"
x64'
......
......@@ -367,3 +367,25 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-----------------------------------------------------------------------------
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
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.
......@@ -138,7 +138,8 @@ const FileData installFiles[] =
{"libdns.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
{"libirs.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
{"libeay32.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
{"libuv.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
{"nghttp2.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
{"uv.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
#ifdef HAVE_LIBXML2
{"libxml2.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
#endif
......
......@@ -124,7 +124,7 @@ AS_IF([test "$enable_static" != "no" && test "$enable_developer" != "yes"],
#
# Set the default CFLAGS and CPPFLAGS
#
STD_CFLAGS="-Wall -Wextra -Wwrite-strings -Wcast-qual -Wpointer-arith -Wno-missing-field-initializers -Wformat -Wshadow"
STD_CFLAGS="-Wall -Wextra -Wwrite-strings -Wpointer-arith -Wno-missing-field-initializers -Wformat -Wshadow"
# These should be always errors
STD_CFLAGS="$STD_CFLAGS -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=format-security -Werror=parentheses -Werror=implicit -Werror=strict-prototypes"
......@@ -574,6 +574,15 @@ LIBS="$LIBS $LIBUV_LIBS"
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data uv_import uv_udp_connect uv_translate_sys_error])
AX_RESTORE_FLAGS([libuv])
# libnghttp2
AC_MSG_CHECKING([for libnghttp2])
PKG_CHECK_MODULES([LIBNGHTTP2], [libnghttp2 >= 1.6.0], [],
[AC_MSG_ERROR([libnghttp2 not found])])
AX_SAVE_FLAGS([libnghttp2])
CFLAGS="$CFLAGS $LIBNGHTTP2_CFLAGS"
LIBS="$LIBS $LIBNGHTTP2_LIBS"
#
# flockfile is usually provided by pthreads
#
......
......@@ -90,6 +90,7 @@ libisc_la_HEADERS = \
include/isc/tls.h \
include/isc/tm.h \
include/isc/types.h \
include/isc/url.h \
include/isc/utf8.h \
include/isc/util.h \
pthreads/include/isc/condition.h\
......@@ -124,6 +125,7 @@ libisc_la_SOURCES = \
$(libisc_la_HEADERS) \
$(pk11_HEADERS) \
$(pkcs11_HEADERS) \
netmgr/http.c \
netmgr/netmgr-int.h \
netmgr/netmgr.c \
netmgr/tcp.c \
......@@ -150,6 +152,7 @@ libisc_la_SOURCES = \
unix/stdtime.c \
unix/syslog.c \
unix/time.c \
url.c \
pk11.c \
pk11_result.c \
aes.c \
......
......@@ -505,3 +505,42 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
* The connected socket can only be accessed via the handle passed to
* 'cb'.
*/
typedef void (*isc_nm_http_cb_t)(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *postdata, isc_region_t *getdata,
void *cbarg);
/*%<
* Callback function to be used when receiving an HTTP request.
*
* 'handle' the handle that can be used to send back the answer.
* 'eresult' the result of the event.
* 'postdata' contains the received POST data, if any. It will be freed
* after return by caller.
* 'getdata' contains the received GET data (past '?'), if any. It will be
* freed after return by caller.
* 'cbarg' the callback argument passed to listen function.
*/
isc_result_t
isc_nm_doh_request(isc_nm_t *mgr, const char *uri, isc_region_t *message,
isc_nm_recv_cb_t cb, void *cbarg, isc_ssl_ctx_t *ctx);
isc_result_t
isc_nm_httpsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
const char *uri, isc_nm_cb_t cb, void *cbarg,
unsigned int timeout, size_t extrahandlesize);
isc_result_t
isc_nm_listenhttps(isc_nm_t *mgr, isc_nmiface_t *iface, int backlog,
isc_quota_t *quota, isc_ssl_ctx_t *ctx,
isc_nmsocket_t **sockp);
isc_result_t
isc_nm_http_add_endpoint(isc_nmsocket_t *sock, const char *uri,
isc_nm_http_cb_t cb, void *cbarg,
size_t extrahandlesize);
isc_result_t
isc_nm_http_add_doh_endpoint(isc_nmsocket_t *sock, const char *uri,
isc_nm_recv_cb_t cb, void *cbarg,
size_t extrahandlesize);
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*
* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* 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 <stdbool.h>
#include <stdint.h>
#include <isc/result.h>
/*
* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
#define HTTP_PARSER_STRICT 1
#endif
typedef enum {
ISC_UF_SCHEMA = 0,
ISC_UF_HOST = 1,
ISC_UF_PORT = 2,
ISC_UF_PATH = 3,
ISC_UF_QUERY = 4,
ISC_UF_FRAGMENT = 5,
ISC_UF_USERINFO = 6,
ISC_UF_MAX = 7
} isc_url_field_t;
/* Result structure for isc_url_parse().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
typedef struct {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[ISC_UF_MAX];
} isc_url_parser_t;
isc_result_t
isc_url_parse(const char *buf, size_t buflen, bool is_connect,
isc_url_parser_t *up);
/*%<
* Parse a URL; return nonzero on failure
*/
This diff is collapsed.
......@@ -155,6 +155,8 @@ isc__nm_dump_active(isc_nm_t *nm);
#define isc__nmsocket_prep_destroy(sock) isc___nmsocket_prep_destroy(sock)
#endif
typedef struct isc_nm_http2_session isc_nm_http2_session_t;
/*
* Single network event loop worker.
*/
......@@ -207,6 +209,8 @@ struct isc_nmhandle {
isc_nmsocket_t *sock;
size_t ah_pos; /* Position in the socket's 'active handles' array */
isc_nm_http2_session_t *httpsession;
isc_sockaddr_t peer;
isc_sockaddr_t local;
isc_nm_opaquecb_t doreset; /* reset extra callback, external */
......@@ -293,11 +297,22 @@ typedef enum isc__netievent_type {
typedef union {
isc_nm_recv_cb_t recv;
isc_nm_http_cb_t http;
isc_nm_cb_t send;
isc_nm_cb_t connect;
isc_nm_accept_cb_t accept;
} isc__nm_cb_t;
typedef struct isc_nm_http2_server_handler isc_nm_http2_server_handler_t;
struct isc_nm_http2_server_handler {
char *path;
isc_nm_http_cb_t cb;
void *cbarg;
size_t extrahandlesize;
LINK(isc_nm_http2_server_handler_t) link;
};
/*
* Wrapper around uv_req_t with 'our' fields in it. req->data should
* always point to its parent. Note that we always allocate more than
......@@ -652,7 +667,9 @@ typedef enum isc_nmsocket_type {
isc_nm_tlslistener,
isc_nm_tlssocket,
isc_nm_tlsdnslistener,
isc_nm_tlsdnssocket
isc_nm_tlsdnssocket,
isc_nm_httplistener,
isc_nm_httpstream
} isc_nmsocket_type;
/*%
......@@ -684,12 +701,26 @@ typedef struct isc_nmsocket_tls_send_req {
isc_region_t data;
} isc_nmsocket_tls_send_req_t;
typedef struct isc_nmsocket_h2 {
isc_nmsocket_t *psock; /* owner of the structure */
char *request_path;
char *query_data;
isc_nm_http2_server_handler_t *handler;
uint8_t buf[65535];
size_t bufsize;
size_t bufpos;
int32_t stream_id;
LINK(struct isc_nmsocket_h2) link;
} isc_nmsocket_h2_t;
struct isc_nmsocket {
/*% Unlocked, RO */
int magic;
int tid;
isc_nmsocket_type type;
isc_nm_t *mgr;
/*% Parent socket for multithreaded listeners */
isc_nmsocket_t *parent;
/*% Listener socket this connection was accepted on */
......@@ -740,6 +771,7 @@ struct isc_nmsocket {
ISC_LIST(isc__nm_uvreq_t) sends;
} tlsstream;
isc_nmsocket_h2_t h2;
/*%
* quota is the TCP client, attached when a TCP connection
* is established. pquota is a non-attached pointer to the
......@@ -941,6 +973,9 @@ struct isc_nmsocket {
void *accept_cbarg;
atomic_int_fast32_t active_child_connections;
ISC_LIST(isc_nm_http2_server_handler_t) handlers;
#ifdef NETMGR_TRACE
void *backtrace[TRACE_SIZE];
int backtrace_size;
......@@ -1105,8 +1140,8 @@ isc__nm_async_shutdown(isc__networker_t *worker, isc__netievent_t *ev0);
*/
void
isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg);
isc__nm_udp_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
/*%<
* Back-end implementation of isc_nm_send() for UDP handles.
*/
......@@ -1167,8 +1202,8 @@ isc__nm_async_udpclose(isc__networker_t *worker, isc__netievent_t *ev0);
*/
void
isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg);
isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
/*%<
* Back-end implementation of isc_nm_send() for TCP handles.
*/
......@@ -1349,6 +1384,10 @@ void
isc__nm_tlsdns_send(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_tls_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_tls_cancelread(isc_nmhandle_t *handle);
......@@ -1405,10 +1444,6 @@ isc__nm_tlsdns_cancelread(isc_nmhandle_t *handle);
* Stop reading on a connected TLSDNS handle.
*/
void
isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg);
void
isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
......@@ -1437,6 +1472,10 @@ isc__nm_tls_cleanup_data(isc_nmsocket_t *sock);
void
isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_http_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
#define isc__nm_uverr2result(x) \
isc___nm_uverr2result(x, true, __FILE__, __LINE__, __func__)
isc_result_t
......
......@@ -1696,6 +1696,9 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_send(handle, region, cb, cbarg);
break;
case isc_nm_httpstream:
isc__nm_http_send(handle, region, cb, cbarg);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
......
......@@ -1155,8 +1155,8 @@ failure:
}
void
isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg) {
isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
......
......@@ -559,11 +559,12 @@ isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0) {
}
void
isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg) {
isc__nm_tls_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg) {
isc__netievent_tlssend_t *ievent = NULL;
isc__nm_uvreq_t *uvreq = NULL;
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
......@@ -875,7 +876,6 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
if (result != ISC_R_SUCCESS) {
goto error;
}
return;
error:
tlshandle = isc__nmhandle_get(tlssock, NULL, NULL);
......
......@@ -478,8 +478,8 @@ free:
* another thread.
*/
void
isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg) {
isc__nm_udp_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg) {
isc_nmsocket_t *sock = handle->sock;
isc_nmsocket_t *psock = NULL, *rsock = sock;
isc_sockaddr_t *peer = &handle->peer;
......
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*
* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* 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 <ctype.h>
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include <isc/url.h>
#include <isc/util.h>
#ifndef BIT_AT
#define BIT_AT(a, i) \
(!!((unsigned int)(a)[(unsigned int)(i) >> 3] & \
(1 << ((unsigned int)(i)&7))))
#endif
#if HTTP_PARSER_STRICT
#define T(v) 0
#else
#define T(v) v
#endif
static const uint8_t normal_url_char[32] = {
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
};
#undef T
typedef enum {
s_dead = 1, /* important that this is > 0 */
s_start_req_or_res,
s_res_or_resp_H,
s_start_res,
s_res_H,
s_res_HT,
s_res_HTT,
s_res_HTTP,
s_res_http_major,
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,
s_res_status,
s_res_line_almost_done,
s_start_req,
s_req_method,
s_req_spaces_before_url,
s_req_schema,
s_req_schema_slash,
s_req_schema_slash_slash,
s_req_server_start,
s_req_server,
s_req_server_with_at,
s_req_path,
s_req_query_string_start,
s_req_query_string,
s_req_fragment_start,
s_req_fragment,
s_req_http_start,
s_req_http_H,
s_req_http_HT,
s_req_http_HTT,
s_req_http_HTTP,
s_req_http_I,
s_req_http_IC,
s_req_http_major,
s_req_http_dot,
s_req_http_minor,
s_req_http_end,
s_req_line_almost_done,
s_header_field_start,
s_header_field,
s_header_value_discard_ws,
s_header_value_discard_ws_almost_done,
s_header_value_discard_lws,
s_header_value_start,
s_header_value,
s_header_value_lws,
s_header_almost_done,
s_chunk_size_start,
s_chunk_size,
s_chunk_parameters,
s_chunk_size_almost_done,
s_headers_almost_done,
s_headers_done,
/*
* Important: 's_headers_done' must be the last 'header' state. All
* states beyond this must be 'body' states. It is used for overflow
* checking. See the PARSING_HEADER() macro.
*/
s_chunk_data,
s_chunk_data_almost_done,
s_chunk_data_done,
s_body_identity,
s_body_identity_eof,
s_message_done
} state_t;
typedef enum {
s_http_host_dead = 1,
s_http_userinfo_start,
s_http_userinfo,
s_http_host_start,
s_http_host_v6_start,
s_http_host,
s_http_host_v6,
s_http_host_v6_end,
s_http_host_v6_zone_start,
s_http_host_v6_zone,
s_http_host_port_start,
s_http_host_port
} host_state_t;
/* Macros for character classes; depends on strict-mode */
#define IS_MARK(c) \
((c) == '-' || (c) == '_' || (c) == '.' || (c) == '!' || (c) == '~' || \
(c) == '*' || (c) == '\'' || (c) == '(' || (c) == ')')
#define IS_USERINFO_CHAR(c) \
(isalnum(c) || IS_MARK(c) || (c) == '%' || (c) == ';' || (c) == ':' || \
(c) == '&' || (c) == '=' || (c) == '+' || (c) == '$' || (c) == ',')
#if HTTP_PARSER_STRICT
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
#define IS_HOST_CHAR(c) (isalnum(c) || (c) == '.' || (c) == '-')
#else
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c) || ((c)&0x80))
#define IS_HOST_CHAR(c) (isalnum(c) || (c) == '.' || (c) == '-' || (c) == '_')
#endif