1 /* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org> 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 /* modified by Moriyoshi Koizumi <moriyoshi@php.net> to make it fit to PHP source tree. */ 22 #ifndef php_http_parser_h 23 #define php_http_parser_h 24 #ifdef __cplusplus 25 extern "C" { 26 #endif 27 28 29 #include <sys/types.h> 30 #if defined(_WIN32) && !defined(__MINGW32__) 31 # include <windows.h> 32 # include "config.w32.h" 33 #else 34 # include "php_config.h" 35 #endif 36 37 #include "php_stdint.h" 38 39 /* Compile with -DPHP_HTTP_PARSER_STRICT=0 to make less checks, but run 40 * faster 41 */ 42 #ifndef PHP_HTTP_PARSER_STRICT 43 # define PHP_HTTP_PARSER_STRICT 1 44 #else 45 # define PHP_HTTP_PARSER_STRICT 0 46 #endif 47 48 49 /* Maximium header size allowed */ 50 #define PHP_HTTP_MAX_HEADER_SIZE (80*1024) 51 52 53 typedef struct php_http_parser php_http_parser; 54 typedef struct php_http_parser_settings php_http_parser_settings; 55 56 57 /* Callbacks should return non-zero to indicate an error. The parser will 58 * then halt execution. 59 * 60 * The one exception is on_headers_complete. In a PHP_HTTP_RESPONSE parser 61 * returning '1' from on_headers_complete will tell the parser that it 62 * should not expect a body. This is used when receiving a response to a 63 * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: 64 * chunked' headers that indicate the presence of a body. 65 * 66 * http_data_cb does not return data chunks. It will be call arbitrarally 67 * many times for each string. E.G. you might get 10 callbacks for "on_path" 68 * each providing just a few characters more data. 69 */ 70 typedef int (*php_http_data_cb) (php_http_parser*, const char *at, size_t length); 71 typedef int (*php_http_cb) (php_http_parser*); 72 73 74 /* Request Methods */ 75 enum php_http_method 76 { PHP_HTTP_DELETE = 0 77 , PHP_HTTP_GET 78 , PHP_HTTP_HEAD 79 , PHP_HTTP_POST 80 , PHP_HTTP_PUT 81 , PHP_HTTP_PATCH 82 /* pathological */ 83 , PHP_HTTP_CONNECT 84 , PHP_HTTP_OPTIONS 85 , PHP_HTTP_TRACE 86 /* webdav */ 87 , PHP_HTTP_COPY 88 , PHP_HTTP_LOCK 89 , PHP_HTTP_MKCOL 90 , PHP_HTTP_MOVE 91 , PHP_HTTP_MKCALENDAR 92 , PHP_HTTP_PROPFIND 93 , PHP_HTTP_PROPPATCH 94 , PHP_HTTP_SEARCH 95 , PHP_HTTP_UNLOCK 96 /* subversion */ 97 , PHP_HTTP_REPORT 98 , PHP_HTTP_MKACTIVITY 99 , PHP_HTTP_CHECKOUT 100 , PHP_HTTP_MERGE 101 /* upnp */ 102 , PHP_HTTP_MSEARCH 103 , PHP_HTTP_NOTIFY 104 , PHP_HTTP_SUBSCRIBE 105 , PHP_HTTP_UNSUBSCRIBE 106 /* unknown, not implemented */ 107 , PHP_HTTP_NOT_IMPLEMENTED 108 }; 109 110 111 enum php_http_parser_type { PHP_HTTP_REQUEST, PHP_HTTP_RESPONSE, PHP_HTTP_BOTH }; 112 113 enum state 114 { s_dead = 1 /* important that this is > 0 */ 115 116 , s_start_req_or_res 117 , s_res_or_resp_H 118 , s_start_res 119 , s_res_H 120 , s_res_HT 121 , s_res_HTT 122 , s_res_HTTP 123 , s_res_first_http_major 124 , s_res_http_major 125 , s_res_first_http_minor 126 , s_res_http_minor 127 , s_res_first_status_code 128 , s_res_status_code 129 , s_res_status 130 , s_res_line_almost_done 131 132 , s_start_req 133 134 , s_req_method 135 , s_req_spaces_before_url 136 , s_req_schema 137 , s_req_schema_slash 138 , s_req_schema_slash_slash 139 , s_req_host 140 , s_req_port 141 , s_req_path 142 , s_req_query_string_start 143 , s_req_query_string 144 , s_req_fragment_start 145 , s_req_fragment 146 , s_req_http_start 147 , s_req_http_H 148 , s_req_http_HT 149 , s_req_http_HTT 150 , s_req_http_HTTP 151 , s_req_first_http_major 152 , s_req_http_major 153 , s_req_first_http_minor 154 , s_req_http_minor 155 , s_req_line_almost_done 156 157 , s_header_field_start 158 , s_header_field 159 , s_header_value_start 160 , s_header_value 161 162 , s_header_almost_done 163 164 , s_headers_almost_done 165 /* Important: 's_headers_almost_done' must be the last 'header' state. All 166 * states beyond this must be 'body' states. It is used for overflow 167 * checking. See the PARSING_HEADER() macro. 168 */ 169 , s_chunk_size_start 170 , s_chunk_size 171 , s_chunk_size_almost_done 172 , s_chunk_parameters 173 , s_chunk_data 174 , s_chunk_data_almost_done 175 , s_chunk_data_done 176 177 , s_body_identity 178 , s_body_identity_eof 179 }; 180 181 struct php_http_parser { 182 /** PRIVATE **/ 183 unsigned char type : 2; 184 unsigned char flags : 6; 185 unsigned char state; 186 unsigned char header_state; 187 unsigned char index; 188 189 uint32_t nread; 190 ssize_t content_length; 191 192 /** READ-ONLY **/ 193 unsigned short http_major; 194 unsigned short http_minor; 195 unsigned short status_code; /* responses only */ 196 unsigned char method; /* requests only */ 197 198 /* 1 = Upgrade header was present and the parser has exited because of that. 199 * 0 = No upgrade header present. 200 * Should be checked when http_parser_execute() returns in addition to 201 * error checking. 202 */ 203 char upgrade; 204 205 /** PUBLIC **/ 206 void *data; /* A pointer to get hook to the "connection" or "socket" object */ 207 }; 208 209 210 struct php_http_parser_settings { 211 php_http_cb on_message_begin; 212 php_http_data_cb on_path; 213 php_http_data_cb on_query_string; 214 php_http_data_cb on_url; 215 php_http_data_cb on_fragment; 216 php_http_data_cb on_header_field; 217 php_http_data_cb on_header_value; 218 php_http_cb on_headers_complete; 219 php_http_data_cb on_body; 220 php_http_cb on_message_complete; 221 }; 222 223 224 void php_http_parser_init(php_http_parser *parser, enum php_http_parser_type type); 225 226 227 size_t php_http_parser_execute(php_http_parser *parser, 228 const php_http_parser_settings *settings, 229 const char *data, 230 size_t len); 231 232 233 /* If php_http_should_keep_alive() in the on_headers_complete or 234 * on_message_complete callback returns true, then this will be should be 235 * the last message on the connection. 236 * If you are the server, respond with the "Connection: close" header. 237 * If you are the client, close the connection. 238 */ 239 int php_http_should_keep_alive(php_http_parser *parser); 240 241 /* Returns a string version of the HTTP method. */ 242 const char *php_http_method_str(enum php_http_method); 243 244 #ifdef __cplusplus 245 } 246 #endif 247 #endif 248