xref: /PHP-7.4/sapi/cli/php_http_parser.h (revision 3bc5c9f1)
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