winlin

copy http-parser-2.1 into srs http stack.

@@ -439,42 +439,7 @@ fi @@ -439,42 +439,7 @@ fi
439 ##################################################################################### 439 #####################################################################################
440 # check the cross build flag file, if flag changed, need to rebuild the st. 440 # check the cross build flag file, if flag changed, need to rebuild the st.
441 if [ $SRS_HTTP_CORE = YES ]; then 441 if [ $SRS_HTTP_CORE = YES ]; then
442 - # ok, arm specified, if the flag filed does not exists, need to rebuild.  
443 - if [ $SRS_CROSS_BUILD = YES ]; then  
444 - if [[ -f ${SRS_OBJS}/_flag.st.hp.tmp && -f ${SRS_OBJS}/hp/http_parser.h && -f ${SRS_OBJS}/hp/libhttp_parser.a ]]; then  
445 - echo "http-parser-2.1 for arm is ok.";  
446 - else  
447 - echo "build http-parser-2.1 for arm";  
448 - (  
449 - rm -rf ${SRS_OBJS}/http-parser-2.1 && cd ${SRS_OBJS} && unzip -q ../3rdparty/http-parser-2.1.zip &&  
450 - cd http-parser-2.1 &&  
451 - patch -p0 < ../../3rdparty/patches/2.http.parser.patch &&  
452 - make CC=${SrsArmCC} AR=${SrsArmAR} package &&  
453 - cd .. && rm -rf hp && ln -sf http-parser-2.1 hp &&  
454 - cd .. && touch ${SRS_OBJS}/_flag.st.hp.tmp  
455 - )  
456 - fi  
457 - else  
458 - # cross build not specified, if exists flag, need to rebuild for no-arm platform.  
459 - if [[ ! -f ${SRS_OBJS}/_flag.st.hp.tmp && -f ${SRS_OBJS}/hp/http_parser.h && -f ${SRS_OBJS}/hp/libhttp_parser.a ]]; then  
460 - echo "http-parser-2.1 is ok.";  
461 - else  
462 - echo "build http-parser-2.1";  
463 - (  
464 - rm -rf ${SRS_OBJS}/http-parser-2.1 && cd ${SRS_OBJS} && unzip -q ../3rdparty/http-parser-2.1.zip &&  
465 - cd http-parser-2.1 &&  
466 - patch -p0 < ../../3rdparty/patches/2.http.parser.patch &&  
467 - make package &&  
468 - cd .. && rm -rf hp && ln -sf http-parser-2.1 hp &&  
469 - cd .. && rm -f ${SRS_OBJS}/_flag.st.hp.tmp  
470 - )  
471 - fi  
472 - fi  
473 -  
474 - # check status  
475 - ret=$?; if [[ $ret -ne 0 ]]; then echo "build http-parser-2.1 failed, ret=$ret"; exit $ret; fi  
476 - if [[ ! -f ${SRS_OBJS}/hp/http_parser.h ]]; then echo "build http-parser-2.1 failed"; exit -1; fi  
477 - if [[ ! -f ${SRS_OBJS}/hp/libhttp_parser.a ]]; then echo "build http-parser-2.1 failed"; exit -1; fi 442 + echo "http-parser is copied into srs_http_stack.*pp"
478 fi 443 fi
479 444
480 ##################################################################################### 445 #####################################################################################
@@ -116,9 +116,6 @@ END @@ -116,9 +116,6 @@ END
116 # 116 #
117 # st(state-threads) the basic network library for SRS. 117 # st(state-threads) the basic network library for SRS.
118 LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" 118 LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a"
119 -# hp(http-parser) the http request/url parser, for SRS to support HTTP callback.  
120 -LibHttpParserRoot=""; LibHttpParserfile=""  
121 -if [ $SRS_HTTP_CORE = YES ]; then LibHttpParserRoot="${SRS_OBJS_DIR}/hp"; LibHttpParserfile="${LibHttpParserRoot}/libhttp_parser.a"; fi  
122 # openssl-1.0.1f, for the RTMP complex handshake. 119 # openssl-1.0.1f, for the RTMP complex handshake.
123 LibSSLRoot="";LibSSLfile="" 120 LibSSLRoot="";LibSSLfile=""
124 if [ $SRS_SSL = YES ]; then if [ $SRS_USE_SYS_SSL = NO ]; then LibSSLRoot="${SRS_OBJS_DIR}/openssl/include"; LibSSLfile="${SRS_OBJS_DIR}/openssl/lib/libssl.a ${SRS_OBJS_DIR}/openssl/lib/libcrypto.a"; fi fi 121 if [ $SRS_SSL = YES ]; then if [ $SRS_USE_SYS_SSL = NO ]; then LibSSLRoot="${SRS_OBJS_DIR}/openssl/include"; LibSSLfile="${SRS_OBJS_DIR}/openssl/lib/libssl.a ${SRS_OBJS_DIR}/openssl/lib/libcrypto.a"; fi fi
@@ -171,7 +168,7 @@ PROTOCOL_OBJS="${MODULE_OBJS[@]}" @@ -171,7 +168,7 @@ PROTOCOL_OBJS="${MODULE_OBJS[@]}"
171 if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then 168 if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
172 MODULE_ID="APP" 169 MODULE_ID="APP"
173 MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") 170 MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL")
174 - ModuleLibIncs=(${LibSTRoot} ${LibHttpParserRoot} ${LibSSLRoot} ${SRS_OBJS_DIR}) 171 + ModuleLibIncs=(${LibSTRoot} ${LibSSLRoot} ${SRS_OBJS_DIR})
175 MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" 172 MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source"
176 "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" 173 "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream"
177 "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" 174 "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config"
@@ -204,7 +201,7 @@ LIBS_OBJS="${MODULE_OBJS[@]}" @@ -204,7 +201,7 @@ LIBS_OBJS="${MODULE_OBJS[@]}"
204 if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then 201 if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
205 MODULE_ID="MAIN" 202 MODULE_ID="MAIN"
206 MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP") 203 MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP")
207 - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibHttpParserRoot} ${LibSSLRoot}) 204 + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot})
208 MODULE_FILES=("srs_main_server" "srs_main_ingest_hls") 205 MODULE_FILES=("srs_main_server" "srs_main_ingest_hls")
209 # add each modules for main 206 # add each modules for main
210 for SRS_MODULE in ${SRS_MODULES[*]}; do 207 for SRS_MODULE in ${SRS_MODULES[*]}; do
@@ -230,7 +227,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then @@ -230,7 +227,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
230 done 227 done
231 # 228 #
232 # all depends libraries 229 # all depends libraries
233 - ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile} ${LibGperfFile}) 230 + ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile})
234 # all depends objects 231 # all depends objects
235 MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}" 232 MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}"
236 LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}" 233 LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}"
@@ -260,7 +257,7 @@ if [ $SRS_UTEST = YES ]; then @@ -260,7 +257,7 @@ if [ $SRS_UTEST = YES ]; then
260 "srs_utest_kernel" "srs_utest_core" "srs_utest_config" 257 "srs_utest_kernel" "srs_utest_core" "srs_utest_config"
261 "srs_utest_reload") 258 "srs_utest_reload")
262 ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) 259 ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot})
263 - ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile}) 260 + ModuleLibFiles=(${LibSTfile} ${LibSSLfile})
264 MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP") 261 MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP")
265 MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]}" 262 MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]}"
266 LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh 263 LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh
@@ -1063,100 +1063,6 @@ int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length) @@ -1063,100 +1063,6 @@ int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length)
1063 return 0; 1063 return 0;
1064 } 1064 }
1065 1065
1066 -SrsHttpUri::SrsHttpUri()  
1067 -{  
1068 - port = SRS_DEFAULT_HTTP_PORT;  
1069 -}  
1070 -  
1071 -SrsHttpUri::~SrsHttpUri()  
1072 -{  
1073 -}  
1074 -  
1075 -int SrsHttpUri::initialize(string _url)  
1076 -{  
1077 - int ret = ERROR_SUCCESS;  
1078 -  
1079 - url = _url;  
1080 - const char* purl = url.c_str();  
1081 -  
1082 - http_parser_url hp_u;  
1083 - if((ret = http_parser_parse_url(purl, url.length(), 0, &hp_u)) != 0){  
1084 - int code = ret;  
1085 - ret = ERROR_HTTP_PARSE_URI;  
1086 -  
1087 - srs_error("parse url %s failed, code=%d, ret=%d", purl, code, ret);  
1088 - return ret;  
1089 - }  
1090 -  
1091 - std::string field = get_uri_field(url, &hp_u, UF_SCHEMA);  
1092 - if(!field.empty()){  
1093 - schema = field;  
1094 - }  
1095 -  
1096 - host = get_uri_field(url, &hp_u, UF_HOST);  
1097 -  
1098 - field = get_uri_field(url, &hp_u, UF_PORT);  
1099 - if(!field.empty()){  
1100 - port = atoi(field.c_str());  
1101 - }  
1102 -  
1103 - path = get_uri_field(url, &hp_u, UF_PATH);  
1104 - srs_info("parse url %s success", purl);  
1105 -  
1106 - query = get_uri_field(url, &hp_u, UF_QUERY);  
1107 - srs_info("parse query %s success", query.c_str());  
1108 -  
1109 - return ret;  
1110 -}  
1111 -  
1112 -string SrsHttpUri::get_url()  
1113 -{  
1114 - return url;  
1115 -}  
1116 -  
1117 -string SrsHttpUri::get_schema()  
1118 -{  
1119 - return schema;  
1120 -}  
1121 -  
1122 -string SrsHttpUri::get_host()  
1123 -{  
1124 - return host;  
1125 -}  
1126 -  
1127 -int SrsHttpUri::get_port()  
1128 -{  
1129 - return port;  
1130 -}  
1131 -  
1132 -string SrsHttpUri::get_path()  
1133 -{  
1134 - return path;  
1135 -}  
1136 -  
1137 -string SrsHttpUri::get_query()  
1138 -{  
1139 - return query;  
1140 -}  
1141 -  
1142 -string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field)  
1143 -{  
1144 - if((hp_u->field_set & (1 << field)) == 0){  
1145 - return "";  
1146 - }  
1147 -  
1148 - srs_verbose("uri field matched, off=%d, len=%d, value=%.*s",  
1149 - hp_u->field_data[field].off,  
1150 - hp_u->field_data[field].len,  
1151 - hp_u->field_data[field].len,  
1152 - uri.c_str() + hp_u->field_data[field].off);  
1153 -  
1154 - int offset = hp_u->field_data[field].off;  
1155 - int len = hp_u->field_data[field].len;  
1156 -  
1157 - return uri.substr(offset, len);  
1158 -}  
1159 -  
1160 SrsHttpConn::SrsHttpConn(IConnectionManager* cm, st_netfd_t fd, ISrsHttpServeMux* m) 1066 SrsHttpConn::SrsHttpConn(IConnectionManager* cm, st_netfd_t fd, ISrsHttpServeMux* m)
1161 : SrsConnection(cm, fd) 1067 : SrsConnection(cm, fd)
1162 { 1068 {
@@ -31,10 +31,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,10 +31,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #include <srs_core.hpp> 31 #include <srs_core.hpp>
32 32
33 #ifdef SRS_AUTO_HTTP_CORE 33 #ifdef SRS_AUTO_HTTP_CORE
34 -#include <http_parser.h>  
35 -#endif  
36 -  
37 -#ifdef SRS_AUTO_HTTP_CORE  
38 34
39 #include <map> 35 #include <map>
40 #include <string> 36 #include <string>
@@ -348,41 +344,6 @@ private: @@ -348,41 +344,6 @@ private:
348 static int on_body(http_parser* parser, const char* at, size_t length); 344 static int on_body(http_parser* parser, const char* at, size_t length);
349 }; 345 };
350 346
351 -/**  
352 - * used to resolve the http uri.  
353 - */  
354 -class SrsHttpUri  
355 -{  
356 -private:  
357 - std::string url;  
358 - std::string schema;  
359 - std::string host;  
360 - int port;  
361 - std::string path;  
362 - std::string query;  
363 -public:  
364 - SrsHttpUri();  
365 - virtual ~SrsHttpUri();  
366 -public:  
367 - /**  
368 - * initialize the http uri.  
369 - */  
370 - virtual int initialize(std::string _url);  
371 -public:  
372 - virtual std::string get_url();  
373 - virtual std::string get_schema();  
374 - virtual std::string get_host();  
375 - virtual int get_port();  
376 - virtual std::string get_path();  
377 - virtual std::string get_query();  
378 -private:  
379 - /**  
380 - * get the parsed url field.  
381 - * @return return empty string if not set.  
382 - */  
383 - virtual std::string get_uri_field(std::string uri, http_parser_url* hp_u, http_parser_url_fields field);  
384 -};  
385 -  
386 class SrsHttpConn : public SrsConnection 347 class SrsHttpConn : public SrsConnection
387 { 348 {
388 private: 349 private:
@@ -33,8 +33,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -33,8 +33,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 33
34 #ifdef SRS_AUTO_HTTP_CALLBACK 34 #ifdef SRS_AUTO_HTTP_CALLBACK
35 35
36 -#include <http_parser.h>  
37 -  
38 class SrsHttpUri; 36 class SrsHttpUri;
39 class SrsStSocket; 37 class SrsStSocket;
40 class SrsRequest; 38 class SrsRequest;
@@ -778,3 +778,2296 @@ char* ISrsHttpMessage::http_ts_send_buffer() @@ -778,3 +778,2296 @@ char* ISrsHttpMessage::http_ts_send_buffer()
778 778
779 #endif 779 #endif
780 780
  781 +/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
  782 +*
  783 +* Additional changes are licensed under the same terms as NGINX and
  784 +* copyright Joyent, Inc. and other Node contributors. All rights reserved.
  785 +*
  786 +* Permission is hereby granted, free of charge, to any person obtaining a copy
  787 +* of this software and associated documentation files (the "Software"), to
  788 +* deal in the Software without restriction, including without limitation the
  789 +* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  790 +* sell copies of the Software, and to permit persons to whom the Software is
  791 +* furnished to do so, subject to the following conditions:
  792 +*
  793 +* The above copyright notice and this permission notice shall be included in
  794 +* all copies or substantial portions of the Software.
  795 +*
  796 +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  797 +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  798 +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  799 +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  800 +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  801 +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  802 +* IN THE SOFTWARE.
  803 +*/
  804 +//#include "http_parser.h"
  805 +#include <assert.h>
  806 +#include <stddef.h>
  807 +#include <ctype.h>
  808 +#include <stdlib.h>
  809 +#include <string.h>
  810 +#include <limits.h>
  811 +
  812 +#ifndef ULLONG_MAX
  813 +# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
  814 +#endif
  815 +
  816 +#ifndef MIN
  817 +# define MIN(a,b) ((a) < (b) ? (a) : (b))
  818 +#endif
  819 +
  820 +#ifndef ARRAY_SIZE
  821 +# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  822 +#endif
  823 +
  824 +#ifndef BIT_AT
  825 +# define BIT_AT(a, i) \
  826 +(!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
  827 +(1 << ((unsigned int) (i) & 7))))
  828 +#endif
  829 +
  830 +#ifndef ELEM_AT
  831 +# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
  832 +#endif
  833 +
  834 +#define SET_ERRNO(e) \
  835 +do { \
  836 +parser->http_errno = (e); \
  837 +} while(0)
  838 +
  839 +
  840 +/* Run the notify callback FOR, returning ER if it fails */
  841 +#define CALLBACK_NOTIFY_(FOR, ER) \
  842 +do { \
  843 +assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
  844 +\
  845 +if (settings->on_##FOR) { \
  846 +if (0 != settings->on_##FOR(parser)) { \
  847 +SET_ERRNO(HPE_CB_##FOR); \
  848 +} \
  849 +\
  850 +/* We either errored above or got paused; get out */ \
  851 +if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
  852 +return (ER); \
  853 +} \
  854 +} \
  855 +} while (0)
  856 +
  857 +/* Run the notify callback FOR and consume the current byte */
  858 +#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
  859 +
  860 +/* Run the notify callback FOR and don't consume the current byte */
  861 +#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
  862 +
  863 +/* Run data callback FOR with LEN bytes, returning ER if it fails */
  864 +#define CALLBACK_DATA_(FOR, LEN, ER) \
  865 +do { \
  866 +assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
  867 +\
  868 +if (FOR##_mark) { \
  869 +if (settings->on_##FOR) { \
  870 +if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \
  871 +SET_ERRNO(HPE_CB_##FOR); \
  872 +} \
  873 +\
  874 +/* We either errored above or got paused; get out */ \
  875 +if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
  876 +return (ER); \
  877 +} \
  878 +} \
  879 +FOR##_mark = NULL; \
  880 +} \
  881 +} while (0)
  882 +
  883 +/* Run the data callback FOR and consume the current byte */
  884 +#define CALLBACK_DATA(FOR) \
  885 +CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
  886 +
  887 +/* Run the data callback FOR and don't consume the current byte */
  888 +#define CALLBACK_DATA_NOADVANCE(FOR) \
  889 +CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
  890 +
  891 +/* Set the mark FOR; non-destructive if mark is already set */
  892 +#define MARK(FOR) \
  893 +do { \
  894 +if (!FOR##_mark) { \
  895 +FOR##_mark = p; \
  896 +} \
  897 +} while (0)
  898 +
  899 +
  900 +#define PROXY_CONNECTION "proxy-connection"
  901 +#define CONNECTION "connection"
  902 +#define CONTENT_LENGTH "content-length"
  903 +#define TRANSFER_ENCODING "transfer-encoding"
  904 +#define UPGRADE "upgrade"
  905 +#define CHUNKED "chunked"
  906 +#define KEEP_ALIVE "keep-alive"
  907 +#define CLOSE "close"
  908 +
  909 +
  910 +static const char *method_strings[] =
  911 +{
  912 +#define XX(num, name, string) #string,
  913 + HTTP_METHOD_MAP(XX)
  914 +#undef XX
  915 +};
  916 +
  917 +
  918 +/* Tokens as defined by rfc 2616. Also lowercases them.
  919 + * token = 1*<any CHAR except CTLs or separators>
  920 + * separators = "(" | ")" | "<" | ">" | "@"
  921 + * | "," | ";" | ":" | "\" | <">
  922 + * | "/" | "[" | "]" | "?" | "="
  923 + * | "{" | "}" | SP | HT
  924 + */
  925 +static const char tokens[256] = {
  926 + /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
  927 + 0, 0, 0, 0, 0, 0, 0, 0,
  928 + /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
  929 + 0, 0, 0, 0, 0, 0, 0, 0,
  930 + /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
  931 + 0, 0, 0, 0, 0, 0, 0, 0,
  932 + /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
  933 + 0, 0, 0, 0, 0, 0, 0, 0,
  934 + /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
  935 + 0, '!', 0, '#', '$', '%', '&', '\'',
  936 + /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
  937 + 0, 0, '*', '+', 0, '-', '.', 0,
  938 + /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
  939 + '0', '1', '2', '3', '4', '5', '6', '7',
  940 + /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
  941 + '8', '9', 0, 0, 0, 0, 0, 0,
  942 + /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
  943 + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
  944 + /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
  945 + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
  946 + /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
  947 + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
  948 + /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
  949 + 'x', 'y', 'z', 0, 0, 0, '^', '_',
  950 + /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
  951 + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
  952 + /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
  953 + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
  954 + /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
  955 + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
  956 + /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
  957 + 'x', 'y', 'z', 0, '|', 0, '~', 0 };
  958 +
  959 +
  960 +static const int8_t unhex[256] =
  961 +{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  962 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  963 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  964 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
  965 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
  966 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  967 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
  968 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  969 +};
  970 +
  971 +
  972 +#if HTTP_PARSER_STRICT
  973 +# define T(v) 0
  974 +#else
  975 +# define T(v) v
  976 +#endif
  977 +
  978 +
  979 +static const uint8_t normal_url_char[32] = {
  980 + /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
  981 + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
  982 + /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
  983 + 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
  984 + /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
  985 + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
  986 + /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
  987 + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
  988 + /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
  989 + 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
  990 + /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
  991 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  992 + /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
  993 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  994 + /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
  995 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
  996 + /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
  997 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  998 + /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
  999 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  1000 + /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
  1001 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  1002 + /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
  1003 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  1004 + /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
  1005 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  1006 + /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
  1007 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  1008 + /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
  1009 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
  1010 + /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
  1011 + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
  1012 +
  1013 +#undef T
  1014 +
  1015 +enum state
  1016 +{ s_dead = 1 /* important that this is > 0 */
  1017 +
  1018 + , s_start_req_or_res
  1019 + , s_res_or_resp_H
  1020 + , s_start_res
  1021 + , s_res_H
  1022 + , s_res_HT
  1023 + , s_res_HTT
  1024 + , s_res_HTTP
  1025 + , s_res_first_http_major
  1026 + , s_res_http_major
  1027 + , s_res_first_http_minor
  1028 + , s_res_http_minor
  1029 + , s_res_first_status_code
  1030 + , s_res_status_code
  1031 + , s_res_status
  1032 + , s_res_line_almost_done
  1033 +
  1034 + , s_start_req
  1035 +
  1036 + , s_req_method
  1037 + , s_req_spaces_before_url
  1038 + , s_req_schema
  1039 + , s_req_schema_slash
  1040 + , s_req_schema_slash_slash
  1041 + , s_req_server_start
  1042 + , s_req_server
  1043 + , s_req_server_with_at
  1044 + , s_req_path
  1045 + , s_req_query_string_start
  1046 + , s_req_query_string
  1047 + , s_req_fragment_start
  1048 + , s_req_fragment
  1049 + , s_req_http_start
  1050 + , s_req_http_H
  1051 + , s_req_http_HT
  1052 + , s_req_http_HTT
  1053 + , s_req_http_HTTP
  1054 + , s_req_first_http_major
  1055 + , s_req_http_major
  1056 + , s_req_first_http_minor
  1057 + , s_req_http_minor
  1058 + , s_req_line_almost_done
  1059 +
  1060 + , s_header_field_start
  1061 + , s_header_field
  1062 + , s_header_value_start
  1063 + , s_header_value
  1064 + , s_header_value_lws
  1065 +
  1066 + , s_header_almost_done
  1067 +
  1068 + , s_chunk_size_start
  1069 + , s_chunk_size
  1070 + , s_chunk_parameters
  1071 + , s_chunk_size_almost_done
  1072 +
  1073 + , s_headers_almost_done
  1074 + , s_headers_done
  1075 +
  1076 + /* Important: 's_headers_done' must be the last 'header' state. All
  1077 + * states beyond this must be 'body' states. It is used for overflow
  1078 + * checking. See the PARSING_HEADER() macro.
  1079 + */
  1080 +
  1081 + , s_chunk_data
  1082 + , s_chunk_data_almost_done
  1083 + , s_chunk_data_done
  1084 +
  1085 + , s_body_identity
  1086 + , s_body_identity_eof
  1087 +
  1088 + , s_message_done
  1089 +};
  1090 +
  1091 +
  1092 +#define PARSING_HEADER(state) (state <= s_headers_done)
  1093 +
  1094 +
  1095 +enum header_states
  1096 +{ h_general = 0
  1097 + , h_C
  1098 + , h_CO
  1099 + , h_CON
  1100 +
  1101 + , h_matching_connection
  1102 + , h_matching_proxy_connection
  1103 + , h_matching_content_length
  1104 + , h_matching_transfer_encoding
  1105 + , h_matching_upgrade
  1106 +
  1107 + , h_connection
  1108 + , h_content_length
  1109 + , h_transfer_encoding
  1110 + , h_upgrade
  1111 +
  1112 + , h_matching_transfer_encoding_chunked
  1113 + , h_matching_connection_keep_alive
  1114 + , h_matching_connection_close
  1115 +
  1116 + , h_transfer_encoding_chunked
  1117 + , h_connection_keep_alive
  1118 + , h_connection_close
  1119 +};
  1120 +
  1121 +enum http_host_state
  1122 +{
  1123 + s_http_host_dead = 1
  1124 + , s_http_userinfo_start
  1125 + , s_http_userinfo
  1126 + , s_http_host_start
  1127 + , s_http_host_v6_start
  1128 + , s_http_host
  1129 + , s_http_host_v6
  1130 + , s_http_host_v6_end
  1131 + , s_http_host_port_start
  1132 + , s_http_host_port
  1133 +};
  1134 +
  1135 +/* Macros for character classes; depends on strict-mode */
  1136 +#define CR '\r'
  1137 +#define LF '\n'
  1138 +#define LOWER(c) (unsigned char)(c | 0x20)
  1139 +#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
  1140 +#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
  1141 +#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
  1142 +#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
  1143 +#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
  1144 +(c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
  1145 +(c) == ')')
  1146 +#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
  1147 +(c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
  1148 +(c) == '$' || (c) == ',')
  1149 +
  1150 +#if HTTP_PARSER_STRICT
  1151 +#define TOKEN(c) (tokens[(unsigned char)c])
  1152 +#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
  1153 +#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
  1154 +#else
  1155 +#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
  1156 +#define IS_URL_CHAR(c) \
  1157 +(BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
  1158 +#define IS_HOST_CHAR(c) \
  1159 +(IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
  1160 +#endif
  1161 +
  1162 +
  1163 +#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
  1164 +
  1165 +
  1166 +#if HTTP_PARSER_STRICT
  1167 +# define STRICT_CHECK(cond) \
  1168 +do { \
  1169 +if (cond) { \
  1170 +SET_ERRNO(HPE_STRICT); \
  1171 +goto error; \
  1172 +} \
  1173 +} while (0)
  1174 +# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
  1175 +#else
  1176 +# define STRICT_CHECK(cond)
  1177 +# define NEW_MESSAGE() start_state
  1178 +#endif
  1179 +
  1180 +
  1181 +/* Map errno values to strings for human-readable output */
  1182 +#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
  1183 +static struct {
  1184 + const char *name;
  1185 + const char *description;
  1186 +} http_strerror_tab[] = {
  1187 + HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
  1188 +};
  1189 +#undef HTTP_STRERROR_GEN
  1190 +
  1191 +int http_message_needs_eof(const http_parser *parser);
  1192 +
  1193 +/* Our URL parser.
  1194 + *
  1195 + * This is designed to be shared by http_parser_execute() for URL validation,
  1196 + * hence it has a state transition + byte-for-byte interface. In addition, it
  1197 + * is meant to be embedded in http_parser_parse_url(), which does the dirty
  1198 + * work of turning state transitions URL components for its API.
  1199 + *
  1200 + * This function should only be invoked with non-space characters. It is
  1201 + * assumed that the caller cares about (and can detect) the transition between
  1202 + * URL and non-URL states by looking for these.
  1203 + */
  1204 +static enum state
  1205 +parse_url_char(enum state s, const char ch)
  1206 +{
  1207 + if (ch == ' ' || ch == '\r' || ch == '\n') {
  1208 + return s_dead;
  1209 + }
  1210 +
  1211 +#if HTTP_PARSER_STRICT
  1212 + if (ch == '\t' || ch == '\f') {
  1213 + return s_dead;
  1214 + }
  1215 +#endif
  1216 +
  1217 + switch (s) {
  1218 + case s_req_spaces_before_url:
  1219 + /* Proxied requests are followed by scheme of an absolute URI (alpha).
  1220 + * All methods except CONNECT are followed by '/' or '*'.
  1221 + */
  1222 +
  1223 + if (ch == '/' || ch == '*') {
  1224 + return s_req_path;
  1225 + }
  1226 +
  1227 + if (IS_ALPHA(ch)) {
  1228 + return s_req_schema;
  1229 + }
  1230 +
  1231 + break;
  1232 +
  1233 + case s_req_schema:
  1234 + if (IS_ALPHA(ch)) {
  1235 + return s;
  1236 + }
  1237 +
  1238 + if (ch == ':') {
  1239 + return s_req_schema_slash;
  1240 + }
  1241 +
  1242 + break;
  1243 +
  1244 + case s_req_schema_slash:
  1245 + if (ch == '/') {
  1246 + return s_req_schema_slash_slash;
  1247 + }
  1248 +
  1249 + break;
  1250 +
  1251 + case s_req_schema_slash_slash:
  1252 + if (ch == '/') {
  1253 + return s_req_server_start;
  1254 + }
  1255 +
  1256 + break;
  1257 +
  1258 + case s_req_server_with_at:
  1259 + if (ch == '@') {
  1260 + return s_dead;
  1261 + }
  1262 +
  1263 + /* FALLTHROUGH */
  1264 + case s_req_server_start:
  1265 + case s_req_server:
  1266 + if (ch == '/') {
  1267 + return s_req_path;
  1268 + }
  1269 +
  1270 + if (ch == '?') {
  1271 + return s_req_query_string_start;
  1272 + }
  1273 +
  1274 + if (ch == '@') {
  1275 + return s_req_server_with_at;
  1276 + }
  1277 +
  1278 + if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
  1279 + return s_req_server;
  1280 + }
  1281 +
  1282 + break;
  1283 +
  1284 + case s_req_path:
  1285 + if (IS_URL_CHAR(ch)) {
  1286 + return s;
  1287 + }
  1288 +
  1289 + switch (ch) {
  1290 + case '?':
  1291 + return s_req_query_string_start;
  1292 +
  1293 + case '#':
  1294 + return s_req_fragment_start;
  1295 + }
  1296 +
  1297 + break;
  1298 +
  1299 + case s_req_query_string_start:
  1300 + case s_req_query_string:
  1301 + if (IS_URL_CHAR(ch)) {
  1302 + return s_req_query_string;
  1303 + }
  1304 +
  1305 + switch (ch) {
  1306 + case '?':
  1307 + /* allow extra '?' in query string */
  1308 + return s_req_query_string;
  1309 +
  1310 + case '#':
  1311 + return s_req_fragment_start;
  1312 + }
  1313 +
  1314 + break;
  1315 +
  1316 + case s_req_fragment_start:
  1317 + if (IS_URL_CHAR(ch)) {
  1318 + return s_req_fragment;
  1319 + }
  1320 +
  1321 + switch (ch) {
  1322 + case '?':
  1323 + return s_req_fragment;
  1324 +
  1325 + case '#':
  1326 + return s;
  1327 + }
  1328 +
  1329 + break;
  1330 +
  1331 + case s_req_fragment:
  1332 + if (IS_URL_CHAR(ch)) {
  1333 + return s;
  1334 + }
  1335 +
  1336 + switch (ch) {
  1337 + case '?':
  1338 + case '#':
  1339 + return s;
  1340 + }
  1341 +
  1342 + break;
  1343 +
  1344 + default:
  1345 + break;
  1346 + }
  1347 +
  1348 + /* We should never fall out of the switch above unless there's an error */
  1349 + return s_dead;
  1350 +}
  1351 +
  1352 +size_t http_parser_execute (http_parser *parser,
  1353 + const http_parser_settings *settings,
  1354 + const char *data,
  1355 + size_t len)
  1356 +{
  1357 + char c, ch;
  1358 + int8_t unhex_val;
  1359 + const char *p = data;
  1360 + const char *header_field_mark = 0;
  1361 + const char *header_value_mark = 0;
  1362 + const char *url_mark = 0;
  1363 + const char *body_mark = 0;
  1364 +
  1365 + /* We're in an error state. Don't bother doing anything. */
  1366 + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
  1367 + return 0;
  1368 + }
  1369 +
  1370 + if (len == 0) {
  1371 + switch (parser->state) {
  1372 + case s_body_identity_eof:
  1373 + /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
  1374 + * we got paused.
  1375 + */
  1376 + CALLBACK_NOTIFY_NOADVANCE(message_complete);
  1377 + return 0;
  1378 +
  1379 + case s_dead:
  1380 + case s_start_req_or_res:
  1381 + case s_start_res:
  1382 + case s_start_req:
  1383 + return 0;
  1384 +
  1385 + default:
  1386 + SET_ERRNO(HPE_INVALID_EOF_STATE);
  1387 + return 1;
  1388 + }
  1389 + }
  1390 +
  1391 +
  1392 + if (parser->state == s_header_field)
  1393 + header_field_mark = data;
  1394 + if (parser->state == s_header_value)
  1395 + header_value_mark = data;
  1396 + switch (parser->state) {
  1397 + case s_req_path:
  1398 + case s_req_schema:
  1399 + case s_req_schema_slash:
  1400 + case s_req_schema_slash_slash:
  1401 + case s_req_server_start:
  1402 + case s_req_server:
  1403 + case s_req_server_with_at:
  1404 + case s_req_query_string_start:
  1405 + case s_req_query_string:
  1406 + case s_req_fragment_start:
  1407 + case s_req_fragment:
  1408 + url_mark = data;
  1409 + break;
  1410 + }
  1411 +
  1412 + for (p=data; p != data + len; p++) {
  1413 + ch = *p;
  1414 +
  1415 + if (PARSING_HEADER(parser->state)) {
  1416 + ++parser->nread;
  1417 + /* Buffer overflow attack */
  1418 + if (parser->nread > HTTP_MAX_HEADER_SIZE) {
  1419 + SET_ERRNO(HPE_HEADER_OVERFLOW);
  1420 + goto error;
  1421 + }
  1422 + }
  1423 +
  1424 + reexecute_byte:
  1425 + switch (parser->state) {
  1426 +
  1427 + case s_dead:
  1428 + /* this state is used after a 'Connection: close' message
  1429 + * the parser will error out if it reads another message
  1430 + */
  1431 + if (ch == CR || ch == LF)
  1432 + break;
  1433 +
  1434 + SET_ERRNO(HPE_CLOSED_CONNECTION);
  1435 + goto error;
  1436 +
  1437 + case s_start_req_or_res:
  1438 + {
  1439 + if (ch == CR || ch == LF)
  1440 + break;
  1441 + parser->flags = 0;
  1442 + parser->content_length = ULLONG_MAX;
  1443 +
  1444 + if (ch == 'H') {
  1445 + parser->state = s_res_or_resp_H;
  1446 +
  1447 + CALLBACK_NOTIFY(message_begin);
  1448 + } else {
  1449 + parser->type = HTTP_REQUEST;
  1450 + parser->state = s_start_req;
  1451 + goto reexecute_byte;
  1452 + }
  1453 +
  1454 + break;
  1455 + }
  1456 +
  1457 + case s_res_or_resp_H:
  1458 + if (ch == 'T') {
  1459 + parser->type = HTTP_RESPONSE;
  1460 + parser->state = s_res_HT;
  1461 + } else {
  1462 + if (ch != 'E') {
  1463 + SET_ERRNO(HPE_INVALID_CONSTANT);
  1464 + goto error;
  1465 + }
  1466 +
  1467 + parser->type = HTTP_REQUEST;
  1468 + parser->method = HTTP_HEAD;
  1469 + parser->index = 2;
  1470 + parser->state = s_req_method;
  1471 + }
  1472 + break;
  1473 +
  1474 + case s_start_res:
  1475 + {
  1476 + parser->flags = 0;
  1477 + parser->content_length = ULLONG_MAX;
  1478 +
  1479 + switch (ch) {
  1480 + case 'H':
  1481 + parser->state = s_res_H;
  1482 + break;
  1483 +
  1484 + case CR:
  1485 + case LF:
  1486 + break;
  1487 +
  1488 + default:
  1489 + SET_ERRNO(HPE_INVALID_CONSTANT);
  1490 + goto error;
  1491 + }
  1492 +
  1493 + CALLBACK_NOTIFY(message_begin);
  1494 + break;
  1495 + }
  1496 +
  1497 + case s_res_H:
  1498 + STRICT_CHECK(ch != 'T');
  1499 + parser->state = s_res_HT;
  1500 + break;
  1501 +
  1502 + case s_res_HT:
  1503 + STRICT_CHECK(ch != 'T');
  1504 + parser->state = s_res_HTT;
  1505 + break;
  1506 +
  1507 + case s_res_HTT:
  1508 + STRICT_CHECK(ch != 'P');
  1509 + parser->state = s_res_HTTP;
  1510 + break;
  1511 +
  1512 + case s_res_HTTP:
  1513 + STRICT_CHECK(ch != '/');
  1514 + parser->state = s_res_first_http_major;
  1515 + break;
  1516 +
  1517 + case s_res_first_http_major:
  1518 + if (ch < '0' || ch > '9') {
  1519 + SET_ERRNO(HPE_INVALID_VERSION);
  1520 + goto error;
  1521 + }
  1522 +
  1523 + parser->http_major = ch - '0';
  1524 + parser->state = s_res_http_major;
  1525 + break;
  1526 +
  1527 + /* major HTTP version or dot */
  1528 + case s_res_http_major:
  1529 + {
  1530 + if (ch == '.') {
  1531 + parser->state = s_res_first_http_minor;
  1532 + break;
  1533 + }
  1534 +
  1535 + if (!IS_NUM(ch)) {
  1536 + SET_ERRNO(HPE_INVALID_VERSION);
  1537 + goto error;
  1538 + }
  1539 +
  1540 + parser->http_major *= 10;
  1541 + parser->http_major += ch - '0';
  1542 +
  1543 + if (parser->http_major > 999) {
  1544 + SET_ERRNO(HPE_INVALID_VERSION);
  1545 + goto error;
  1546 + }
  1547 +
  1548 + break;
  1549 + }
  1550 +
  1551 + /* first digit of minor HTTP version */
  1552 + case s_res_first_http_minor:
  1553 + if (!IS_NUM(ch)) {
  1554 + SET_ERRNO(HPE_INVALID_VERSION);
  1555 + goto error;
  1556 + }
  1557 +
  1558 + parser->http_minor = ch - '0';
  1559 + parser->state = s_res_http_minor;
  1560 + break;
  1561 +
  1562 + /* minor HTTP version or end of request line */
  1563 + case s_res_http_minor:
  1564 + {
  1565 + if (ch == ' ') {
  1566 + parser->state = s_res_first_status_code;
  1567 + break;
  1568 + }
  1569 +
  1570 + if (!IS_NUM(ch)) {
  1571 + SET_ERRNO(HPE_INVALID_VERSION);
  1572 + goto error;
  1573 + }
  1574 +
  1575 + parser->http_minor *= 10;
  1576 + parser->http_minor += ch - '0';
  1577 +
  1578 + if (parser->http_minor > 999) {
  1579 + SET_ERRNO(HPE_INVALID_VERSION);
  1580 + goto error;
  1581 + }
  1582 +
  1583 + break;
  1584 + }
  1585 +
  1586 + case s_res_first_status_code:
  1587 + {
  1588 + if (!IS_NUM(ch)) {
  1589 + if (ch == ' ') {
  1590 + break;
  1591 + }
  1592 +
  1593 + SET_ERRNO(HPE_INVALID_STATUS);
  1594 + goto error;
  1595 + }
  1596 + parser->status_code = ch - '0';
  1597 + parser->state = s_res_status_code;
  1598 + break;
  1599 + }
  1600 +
  1601 + case s_res_status_code:
  1602 + {
  1603 + if (!IS_NUM(ch)) {
  1604 + switch (ch) {
  1605 + case ' ':
  1606 + parser->state = s_res_status;
  1607 + break;
  1608 + case CR:
  1609 + parser->state = s_res_line_almost_done;
  1610 + break;
  1611 + case LF:
  1612 + parser->state = s_header_field_start;
  1613 + break;
  1614 + default:
  1615 + SET_ERRNO(HPE_INVALID_STATUS);
  1616 + goto error;
  1617 + }
  1618 + break;
  1619 + }
  1620 +
  1621 + parser->status_code *= 10;
  1622 + parser->status_code += ch - '0';
  1623 +
  1624 + if (parser->status_code > 999) {
  1625 + SET_ERRNO(HPE_INVALID_STATUS);
  1626 + goto error;
  1627 + }
  1628 +
  1629 + break;
  1630 + }
  1631 +
  1632 + case s_res_status:
  1633 + /* the human readable status. e.g. "NOT FOUND"
  1634 + * we are not humans so just ignore this */
  1635 + if (ch == CR) {
  1636 + parser->state = s_res_line_almost_done;
  1637 + break;
  1638 + }
  1639 +
  1640 + if (ch == LF) {
  1641 + parser->state = s_header_field_start;
  1642 + break;
  1643 + }
  1644 + break;
  1645 +
  1646 + case s_res_line_almost_done:
  1647 + STRICT_CHECK(ch != LF);
  1648 + parser->state = s_header_field_start;
  1649 + CALLBACK_NOTIFY(status_complete);
  1650 + break;
  1651 +
  1652 + case s_start_req:
  1653 + {
  1654 + if (ch == CR || ch == LF)
  1655 + break;
  1656 + parser->flags = 0;
  1657 + parser->content_length = ULLONG_MAX;
  1658 +
  1659 + if (!IS_ALPHA(ch)) {
  1660 + SET_ERRNO(HPE_INVALID_METHOD);
  1661 + goto error;
  1662 + }
  1663 +
  1664 + parser->method = (enum http_method) 0;
  1665 + parser->index = 1;
  1666 + switch (ch) {
  1667 + case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
  1668 + case 'D': parser->method = HTTP_DELETE; break;
  1669 + case 'G': parser->method = HTTP_GET; break;
  1670 + case 'H': parser->method = HTTP_HEAD; break;
  1671 + case 'L': parser->method = HTTP_LOCK; break;
  1672 + case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
  1673 + case 'N': parser->method = HTTP_NOTIFY; break;
  1674 + case 'O': parser->method = HTTP_OPTIONS; break;
  1675 + case 'P': parser->method = HTTP_POST;
  1676 + /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
  1677 + break;
  1678 + case 'R': parser->method = HTTP_REPORT; break;
  1679 + case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;
  1680 + case 'T': parser->method = HTTP_TRACE; break;
  1681 + case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
  1682 + default:
  1683 + SET_ERRNO(HPE_INVALID_METHOD);
  1684 + goto error;
  1685 + }
  1686 + parser->state = s_req_method;
  1687 +
  1688 + CALLBACK_NOTIFY(message_begin);
  1689 +
  1690 + break;
  1691 + }
  1692 +
  1693 + case s_req_method:
  1694 + {
  1695 + const char *matcher;
  1696 + if (ch == '\0') {
  1697 + SET_ERRNO(HPE_INVALID_METHOD);
  1698 + goto error;
  1699 + }
  1700 +
  1701 + matcher = method_strings[parser->method];
  1702 + if (ch == ' ' && matcher[parser->index] == '\0') {
  1703 + parser->state = s_req_spaces_before_url;
  1704 + } else if (ch == matcher[parser->index]) {
  1705 + ; /* nada */
  1706 + } else if (parser->method == HTTP_CONNECT) {
  1707 + if (parser->index == 1 && ch == 'H') {
  1708 + parser->method = HTTP_CHECKOUT;
  1709 + } else if (parser->index == 2 && ch == 'P') {
  1710 + parser->method = HTTP_COPY;
  1711 + } else {
  1712 + goto error;
  1713 + }
  1714 + } else if (parser->method == HTTP_MKCOL) {
  1715 + if (parser->index == 1 && ch == 'O') {
  1716 + parser->method = HTTP_MOVE;
  1717 + } else if (parser->index == 1 && ch == 'E') {
  1718 + parser->method = HTTP_MERGE;
  1719 + } else if (parser->index == 1 && ch == '-') {
  1720 + parser->method = HTTP_MSEARCH;
  1721 + } else if (parser->index == 2 && ch == 'A') {
  1722 + parser->method = HTTP_MKACTIVITY;
  1723 + } else {
  1724 + goto error;
  1725 + }
  1726 + } else if (parser->method == HTTP_SUBSCRIBE) {
  1727 + if (parser->index == 1 && ch == 'E') {
  1728 + parser->method = HTTP_SEARCH;
  1729 + } else {
  1730 + goto error;
  1731 + }
  1732 + } else if (parser->index == 1 && parser->method == HTTP_POST) {
  1733 + if (ch == 'R') {
  1734 + parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
  1735 + } else if (ch == 'U') {
  1736 + parser->method = HTTP_PUT; /* or HTTP_PURGE */
  1737 + } else if (ch == 'A') {
  1738 + parser->method = HTTP_PATCH;
  1739 + } else {
  1740 + goto error;
  1741 + }
  1742 + } else if (parser->index == 2) {
  1743 + if (parser->method == HTTP_PUT) {
  1744 + if (ch == 'R') parser->method = HTTP_PURGE;
  1745 + } else if (parser->method == HTTP_UNLOCK) {
  1746 + if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE;
  1747 + }
  1748 + } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
  1749 + parser->method = HTTP_PROPPATCH;
  1750 + } else {
  1751 + SET_ERRNO(HPE_INVALID_METHOD);
  1752 + goto error;
  1753 + }
  1754 +
  1755 + ++parser->index;
  1756 + break;
  1757 + }
  1758 +
  1759 + case s_req_spaces_before_url:
  1760 + {
  1761 + if (ch == ' ') break;
  1762 +
  1763 + MARK(url);
  1764 + if (parser->method == HTTP_CONNECT) {
  1765 + parser->state = s_req_server_start;
  1766 + }
  1767 +
  1768 + parser->state = parse_url_char((enum state)parser->state, ch);
  1769 + if (parser->state == s_dead) {
  1770 + SET_ERRNO(HPE_INVALID_URL);
  1771 + goto error;
  1772 + }
  1773 +
  1774 + break;
  1775 + }
  1776 +
  1777 + case s_req_schema:
  1778 + case s_req_schema_slash:
  1779 + case s_req_schema_slash_slash:
  1780 + case s_req_server_start:
  1781 + {
  1782 + switch (ch) {
  1783 + /* No whitespace allowed here */
  1784 + case ' ':
  1785 + case CR:
  1786 + case LF:
  1787 + SET_ERRNO(HPE_INVALID_URL);
  1788 + goto error;
  1789 + default:
  1790 + parser->state = parse_url_char((enum state)parser->state, ch);
  1791 + if (parser->state == s_dead) {
  1792 + SET_ERRNO(HPE_INVALID_URL);
  1793 + goto error;
  1794 + }
  1795 + }
  1796 +
  1797 + break;
  1798 + }
  1799 +
  1800 + case s_req_server:
  1801 + case s_req_server_with_at:
  1802 + case s_req_path:
  1803 + case s_req_query_string_start:
  1804 + case s_req_query_string:
  1805 + case s_req_fragment_start:
  1806 + case s_req_fragment:
  1807 + {
  1808 + switch (ch) {
  1809 + case ' ':
  1810 + parser->state = s_req_http_start;
  1811 + CALLBACK_DATA(url);
  1812 + break;
  1813 + case CR:
  1814 + case LF:
  1815 + parser->http_major = 0;
  1816 + parser->http_minor = 9;
  1817 + parser->state = (ch == CR) ?
  1818 + s_req_line_almost_done :
  1819 + s_header_field_start;
  1820 + CALLBACK_DATA(url);
  1821 + break;
  1822 + default:
  1823 + parser->state = parse_url_char((enum state)parser->state, ch);
  1824 + if (parser->state == s_dead) {
  1825 + SET_ERRNO(HPE_INVALID_URL);
  1826 + goto error;
  1827 + }
  1828 + }
  1829 + break;
  1830 + }
  1831 +
  1832 + case s_req_http_start:
  1833 + switch (ch) {
  1834 + case 'H':
  1835 + parser->state = s_req_http_H;
  1836 + break;
  1837 + case ' ':
  1838 + break;
  1839 + default:
  1840 + SET_ERRNO(HPE_INVALID_CONSTANT);
  1841 + goto error;
  1842 + }
  1843 + break;
  1844 +
  1845 + case s_req_http_H:
  1846 + STRICT_CHECK(ch != 'T');
  1847 + parser->state = s_req_http_HT;
  1848 + break;
  1849 +
  1850 + case s_req_http_HT:
  1851 + STRICT_CHECK(ch != 'T');
  1852 + parser->state = s_req_http_HTT;
  1853 + break;
  1854 +
  1855 + case s_req_http_HTT:
  1856 + STRICT_CHECK(ch != 'P');
  1857 + parser->state = s_req_http_HTTP;
  1858 + break;
  1859 +
  1860 + case s_req_http_HTTP:
  1861 + STRICT_CHECK(ch != '/');
  1862 + parser->state = s_req_first_http_major;
  1863 + break;
  1864 +
  1865 + /* first digit of major HTTP version */
  1866 + case s_req_first_http_major:
  1867 + if (ch < '1' || ch > '9') {
  1868 + SET_ERRNO(HPE_INVALID_VERSION);
  1869 + goto error;
  1870 + }
  1871 +
  1872 + parser->http_major = ch - '0';
  1873 + parser->state = s_req_http_major;
  1874 + break;
  1875 +
  1876 + /* major HTTP version or dot */
  1877 + case s_req_http_major:
  1878 + {
  1879 + if (ch == '.') {
  1880 + parser->state = s_req_first_http_minor;
  1881 + break;
  1882 + }
  1883 +
  1884 + if (!IS_NUM(ch)) {
  1885 + SET_ERRNO(HPE_INVALID_VERSION);
  1886 + goto error;
  1887 + }
  1888 +
  1889 + parser->http_major *= 10;
  1890 + parser->http_major += ch - '0';
  1891 +
  1892 + if (parser->http_major > 999) {
  1893 + SET_ERRNO(HPE_INVALID_VERSION);
  1894 + goto error;
  1895 + }
  1896 +
  1897 + break;
  1898 + }
  1899 +
  1900 + /* first digit of minor HTTP version */
  1901 + case s_req_first_http_minor:
  1902 + if (!IS_NUM(ch)) {
  1903 + SET_ERRNO(HPE_INVALID_VERSION);
  1904 + goto error;
  1905 + }
  1906 +
  1907 + parser->http_minor = ch - '0';
  1908 + parser->state = s_req_http_minor;
  1909 + break;
  1910 +
  1911 + /* minor HTTP version or end of request line */
  1912 + case s_req_http_minor:
  1913 + {
  1914 + if (ch == CR) {
  1915 + parser->state = s_req_line_almost_done;
  1916 + break;
  1917 + }
  1918 +
  1919 + if (ch == LF) {
  1920 + parser->state = s_header_field_start;
  1921 + break;
  1922 + }
  1923 +
  1924 + /* XXX allow spaces after digit? */
  1925 +
  1926 + if (!IS_NUM(ch)) {
  1927 + SET_ERRNO(HPE_INVALID_VERSION);
  1928 + goto error;
  1929 + }
  1930 +
  1931 + parser->http_minor *= 10;
  1932 + parser->http_minor += ch - '0';
  1933 +
  1934 + if (parser->http_minor > 999) {
  1935 + SET_ERRNO(HPE_INVALID_VERSION);
  1936 + goto error;
  1937 + }
  1938 +
  1939 + break;
  1940 + }
  1941 +
  1942 + /* end of request line */
  1943 + case s_req_line_almost_done:
  1944 + {
  1945 + if (ch != LF) {
  1946 + SET_ERRNO(HPE_LF_EXPECTED);
  1947 + goto error;
  1948 + }
  1949 +
  1950 + parser->state = s_header_field_start;
  1951 + break;
  1952 + }
  1953 +
  1954 + case s_header_field_start:
  1955 + {
  1956 + if (ch == CR) {
  1957 + parser->state = s_headers_almost_done;
  1958 + break;
  1959 + }
  1960 +
  1961 + if (ch == LF) {
  1962 + /* they might be just sending \n instead of \r\n so this would be
  1963 + * the second \n to denote the end of headers*/
  1964 + parser->state = s_headers_almost_done;
  1965 + goto reexecute_byte;
  1966 + }
  1967 +
  1968 + c = TOKEN(ch);
  1969 +
  1970 + if (!c) {
  1971 + SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
  1972 + goto error;
  1973 + }
  1974 +
  1975 + MARK(header_field);
  1976 +
  1977 + parser->index = 0;
  1978 + parser->state = s_header_field;
  1979 +
  1980 + switch (c) {
  1981 + case 'c':
  1982 + parser->header_state = h_C;
  1983 + break;
  1984 +
  1985 + case 'p':
  1986 + parser->header_state = h_matching_proxy_connection;
  1987 + break;
  1988 +
  1989 + case 't':
  1990 + parser->header_state = h_matching_transfer_encoding;
  1991 + break;
  1992 +
  1993 + case 'u':
  1994 + parser->header_state = h_matching_upgrade;
  1995 + break;
  1996 +
  1997 + default:
  1998 + parser->header_state = h_general;
  1999 + break;
  2000 + }
  2001 + break;
  2002 + }
  2003 +
  2004 + case s_header_field:
  2005 + {
  2006 + c = TOKEN(ch);
  2007 +
  2008 + if (c) {
  2009 + switch (parser->header_state) {
  2010 + case h_general:
  2011 + break;
  2012 +
  2013 + case h_C:
  2014 + parser->index++;
  2015 + parser->header_state = (c == 'o' ? h_CO : h_general);
  2016 + break;
  2017 +
  2018 + case h_CO:
  2019 + parser->index++;
  2020 + parser->header_state = (c == 'n' ? h_CON : h_general);
  2021 + break;
  2022 +
  2023 + case h_CON:
  2024 + parser->index++;
  2025 + switch (c) {
  2026 + case 'n':
  2027 + parser->header_state = h_matching_connection;
  2028 + break;
  2029 + case 't':
  2030 + parser->header_state = h_matching_content_length;
  2031 + break;
  2032 + default:
  2033 + parser->header_state = h_general;
  2034 + break;
  2035 + }
  2036 + break;
  2037 +
  2038 + /* connection */
  2039 +
  2040 + case h_matching_connection:
  2041 + parser->index++;
  2042 + if (parser->index > sizeof(CONNECTION)-1
  2043 + || c != CONNECTION[parser->index]) {
  2044 + parser->header_state = h_general;
  2045 + } else if (parser->index == sizeof(CONNECTION)-2) {
  2046 + parser->header_state = h_connection;
  2047 + }
  2048 + break;
  2049 +
  2050 + /* proxy-connection */
  2051 +
  2052 + case h_matching_proxy_connection:
  2053 + parser->index++;
  2054 + if (parser->index > sizeof(PROXY_CONNECTION)-1
  2055 + || c != PROXY_CONNECTION[parser->index]) {
  2056 + parser->header_state = h_general;
  2057 + } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
  2058 + parser->header_state = h_connection;
  2059 + }
  2060 + break;
  2061 +
  2062 + /* content-length */
  2063 +
  2064 + case h_matching_content_length:
  2065 + parser->index++;
  2066 + if (parser->index > sizeof(CONTENT_LENGTH)-1
  2067 + || c != CONTENT_LENGTH[parser->index]) {
  2068 + parser->header_state = h_general;
  2069 + } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
  2070 + parser->header_state = h_content_length;
  2071 + }
  2072 + break;
  2073 +
  2074 + /* transfer-encoding */
  2075 +
  2076 + case h_matching_transfer_encoding:
  2077 + parser->index++;
  2078 + if (parser->index > sizeof(TRANSFER_ENCODING)-1
  2079 + || c != TRANSFER_ENCODING[parser->index]) {
  2080 + parser->header_state = h_general;
  2081 + } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
  2082 + parser->header_state = h_transfer_encoding;
  2083 + }
  2084 + break;
  2085 +
  2086 + /* upgrade */
  2087 +
  2088 + case h_matching_upgrade:
  2089 + parser->index++;
  2090 + if (parser->index > sizeof(UPGRADE)-1
  2091 + || c != UPGRADE[parser->index]) {
  2092 + parser->header_state = h_general;
  2093 + } else if (parser->index == sizeof(UPGRADE)-2) {
  2094 + parser->header_state = h_upgrade;
  2095 + }
  2096 + break;
  2097 +
  2098 + case h_connection:
  2099 + case h_content_length:
  2100 + case h_transfer_encoding:
  2101 + case h_upgrade:
  2102 + if (ch != ' ') parser->header_state = h_general;
  2103 + break;
  2104 +
  2105 + default:
  2106 + assert(0 && "Unknown header_state");
  2107 + break;
  2108 + }
  2109 + break;
  2110 + }
  2111 +
  2112 + if (ch == ':') {
  2113 + parser->state = s_header_value_start;
  2114 + CALLBACK_DATA(header_field);
  2115 + break;
  2116 + }
  2117 +
  2118 + if (ch == CR) {
  2119 + parser->state = s_header_almost_done;
  2120 + CALLBACK_DATA(header_field);
  2121 + break;
  2122 + }
  2123 +
  2124 + if (ch == LF) {
  2125 + parser->state = s_header_field_start;
  2126 + CALLBACK_DATA(header_field);
  2127 + break;
  2128 + }
  2129 +
  2130 + SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
  2131 + goto error;
  2132 + }
  2133 +
  2134 + case s_header_value_start:
  2135 + {
  2136 + if (ch == ' ' || ch == '\t') break;
  2137 +
  2138 + MARK(header_value);
  2139 +
  2140 + parser->state = s_header_value;
  2141 + parser->index = 0;
  2142 +
  2143 + if (ch == CR) {
  2144 + parser->header_state = h_general;
  2145 + parser->state = s_header_almost_done;
  2146 + CALLBACK_DATA(header_value);
  2147 + break;
  2148 + }
  2149 +
  2150 + if (ch == LF) {
  2151 + parser->state = s_header_field_start;
  2152 + CALLBACK_DATA(header_value);
  2153 + break;
  2154 + }
  2155 +
  2156 + c = LOWER(ch);
  2157 +
  2158 + switch (parser->header_state) {
  2159 + case h_upgrade:
  2160 + parser->flags |= F_UPGRADE;
  2161 + parser->header_state = h_general;
  2162 + break;
  2163 +
  2164 + case h_transfer_encoding:
  2165 + /* looking for 'Transfer-Encoding: chunked' */
  2166 + if ('c' == c) {
  2167 + parser->header_state = h_matching_transfer_encoding_chunked;
  2168 + } else {
  2169 + parser->header_state = h_general;
  2170 + }
  2171 + break;
  2172 +
  2173 + case h_content_length:
  2174 + if (!IS_NUM(ch)) {
  2175 + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
  2176 + goto error;
  2177 + }
  2178 +
  2179 + parser->content_length = ch - '0';
  2180 + break;
  2181 +
  2182 + case h_connection:
  2183 + /* looking for 'Connection: keep-alive' */
  2184 + if (c == 'k') {
  2185 + parser->header_state = h_matching_connection_keep_alive;
  2186 + /* looking for 'Connection: close' */
  2187 + } else if (c == 'c') {
  2188 + parser->header_state = h_matching_connection_close;
  2189 + } else {
  2190 + parser->header_state = h_general;
  2191 + }
  2192 + break;
  2193 +
  2194 + default:
  2195 + parser->header_state = h_general;
  2196 + break;
  2197 + }
  2198 + break;
  2199 + }
  2200 +
  2201 + case s_header_value:
  2202 + {
  2203 +
  2204 + if (ch == CR) {
  2205 + parser->state = s_header_almost_done;
  2206 + CALLBACK_DATA(header_value);
  2207 + break;
  2208 + }
  2209 +
  2210 + if (ch == LF) {
  2211 + parser->state = s_header_almost_done;
  2212 + CALLBACK_DATA_NOADVANCE(header_value);
  2213 + goto reexecute_byte;
  2214 + }
  2215 +
  2216 + c = LOWER(ch);
  2217 +
  2218 + switch (parser->header_state) {
  2219 + case h_general:
  2220 + break;
  2221 +
  2222 + case h_connection:
  2223 + case h_transfer_encoding:
  2224 + assert(0 && "Shouldn't get here.");
  2225 + break;
  2226 +
  2227 + case h_content_length:
  2228 + {
  2229 + uint64_t t;
  2230 +
  2231 + if (ch == ' ') break;
  2232 +
  2233 + if (!IS_NUM(ch)) {
  2234 + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
  2235 + goto error;
  2236 + }
  2237 +
  2238 + t = parser->content_length;
  2239 + t *= 10;
  2240 + t += ch - '0';
  2241 +
  2242 + /* Overflow? */
  2243 + if (t < parser->content_length || t == ULLONG_MAX) {
  2244 + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
  2245 + goto error;
  2246 + }
  2247 +
  2248 + parser->content_length = t;
  2249 + break;
  2250 + }
  2251 +
  2252 + /* Transfer-Encoding: chunked */
  2253 + case h_matching_transfer_encoding_chunked:
  2254 + parser->index++;
  2255 + if (parser->index > sizeof(CHUNKED)-1
  2256 + || c != CHUNKED[parser->index]) {
  2257 + parser->header_state = h_general;
  2258 + } else if (parser->index == sizeof(CHUNKED)-2) {
  2259 + parser->header_state = h_transfer_encoding_chunked;
  2260 + }
  2261 + break;
  2262 +
  2263 + /* looking for 'Connection: keep-alive' */
  2264 + case h_matching_connection_keep_alive:
  2265 + parser->index++;
  2266 + if (parser->index > sizeof(KEEP_ALIVE)-1
  2267 + || c != KEEP_ALIVE[parser->index]) {
  2268 + parser->header_state = h_general;
  2269 + } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
  2270 + parser->header_state = h_connection_keep_alive;
  2271 + }
  2272 + break;
  2273 +
  2274 + /* looking for 'Connection: close' */
  2275 + case h_matching_connection_close:
  2276 + parser->index++;
  2277 + if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
  2278 + parser->header_state = h_general;
  2279 + } else if (parser->index == sizeof(CLOSE)-2) {
  2280 + parser->header_state = h_connection_close;
  2281 + }
  2282 + break;
  2283 +
  2284 + case h_transfer_encoding_chunked:
  2285 + case h_connection_keep_alive:
  2286 + case h_connection_close:
  2287 + if (ch != ' ') parser->header_state = h_general;
  2288 + break;
  2289 +
  2290 + default:
  2291 + parser->state = s_header_value;
  2292 + parser->header_state = h_general;
  2293 + break;
  2294 + }
  2295 + break;
  2296 + }
  2297 +
  2298 + case s_header_almost_done:
  2299 + {
  2300 + STRICT_CHECK(ch != LF);
  2301 +
  2302 + parser->state = s_header_value_lws;
  2303 +
  2304 + switch (parser->header_state) {
  2305 + case h_connection_keep_alive:
  2306 + parser->flags |= F_CONNECTION_KEEP_ALIVE;
  2307 + break;
  2308 + case h_connection_close:
  2309 + parser->flags |= F_CONNECTION_CLOSE;
  2310 + break;
  2311 + case h_transfer_encoding_chunked:
  2312 + parser->flags |= F_CHUNKED;
  2313 + break;
  2314 + default:
  2315 + break;
  2316 + }
  2317 +
  2318 + break;
  2319 + }
  2320 +
  2321 + case s_header_value_lws:
  2322 + {
  2323 + if (ch == ' ' || ch == '\t')
  2324 + parser->state = s_header_value_start;
  2325 + else
  2326 + {
  2327 + parser->state = s_header_field_start;
  2328 + goto reexecute_byte;
  2329 + }
  2330 + break;
  2331 + }
  2332 +
  2333 + case s_headers_almost_done:
  2334 + {
  2335 + STRICT_CHECK(ch != LF);
  2336 +
  2337 + if (parser->flags & F_TRAILING) {
  2338 + /* End of a chunked request */
  2339 + parser->state = NEW_MESSAGE();
  2340 + CALLBACK_NOTIFY(message_complete);
  2341 + break;
  2342 + }
  2343 +
  2344 + parser->state = s_headers_done;
  2345 +
  2346 + /* Set this here so that on_headers_complete() callbacks can see it */
  2347 + parser->upgrade =
  2348 + (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT);
  2349 +
  2350 + /* Here we call the headers_complete callback. This is somewhat
  2351 + * different than other callbacks because if the user returns 1, we
  2352 + * will interpret that as saying that this message has no body. This
  2353 + * is needed for the annoying case of recieving a response to a HEAD
  2354 + * request.
  2355 + *
  2356 + * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
  2357 + * we have to simulate it by handling a change in errno below.
  2358 + */
  2359 + if (settings->on_headers_complete) {
  2360 + switch (settings->on_headers_complete(parser)) {
  2361 + case 0:
  2362 + break;
  2363 +
  2364 + case 1:
  2365 + parser->flags |= F_SKIPBODY;
  2366 + break;
  2367 +
  2368 + default:
  2369 + SET_ERRNO(HPE_CB_headers_complete);
  2370 + return p - data; /* Error */
  2371 + }
  2372 + }
  2373 +
  2374 + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
  2375 + return p - data;
  2376 + }
  2377 +
  2378 + goto reexecute_byte;
  2379 + }
  2380 +
  2381 + case s_headers_done:
  2382 + {
  2383 + STRICT_CHECK(ch != LF);
  2384 +
  2385 + parser->nread = 0;
  2386 +
  2387 + /* Exit, the rest of the connect is in a different protocol. */
  2388 + if (parser->upgrade) {
  2389 + parser->state = NEW_MESSAGE();
  2390 + CALLBACK_NOTIFY(message_complete);
  2391 + return (p - data) + 1;
  2392 + }
  2393 +
  2394 + if (parser->flags & F_SKIPBODY) {
  2395 + parser->state = NEW_MESSAGE();
  2396 + CALLBACK_NOTIFY(message_complete);
  2397 + } else if (parser->flags & F_CHUNKED) {
  2398 + /* chunked encoding - ignore Content-Length header */
  2399 + parser->state = s_chunk_size_start;
  2400 + } else {
  2401 + if (parser->content_length == 0) {
  2402 + /* Content-Length header given but zero: Content-Length: 0\r\n */
  2403 + parser->state = NEW_MESSAGE();
  2404 + CALLBACK_NOTIFY(message_complete);
  2405 + } else if (parser->content_length != ULLONG_MAX) {
  2406 + /* Content-Length header given and non-zero */
  2407 + parser->state = s_body_identity;
  2408 + } else {
  2409 + if (parser->type == HTTP_REQUEST ||
  2410 + !http_message_needs_eof(parser)) {
  2411 + /* Assume content-length 0 - read the next */
  2412 + parser->state = NEW_MESSAGE();
  2413 + CALLBACK_NOTIFY(message_complete);
  2414 + } else {
  2415 + /* Read body until EOF */
  2416 + parser->state = s_body_identity_eof;
  2417 + }
  2418 + }
  2419 + }
  2420 +
  2421 + break;
  2422 + }
  2423 +
  2424 + case s_body_identity:
  2425 + {
  2426 + uint64_t to_read = MIN(parser->content_length,
  2427 + (uint64_t) ((data + len) - p));
  2428 +
  2429 + assert(parser->content_length != 0
  2430 + && parser->content_length != ULLONG_MAX);
  2431 +
  2432 + /* The difference between advancing content_length and p is because
  2433 + * the latter will automaticaly advance on the next loop iteration.
  2434 + * Further, if content_length ends up at 0, we want to see the last
  2435 + * byte again for our message complete callback.
  2436 + */
  2437 + MARK(body);
  2438 + parser->content_length -= to_read;
  2439 + p += to_read - 1;
  2440 +
  2441 + if (parser->content_length == 0) {
  2442 + parser->state = s_message_done;
  2443 +
  2444 + /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
  2445 + *
  2446 + * The alternative to doing this is to wait for the next byte to
  2447 + * trigger the data callback, just as in every other case. The
  2448 + * problem with this is that this makes it difficult for the test
  2449 + * harness to distinguish between complete-on-EOF and
  2450 + * complete-on-length. It's not clear that this distinction is
  2451 + * important for applications, but let's keep it for now.
  2452 + */
  2453 + CALLBACK_DATA_(body, p - body_mark + 1, p - data);
  2454 + goto reexecute_byte;
  2455 + }
  2456 +
  2457 + break;
  2458 + }
  2459 +
  2460 + /* read until EOF */
  2461 + case s_body_identity_eof:
  2462 + MARK(body);
  2463 + p = data + len - 1;
  2464 +
  2465 + break;
  2466 +
  2467 + case s_message_done:
  2468 + parser->state = NEW_MESSAGE();
  2469 + CALLBACK_NOTIFY(message_complete);
  2470 + break;
  2471 +
  2472 + case s_chunk_size_start:
  2473 + {
  2474 + assert(parser->nread == 1);
  2475 + assert(parser->flags & F_CHUNKED);
  2476 +
  2477 + unhex_val = unhex[(unsigned char)ch];
  2478 + if (unhex_val == -1) {
  2479 + SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
  2480 + goto error;
  2481 + }
  2482 +
  2483 + parser->content_length = unhex_val;
  2484 + parser->state = s_chunk_size;
  2485 + break;
  2486 + }
  2487 +
  2488 + case s_chunk_size:
  2489 + {
  2490 + uint64_t t;
  2491 +
  2492 + assert(parser->flags & F_CHUNKED);
  2493 +
  2494 + if (ch == CR) {
  2495 + parser->state = s_chunk_size_almost_done;
  2496 + break;
  2497 + }
  2498 +
  2499 + unhex_val = unhex[(unsigned char)ch];
  2500 +
  2501 + if (unhex_val == -1) {
  2502 + if (ch == ';' || ch == ' ') {
  2503 + parser->state = s_chunk_parameters;
  2504 + break;
  2505 + }
  2506 +
  2507 + SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
  2508 + goto error;
  2509 + }
  2510 +
  2511 + t = parser->content_length;
  2512 + t *= 16;
  2513 + t += unhex_val;
  2514 +
  2515 + /* Overflow? */
  2516 + if (t < parser->content_length || t == ULLONG_MAX) {
  2517 + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
  2518 + goto error;
  2519 + }
  2520 +
  2521 + parser->content_length = t;
  2522 + break;
  2523 + }
  2524 +
  2525 + case s_chunk_parameters:
  2526 + {
  2527 + assert(parser->flags & F_CHUNKED);
  2528 + /* just ignore this shit. TODO check for overflow */
  2529 + if (ch == CR) {
  2530 + parser->state = s_chunk_size_almost_done;
  2531 + break;
  2532 + }
  2533 + break;
  2534 + }
  2535 +
  2536 + case s_chunk_size_almost_done:
  2537 + {
  2538 + assert(parser->flags & F_CHUNKED);
  2539 + STRICT_CHECK(ch != LF);
  2540 +
  2541 + parser->nread = 0;
  2542 +
  2543 + if (parser->content_length == 0) {
  2544 + parser->flags |= F_TRAILING;
  2545 + parser->state = s_header_field_start;
  2546 + } else {
  2547 + parser->state = s_chunk_data;
  2548 + }
  2549 + break;
  2550 + }
  2551 +
  2552 + case s_chunk_data:
  2553 + {
  2554 + uint64_t to_read = MIN(parser->content_length,
  2555 + (uint64_t) ((data + len) - p));
  2556 +
  2557 + assert(parser->flags & F_CHUNKED);
  2558 + assert(parser->content_length != 0
  2559 + && parser->content_length != ULLONG_MAX);
  2560 +
  2561 + /* See the explanation in s_body_identity for why the content
  2562 + * length and data pointers are managed this way.
  2563 + */
  2564 + MARK(body);
  2565 + parser->content_length -= to_read;
  2566 + p += to_read - 1;
  2567 +
  2568 + if (parser->content_length == 0) {
  2569 + parser->state = s_chunk_data_almost_done;
  2570 + }
  2571 +
  2572 + break;
  2573 + }
  2574 +
  2575 + case s_chunk_data_almost_done:
  2576 + assert(parser->flags & F_CHUNKED);
  2577 + assert(parser->content_length == 0);
  2578 + STRICT_CHECK(ch != CR);
  2579 + parser->state = s_chunk_data_done;
  2580 + CALLBACK_DATA(body);
  2581 + break;
  2582 +
  2583 + case s_chunk_data_done:
  2584 + assert(parser->flags & F_CHUNKED);
  2585 + STRICT_CHECK(ch != LF);
  2586 + parser->nread = 0;
  2587 + parser->state = s_chunk_size_start;
  2588 + break;
  2589 +
  2590 + default:
  2591 + assert(0 && "unhandled state");
  2592 + SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
  2593 + goto error;
  2594 + }
  2595 + }
  2596 +
  2597 + /* Run callbacks for any marks that we have leftover after we ran our of
  2598 + * bytes. There should be at most one of these set, so it's OK to invoke
  2599 + * them in series (unset marks will not result in callbacks).
  2600 + *
  2601 + * We use the NOADVANCE() variety of callbacks here because 'p' has already
  2602 + * overflowed 'data' and this allows us to correct for the off-by-one that
  2603 + * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
  2604 + * value that's in-bounds).
  2605 + */
  2606 +
  2607 + assert(((header_field_mark ? 1 : 0) +
  2608 + (header_value_mark ? 1 : 0) +
  2609 + (url_mark ? 1 : 0) +
  2610 + (body_mark ? 1 : 0)) <= 1);
  2611 +
  2612 + CALLBACK_DATA_NOADVANCE(header_field);
  2613 + CALLBACK_DATA_NOADVANCE(header_value);
  2614 + CALLBACK_DATA_NOADVANCE(url);
  2615 + CALLBACK_DATA_NOADVANCE(body);
  2616 +
  2617 + return len;
  2618 +
  2619 +error:
  2620 + if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
  2621 + SET_ERRNO(HPE_UNKNOWN);
  2622 + }
  2623 +
  2624 + return (p - data);
  2625 +}
  2626 +
  2627 +
  2628 +/* Does the parser need to see an EOF to find the end of the message? */
  2629 +int
  2630 +http_message_needs_eof (const http_parser *parser)
  2631 +{
  2632 + if (parser->type == HTTP_REQUEST) {
  2633 + return 0;
  2634 + }
  2635 +
  2636 + /* See RFC 2616 section 4.4 */
  2637 + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
  2638 + parser->status_code == 204 || /* No Content */
  2639 + parser->status_code == 304 || /* Not Modified */
  2640 + parser->flags & F_SKIPBODY) { /* response to a HEAD request */
  2641 + return 0;
  2642 + }
  2643 +
  2644 + if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
  2645 + return 0;
  2646 + }
  2647 +
  2648 + return 1;
  2649 +}
  2650 +
  2651 +
  2652 +int
  2653 +http_should_keep_alive (const http_parser *parser)
  2654 +{
  2655 + if (parser->http_major > 0 && parser->http_minor > 0) {
  2656 + /* HTTP/1.1 */
  2657 + if (parser->flags & F_CONNECTION_CLOSE) {
  2658 + return 0;
  2659 + }
  2660 + } else {
  2661 + /* HTTP/1.0 or earlier */
  2662 + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
  2663 + return 0;
  2664 + }
  2665 + }
  2666 +
  2667 + return !http_message_needs_eof(parser);
  2668 +}
  2669 +
  2670 +
  2671 +const char *
  2672 +http_method_str (enum http_method m)
  2673 +{
  2674 + return ELEM_AT(method_strings, m, "<unknown>");
  2675 +}
  2676 +
  2677 +
  2678 +void
  2679 +http_parser_init (http_parser *parser, enum http_parser_type t)
  2680 +{
  2681 + void *data = parser->data; /* preserve application data */
  2682 + memset(parser, 0, sizeof(*parser));
  2683 + parser->data = data;
  2684 + parser->type = t;
  2685 + parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
  2686 + parser->http_errno = HPE_OK;
  2687 +}
  2688 +
  2689 +const char *
  2690 +http_errno_name(enum http_errno err) {
  2691 + assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
  2692 + return http_strerror_tab[err].name;
  2693 +}
  2694 +
  2695 +const char *
  2696 +http_errno_description(enum http_errno err) {
  2697 + assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
  2698 + return http_strerror_tab[err].description;
  2699 +}
  2700 +
  2701 +static enum http_host_state
  2702 +http_parse_host_char(enum http_host_state s, const char ch) {
  2703 + switch(s) {
  2704 + case s_http_userinfo:
  2705 + case s_http_userinfo_start:
  2706 + if (ch == '@') {
  2707 + return s_http_host_start;
  2708 + }
  2709 +
  2710 + if (IS_USERINFO_CHAR(ch)) {
  2711 + return s_http_userinfo;
  2712 + }
  2713 + break;
  2714 +
  2715 + case s_http_host_start:
  2716 + if (ch == '[') {
  2717 + return s_http_host_v6_start;
  2718 + }
  2719 +
  2720 + if (IS_HOST_CHAR(ch)) {
  2721 + return s_http_host;
  2722 + }
  2723 +
  2724 + break;
  2725 +
  2726 + case s_http_host:
  2727 + if (IS_HOST_CHAR(ch)) {
  2728 + return s_http_host;
  2729 + }
  2730 +
  2731 + /* FALLTHROUGH */
  2732 + case s_http_host_v6_end:
  2733 + if (ch == ':') {
  2734 + return s_http_host_port_start;
  2735 + }
  2736 +
  2737 + break;
  2738 +
  2739 + case s_http_host_v6:
  2740 + if (ch == ']') {
  2741 + return s_http_host_v6_end;
  2742 + }
  2743 +
  2744 + /* FALLTHROUGH */
  2745 + case s_http_host_v6_start:
  2746 + if (IS_HEX(ch) || ch == ':' || ch == '.') {
  2747 + return s_http_host_v6;
  2748 + }
  2749 +
  2750 + break;
  2751 +
  2752 + case s_http_host_port:
  2753 + case s_http_host_port_start:
  2754 + if (IS_NUM(ch)) {
  2755 + return s_http_host_port;
  2756 + }
  2757 +
  2758 + break;
  2759 +
  2760 + default:
  2761 + break;
  2762 + }
  2763 + return s_http_host_dead;
  2764 +}
  2765 +
  2766 +static int
  2767 +http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
  2768 + enum http_host_state s;
  2769 +
  2770 + const char *p;
  2771 + size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
  2772 +
  2773 + u->field_data[UF_HOST].len = 0;
  2774 +
  2775 + s = found_at ? s_http_userinfo_start : s_http_host_start;
  2776 +
  2777 + for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
  2778 + enum http_host_state new_s = http_parse_host_char(s, *p);
  2779 +
  2780 + if (new_s == s_http_host_dead) {
  2781 + return 1;
  2782 + }
  2783 +
  2784 + switch(new_s) {
  2785 + case s_http_host:
  2786 + if (s != s_http_host) {
  2787 + u->field_data[UF_HOST].off = p - buf;
  2788 + }
  2789 + u->field_data[UF_HOST].len++;
  2790 + break;
  2791 +
  2792 + case s_http_host_v6:
  2793 + if (s != s_http_host_v6) {
  2794 + u->field_data[UF_HOST].off = p - buf;
  2795 + }
  2796 + u->field_data[UF_HOST].len++;
  2797 + break;
  2798 +
  2799 + case s_http_host_port:
  2800 + if (s != s_http_host_port) {
  2801 + u->field_data[UF_PORT].off = p - buf;
  2802 + u->field_data[UF_PORT].len = 0;
  2803 + u->field_set |= (1 << UF_PORT);
  2804 + }
  2805 + u->field_data[UF_PORT].len++;
  2806 + break;
  2807 +
  2808 + case s_http_userinfo:
  2809 + if (s != s_http_userinfo) {
  2810 + u->field_data[UF_USERINFO].off = p - buf ;
  2811 + u->field_data[UF_USERINFO].len = 0;
  2812 + u->field_set |= (1 << UF_USERINFO);
  2813 + }
  2814 + u->field_data[UF_USERINFO].len++;
  2815 + break;
  2816 +
  2817 + default:
  2818 + break;
  2819 + }
  2820 + s = new_s;
  2821 + }
  2822 +
  2823 + /* Make sure we don't end somewhere unexpected */
  2824 + switch (s) {
  2825 + case s_http_host_start:
  2826 + case s_http_host_v6_start:
  2827 + case s_http_host_v6:
  2828 + case s_http_host_port_start:
  2829 + case s_http_userinfo:
  2830 + case s_http_userinfo_start:
  2831 + return 1;
  2832 + default:
  2833 + break;
  2834 + }
  2835 +
  2836 + return 0;
  2837 +}
  2838 +
  2839 +int
  2840 +http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
  2841 + struct http_parser_url *u)
  2842 +{
  2843 + enum state s;
  2844 + const char *p;
  2845 + enum http_parser_url_fields uf, old_uf;
  2846 + int found_at = 0;
  2847 +
  2848 + u->port = u->field_set = 0;
  2849 + s = is_connect ? s_req_server_start : s_req_spaces_before_url;
  2850 + uf = old_uf = UF_MAX;
  2851 +
  2852 + for (p = buf; p < buf + buflen; p++) {
  2853 + s = parse_url_char(s, *p);
  2854 +
  2855 + /* Figure out the next field that we're operating on */
  2856 + switch (s) {
  2857 + case s_dead:
  2858 + return 1;
  2859 +
  2860 + /* Skip delimeters */
  2861 + case s_req_schema_slash:
  2862 + case s_req_schema_slash_slash:
  2863 + case s_req_server_start:
  2864 + case s_req_query_string_start:
  2865 + case s_req_fragment_start:
  2866 + continue;
  2867 +
  2868 + case s_req_schema:
  2869 + uf = UF_SCHEMA;
  2870 + break;
  2871 +
  2872 + case s_req_server_with_at:
  2873 + found_at = 1;
  2874 +
  2875 + /* FALLTROUGH */
  2876 + case s_req_server:
  2877 + uf = UF_HOST;
  2878 + break;
  2879 +
  2880 + case s_req_path:
  2881 + uf = UF_PATH;
  2882 + break;
  2883 +
  2884 + case s_req_query_string:
  2885 + uf = UF_QUERY;
  2886 + break;
  2887 +
  2888 + case s_req_fragment:
  2889 + uf = UF_FRAGMENT;
  2890 + break;
  2891 +
  2892 + default:
  2893 + assert(!"Unexpected state");
  2894 + return 1;
  2895 + }
  2896 +
  2897 + /* Nothing's changed; soldier on */
  2898 + if (uf == old_uf) {
  2899 + u->field_data[uf].len++;
  2900 + continue;
  2901 + }
  2902 +
  2903 + u->field_data[uf].off = p - buf;
  2904 + u->field_data[uf].len = 1;
  2905 +
  2906 + u->field_set |= (1 << uf);
  2907 + old_uf = uf;
  2908 + }
  2909 +
  2910 + /* host must be present if there is a schema */
  2911 + /* parsing http:///toto will fail */
  2912 + if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) {
  2913 + if (http_parse_host(buf, u, found_at) != 0) {
  2914 + return 1;
  2915 + }
  2916 + }
  2917 +
  2918 + /* CONNECT requests can only contain "hostname:port" */
  2919 + if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
  2920 + return 1;
  2921 + }
  2922 +
  2923 + if (u->field_set & (1 << UF_PORT)) {
  2924 + /* Don't bother with endp; we've already validated the string */
  2925 + unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
  2926 +
  2927 + /* Ports have a max value of 2^16 */
  2928 + if (v > 0xffff) {
  2929 + return 1;
  2930 + }
  2931 +
  2932 + u->port = (uint16_t) v;
  2933 + }
  2934 +
  2935 + return 0;
  2936 +}
  2937 +
  2938 +void
  2939 +http_parser_pause(http_parser *parser, int paused) {
  2940 + /* Users should only be pausing/unpausing a parser that is not in an error
  2941 + * state. In non-debug builds, there's not much that we can do about this
  2942 + * other than ignore it.
  2943 + */
  2944 + if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
  2945 + HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
  2946 + SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
  2947 + } else {
  2948 + assert(0 && "Attempting to pause parser in error state");
  2949 + }
  2950 +}
  2951 +
  2952 +int
  2953 +http_body_is_final(const struct http_parser *parser) {
  2954 + return parser->state == s_message_done;
  2955 +}
  2956 +
  2957 +/*
  2958 + The MIT License (MIT)
  2959 +
  2960 + Copyright (c) 2013-2015 SRS(ossrs)
  2961 +
  2962 + Permission is hereby granted, free of charge, to any person obtaining a copy of
  2963 + this software and associated documentation files (the "Software"), to deal in
  2964 + the Software without restriction, including without limitation the rights to
  2965 + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  2966 + the Software, and to permit persons to whom the Software is furnished to do so,
  2967 + subject to the following conditions:
  2968 +
  2969 + The above copyright notice and this permission notice shall be included in all
  2970 + copies or substantial portions of the Software.
  2971 +
  2972 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2973 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  2974 + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  2975 + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  2976 + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  2977 + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  2978 + */
  2979 +SrsHttpUri::SrsHttpUri()
  2980 +{
  2981 + port = SRS_DEFAULT_HTTP_PORT;
  2982 +}
  2983 +
  2984 +SrsHttpUri::~SrsHttpUri()
  2985 +{
  2986 +}
  2987 +
  2988 +int SrsHttpUri::initialize(string _url)
  2989 +{
  2990 + int ret = ERROR_SUCCESS;
  2991 +
  2992 + url = _url;
  2993 + const char* purl = url.c_str();
  2994 +
  2995 + http_parser_url hp_u;
  2996 + if((ret = http_parser_parse_url(purl, url.length(), 0, &hp_u)) != 0){
  2997 + int code = ret;
  2998 + ret = ERROR_HTTP_PARSE_URI;
  2999 +
  3000 + srs_error("parse url %s failed, code=%d, ret=%d", purl, code, ret);
  3001 + return ret;
  3002 + }
  3003 +
  3004 + std::string field = get_uri_field(url, &hp_u, UF_SCHEMA);
  3005 + if(!field.empty()){
  3006 + schema = field;
  3007 + }
  3008 +
  3009 + host = get_uri_field(url, &hp_u, UF_HOST);
  3010 +
  3011 + field = get_uri_field(url, &hp_u, UF_PORT);
  3012 + if(!field.empty()){
  3013 + port = atoi(field.c_str());
  3014 + }
  3015 +
  3016 + path = get_uri_field(url, &hp_u, UF_PATH);
  3017 + srs_info("parse url %s success", purl);
  3018 +
  3019 + query = get_uri_field(url, &hp_u, UF_QUERY);
  3020 + srs_info("parse query %s success", query.c_str());
  3021 +
  3022 + return ret;
  3023 +}
  3024 +
  3025 +string SrsHttpUri::get_url()
  3026 +{
  3027 + return url;
  3028 +}
  3029 +
  3030 +string SrsHttpUri::get_schema()
  3031 +{
  3032 + return schema;
  3033 +}
  3034 +
  3035 +string SrsHttpUri::get_host()
  3036 +{
  3037 + return host;
  3038 +}
  3039 +
  3040 +int SrsHttpUri::get_port()
  3041 +{
  3042 + return port;
  3043 +}
  3044 +
  3045 +string SrsHttpUri::get_path()
  3046 +{
  3047 + return path;
  3048 +}
  3049 +
  3050 +string SrsHttpUri::get_query()
  3051 +{
  3052 + return query;
  3053 +}
  3054 +
  3055 +string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field)
  3056 +{
  3057 + if((hp_u->field_set & (1 << field)) == 0){
  3058 + return "";
  3059 + }
  3060 +
  3061 + srs_verbose("uri field matched, off=%d, len=%d, value=%.*s",
  3062 + hp_u->field_data[field].off,
  3063 + hp_u->field_data[field].len,
  3064 + hp_u->field_data[field].len,
  3065 + uri.c_str() + hp_u->field_data[field].off);
  3066 +
  3067 + int offset = hp_u->field_data[field].off;
  3068 + int len = hp_u->field_data[field].len;
  3069 +
  3070 + return uri.substr(offset, len);
  3071 +}
  3072 +
  3073 +
@@ -539,5 +539,345 @@ public: @@ -539,5 +539,345 @@ public:
539 539
540 #endif 540 #endif
541 541
  542 +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
  543 + *
  544 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  545 + * of this software and associated documentation files (the "Software"), to
  546 + * deal in the Software without restriction, including without limitation the
  547 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  548 + * sell copies of the Software, and to permit persons to whom the Software is
  549 + * furnished to do so, subject to the following conditions:
  550 + *
  551 + * The above copyright notice and this permission notice shall be included in
  552 + * all copies or substantial portions of the Software.
  553 + *
  554 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  555 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  556 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  557 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  558 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  559 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  560 + * IN THE SOFTWARE.
  561 + */
  562 +#ifndef http_parser_h
  563 +#define http_parser_h
  564 +#ifdef __cplusplus
  565 +extern "C" {
  566 +#endif
  567 +
  568 +#define HTTP_PARSER_VERSION_MAJOR 2
  569 +#define HTTP_PARSER_VERSION_MINOR 1
  570 +
  571 +#include <sys/types.h>
  572 +#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
  573 +#include <BaseTsd.h>
  574 +#include <stddef.h>
  575 + typedef __int8 int8_t;
  576 + typedef unsigned __int8 uint8_t;
  577 + typedef __int16 int16_t;
  578 + typedef unsigned __int16 uint16_t;
  579 + typedef __int32 int32_t;
  580 + typedef unsigned __int32 uint32_t;
  581 + typedef __int64 int64_t;
  582 + typedef unsigned __int64 uint64_t;
  583 +#else
  584 +#include <stdint.h>
  585 +#endif
  586 +
  587 + /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
  588 + * faster
  589 + */
  590 +#ifndef HTTP_PARSER_STRICT
  591 +# define HTTP_PARSER_STRICT 1
  592 +#endif
  593 +
  594 + /* Maximium header size allowed */
  595 +#define HTTP_MAX_HEADER_SIZE (80*1024)
  596 +
  597 +
  598 + typedef struct http_parser http_parser;
  599 + typedef struct http_parser_settings http_parser_settings;
  600 +
  601 +
  602 + /* Callbacks should return non-zero to indicate an error. The parser will
  603 + * then halt execution.
  604 + *
  605 + * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
  606 + * returning '1' from on_headers_complete will tell the parser that it
  607 + * should not expect a body. This is used when receiving a response to a
  608 + * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
  609 + * chunked' headers that indicate the presence of a body.
  610 + *
  611 + * http_data_cb does not return data chunks. It will be call arbitrarally
  612 + * many times for each string. E.G. you might get 10 callbacks for "on_url"
  613 + * each providing just a few characters more data.
  614 + */
  615 + typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
  616 + typedef int (*http_cb) (http_parser*);
  617 +
  618 +
  619 + /* Request Methods */
  620 +#define HTTP_METHOD_MAP(XX) \
  621 +XX(0, DELETE, DELETE) \
  622 +XX(1, GET, GET) \
  623 +XX(2, HEAD, HEAD) \
  624 +XX(3, POST, POST) \
  625 +XX(4, PUT, PUT) \
  626 +/* pathological */ \
  627 +XX(5, CONNECT, CONNECT) \
  628 +XX(6, OPTIONS, OPTIONS) \
  629 +XX(7, TRACE, TRACE) \
  630 +/* webdav */ \
  631 +XX(8, COPY, COPY) \
  632 +XX(9, LOCK, LOCK) \
  633 +XX(10, MKCOL, MKCOL) \
  634 +XX(11, MOVE, MOVE) \
  635 +XX(12, PROPFIND, PROPFIND) \
  636 +XX(13, PROPPATCH, PROPPATCH) \
  637 +XX(14, SEARCH, SEARCH) \
  638 +XX(15, UNLOCK, UNLOCK) \
  639 +/* subversion */ \
  640 +XX(16, REPORT, REPORT) \
  641 +XX(17, MKACTIVITY, MKACTIVITY) \
  642 +XX(18, CHECKOUT, CHECKOUT) \
  643 +XX(19, MERGE, MERGE) \
  644 +/* upnp */ \
  645 +XX(20, MSEARCH, M-SEARCH) \
  646 +XX(21, NOTIFY, NOTIFY) \
  647 +XX(22, SUBSCRIBE, SUBSCRIBE) \
  648 +XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
  649 +/* RFC-5789 */ \
  650 +XX(24, PATCH, PATCH) \
  651 +XX(25, PURGE, PURGE) \
  652 +
  653 + enum http_method
  654 + {
  655 +#define XX(num, name, string) HTTP_##name = num,
  656 + HTTP_METHOD_MAP(XX)
  657 +#undef XX
  658 + };
  659 +
  660 +
  661 + enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
  662 +
  663 +
  664 + /* Flag values for http_parser.flags field */
  665 + enum flags
  666 + { F_CHUNKED = 1 << 0
  667 + , F_CONNECTION_KEEP_ALIVE = 1 << 1
  668 + , F_CONNECTION_CLOSE = 1 << 2
  669 + , F_TRAILING = 1 << 3
  670 + , F_UPGRADE = 1 << 4
  671 + , F_SKIPBODY = 1 << 5
  672 + };
  673 +
  674 +
  675 + /* Map for errno-related constants
  676 + *
  677 + * The provided argument should be a macro that takes 2 arguments.
  678 + */
  679 +#define HTTP_ERRNO_MAP(XX) \
  680 +/* No error */ \
  681 +XX(OK, "success") \
  682 +\
  683 +/* Callback-related errors */ \
  684 +XX(CB_message_begin, "the on_message_begin callback failed") \
  685 +XX(CB_status_complete, "the on_status_complete callback failed") \
  686 +XX(CB_url, "the on_url callback failed") \
  687 +XX(CB_header_field, "the on_header_field callback failed") \
  688 +XX(CB_header_value, "the on_header_value callback failed") \
  689 +XX(CB_headers_complete, "the on_headers_complete callback failed") \
  690 +XX(CB_body, "the on_body callback failed") \
  691 +XX(CB_message_complete, "the on_message_complete callback failed") \
  692 +\
  693 +/* Parsing-related errors */ \
  694 +XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
  695 +XX(HEADER_OVERFLOW, \
  696 +"too many header bytes seen; overflow detected") \
  697 +XX(CLOSED_CONNECTION, \
  698 +"data received after completed connection: close message") \
  699 +XX(INVALID_VERSION, "invalid HTTP version") \
  700 +XX(INVALID_STATUS, "invalid HTTP status code") \
  701 +XX(INVALID_METHOD, "invalid HTTP method") \
  702 +XX(INVALID_URL, "invalid URL") \
  703 +XX(INVALID_HOST, "invalid host") \
  704 +XX(INVALID_PORT, "invalid port") \
  705 +XX(INVALID_PATH, "invalid path") \
  706 +XX(INVALID_QUERY_STRING, "invalid query string") \
  707 +XX(INVALID_FRAGMENT, "invalid fragment") \
  708 +XX(LF_EXPECTED, "LF character expected") \
  709 +XX(INVALID_HEADER_TOKEN, "invalid character in header") \
  710 +XX(INVALID_CONTENT_LENGTH, \
  711 +"invalid character in content-length header") \
  712 +XX(INVALID_CHUNK_SIZE, \
  713 +"invalid character in chunk size header") \
  714 +XX(INVALID_CONSTANT, "invalid constant string") \
  715 +XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
  716 +XX(STRICT, "strict mode assertion failed") \
  717 +XX(PAUSED, "parser is paused") \
  718 +XX(UNKNOWN, "an unknown error occurred")
  719 +
  720 +
  721 + /* Define HPE_* values for each errno value above */
  722 +#define HTTP_ERRNO_GEN(n, s) HPE_##n,
  723 + enum http_errno {
  724 + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
  725 + };
  726 +#undef HTTP_ERRNO_GEN
  727 +
  728 +
  729 + /* Get an http_errno value from an http_parser */
  730 +#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
  731 +
  732 +
  733 + struct http_parser {
  734 + /** PRIVATE **/
  735 + unsigned char type : 2; /* enum http_parser_type */
  736 + unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
  737 + unsigned char state; /* enum state from http_parser.c */
  738 + unsigned char header_state; /* enum header_state from http_parser.c */
  739 + unsigned char index; /* index into current matcher */
  740 +
  741 + uint32_t nread; /* # bytes read in various scenarios */
  742 + uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
  743 +
  744 + /** READ-ONLY **/
  745 + unsigned short http_major;
  746 + unsigned short http_minor;
  747 + unsigned short status_code; /* responses only */
  748 + unsigned char method; /* requests only */
  749 + unsigned char http_errno : 7;
  750 +
  751 + /* 1 = Upgrade header was present and the parser has exited because of that.
  752 + * 0 = No upgrade header present.
  753 + * Should be checked when http_parser_execute() returns in addition to
  754 + * error checking.
  755 + */
  756 + unsigned char upgrade : 1;
  757 +
  758 + /** PUBLIC **/
  759 + void *data; /* A pointer to get hook to the "connection" or "socket" object */
  760 + };
  761 +
  762 +
  763 + struct http_parser_settings {
  764 + http_cb on_message_begin;
  765 + http_data_cb on_url;
  766 + http_cb on_status_complete;
  767 + http_data_cb on_header_field;
  768 + http_data_cb on_header_value;
  769 + http_cb on_headers_complete;
  770 + http_data_cb on_body;
  771 + http_cb on_message_complete;
  772 + };
  773 +
  774 +
  775 + enum http_parser_url_fields
  776 + { UF_SCHEMA = 0
  777 + , UF_HOST = 1
  778 + , UF_PORT = 2
  779 + , UF_PATH = 3
  780 + , UF_QUERY = 4
  781 + , UF_FRAGMENT = 5
  782 + , UF_USERINFO = 6
  783 + , UF_MAX = 7
  784 + };
  785 +
  786 +
  787 + /* Result structure for http_parser_parse_url().
  788 + *
  789 + * Callers should index into field_data[] with UF_* values iff field_set
  790 + * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
  791 + * because we probably have padding left over), we convert any port to
  792 + * a uint16_t.
  793 + */
  794 + struct http_parser_url {
  795 + uint16_t field_set; /* Bitmask of (1 << UF_*) values */
  796 + uint16_t port; /* Converted UF_PORT string */
  797 +
  798 + struct {
  799 + uint16_t off; /* Offset into buffer in which field starts */
  800 + uint16_t len; /* Length of run in buffer */
  801 + } field_data[UF_MAX];
  802 + };
  803 +
  804 +
  805 + void http_parser_init(http_parser *parser, enum http_parser_type type);
  806 +
  807 +
  808 + size_t http_parser_execute(http_parser *parser,
  809 + const http_parser_settings *settings,
  810 + const char *data,
  811 + size_t len);
  812 +
  813 +
  814 + /* If http_should_keep_alive() in the on_headers_complete or
  815 + * on_message_complete callback returns 0, then this should be
  816 + * the last message on the connection.
  817 + * If you are the server, respond with the "Connection: close" header.
  818 + * If you are the client, close the connection.
  819 + */
  820 + int http_should_keep_alive(const http_parser *parser);
  821 +
  822 + /* Returns a string version of the HTTP method. */
  823 + const char *http_method_str(enum http_method m);
  824 +
  825 + /* Return a string name of the given error */
  826 + const char *http_errno_name(enum http_errno err);
  827 +
  828 + /* Return a string description of the given error */
  829 + const char *http_errno_description(enum http_errno err);
  830 +
  831 + /* Parse a URL; return nonzero on failure */
  832 + int http_parser_parse_url(const char *buf, size_t buflen,
  833 + int is_connect,
  834 + struct http_parser_url *u);
  835 +
  836 + /* Pause or un-pause the parser; a nonzero value pauses */
  837 + void http_parser_pause(http_parser *parser, int paused);
  838 +
  839 + /* Checks if this is the final chunk of the body. */
  840 + int http_body_is_final(const http_parser *parser);
  841 +
  842 +#ifdef __cplusplus
  843 +}
  844 +#endif
  845 +#endif
  846 +
  847 +/**
  848 + * used to resolve the http uri.
  849 + */
  850 +class SrsHttpUri
  851 +{
  852 +private:
  853 + std::string url;
  854 + std::string schema;
  855 + std::string host;
  856 + int port;
  857 + std::string path;
  858 + std::string query;
  859 +public:
  860 + SrsHttpUri();
  861 + virtual ~SrsHttpUri();
  862 +public:
  863 + /**
  864 + * initialize the http uri.
  865 + */
  866 + virtual int initialize(std::string _url);
  867 +public:
  868 + virtual std::string get_url();
  869 + virtual std::string get_schema();
  870 + virtual std::string get_host();
  871 + virtual int get_port();
  872 + virtual std::string get_path();
  873 + virtual std::string get_query();
  874 +private:
  875 + /**
  876 + * get the parsed url field.
  877 + * @return return empty string if not set.
  878 + */
  879 + virtual std::string get_uri_field(std::string uri, http_parser_url* hp_u, http_parser_url_fields field);
  880 +};
  881 +
542 #endif 882 #endif
543 883