Add log level and log callback support to the RAOP API
[deb_shairplay.git] / src / lib / http_parser.h
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
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 #ifndef http_parser_h
22 #define http_parser_h
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 #define HTTP_PARSER_VERSION_MAJOR 1
28 #define HTTP_PARSER_VERSION_MINOR 0
29
30 #include <sys/types.h>
31 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(_MSC_VER)
32 typedef __int8 int8_t;
33 typedef unsigned __int8 uint8_t;
34 typedef __int16 int16_t;
35 typedef unsigned __int16 uint16_t;
36 typedef __int32 int32_t;
37 typedef unsigned __int32 uint32_t;
38 typedef __int64 int64_t;
39 typedef unsigned __int64 uint64_t;
40
41 typedef unsigned int size_t;
42 typedef int ssize_t;
43 #else
44 #include <stdint.h>
45 #endif
46
47 /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
48 * faster
49 */
50 #ifndef HTTP_PARSER_STRICT
51 # define HTTP_PARSER_STRICT 0
52 #endif
53
54 /* Compile with -DHTTP_PARSER_DEBUG=1 to add extra debugging information to
55 * the error reporting facility.
56 */
57 #ifndef HTTP_PARSER_DEBUG
58 # define HTTP_PARSER_DEBUG 0
59 #endif
60
61
62 /* Maximium header size allowed */
63 #define HTTP_MAX_HEADER_SIZE (80*1024)
64
65
66 typedef struct http_parser http_parser;
67 typedef struct http_parser_settings http_parser_settings;
68 typedef struct http_parser_result http_parser_result;
69
70
71 /* Callbacks should return non-zero to indicate an error. The parser will
72 * then halt execution.
73 *
74 * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
75 * returning '1' from on_headers_complete will tell the parser that it
76 * should not expect a body. This is used when receiving a response to a
77 * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
78 * chunked' headers that indicate the presence of a body.
79 *
80 * http_data_cb does not return data chunks. It will be call arbitrarally
81 * many times for each string. E.G. you might get 10 callbacks for "on_path"
82 * each providing just a few characters more data.
83 */
84 typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
85 typedef int (*http_cb) (http_parser*);
86
87
88 /* Request Methods */
89 enum http_method
90 { HTTP_DELETE = 0
91 , HTTP_GET
92 , HTTP_HEAD
93 , HTTP_POST
94 , HTTP_PUT
95 /* pathological */
96 , HTTP_CONNECT
97 , HTTP_OPTIONS
98 , HTTP_TRACE
99 /* webdav */
100 , HTTP_COPY
101 , HTTP_LOCK
102 , HTTP_MKCOL
103 , HTTP_MOVE
104 , HTTP_PROPFIND
105 , HTTP_PROPPATCH
106 , HTTP_UNLOCK
107 /* subversion */
108 , HTTP_REPORT
109 , HTTP_MKACTIVITY
110 , HTTP_CHECKOUT
111 , HTTP_MERGE
112 /* upnp */
113 , HTTP_MSEARCH
114 , HTTP_NOTIFY
115 , HTTP_SUBSCRIBE
116 , HTTP_UNSUBSCRIBE
117 /* RFC-5789 */
118 , HTTP_PATCH
119 /* RTSP RFC 2326 */
120 , HTTP_DESCRIBE
121 , HTTP_ANNOUNCE
122 , HTTP_SETUP
123 , HTTP_PLAY
124 , HTTP_PAUSE
125 , HTTP_TEARDOWN
126 , HTTP_GET_PARAMETER
127 , HTTP_SET_PARAMETER
128 , HTTP_REDIRECT
129 , HTTP_RECORD
130 /* RAOP FLUSH */
131 , HTTP_FLUSH
132 };
133
134
135 enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
136
137
138 /* Flag values for http_parser.flags field */
139 enum flags
140 { F_CHUNKED = 1 << 0
141 , F_CONNECTION_KEEP_ALIVE = 1 << 1
142 , F_CONNECTION_CLOSE = 1 << 2
143 , F_TRAILING = 1 << 3
144 , F_UPGRADE = 1 << 4
145 , F_SKIPBODY = 1 << 5
146 };
147
148
149 /* Map for errno-related constants
150 *
151 * The provided argument should be a macro that takes 2 arguments.
152 */
153 #define HTTP_ERRNO_MAP(XX) \
154 /* No error */ \
155 XX(OK, "success") \
156 \
157 /* Callback-related errors */ \
158 XX(CB_message_begin, "the on_message_begin callback failed") \
159 XX(CB_path, "the on_path callback failed") \
160 XX(CB_query_string, "the on_query_string callback failed") \
161 XX(CB_url, "the on_url callback failed") \
162 XX(CB_fragment, "the on_fragment callback failed") \
163 XX(CB_header_field, "the on_header_field callback failed") \
164 XX(CB_header_value, "the on_header_value callback failed") \
165 XX(CB_headers_complete, "the on_headers_complete callback failed") \
166 XX(CB_body, "the on_body callback failed") \
167 XX(CB_message_complete, "the on_message_complete callback failed") \
168 \
169 /* Parsing-related errors */ \
170 XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
171 XX(HEADER_OVERFLOW, \
172 "too many header bytes seen; overflow detected") \
173 XX(CLOSED_CONNECTION, \
174 "data received after completed connection: close message") \
175 XX(INVALID_VERSION, "invalid HTTP version") \
176 XX(INVALID_STATUS, "invalid HTTP status code") \
177 XX(INVALID_METHOD, "invalid HTTP method") \
178 XX(INVALID_URL, "invalid URL") \
179 XX(INVALID_HOST, "invalid host") \
180 XX(INVALID_PORT, "invalid port") \
181 XX(INVALID_PATH, "invalid path") \
182 XX(INVALID_QUERY_STRING, "invalid query string") \
183 XX(INVALID_FRAGMENT, "invalid fragment") \
184 XX(LF_EXPECTED, "LF character expected") \
185 XX(INVALID_HEADER_TOKEN, "invalid character in header") \
186 XX(INVALID_CONTENT_LENGTH, \
187 "invalid character in content-length header") \
188 XX(INVALID_CHUNK_SIZE, \
189 "invalid character in chunk size header") \
190 XX(INVALID_CONSTANT, "invalid constant string") \
191 XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
192 XX(STRICT, "strict mode assertion failed") \
193 XX(UNKNOWN, "an unknown error occurred")
194
195
196 /* Define HPE_* values for each errno value above */
197 #define HTTP_ERRNO_GEN(n, s) HPE_##n,
198 enum http_errno {
199 HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
200 };
201 #undef HTTP_ERRNO_GEN
202
203
204 /* Get an http_errno value from an http_parser */
205 #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
206
207 /* Get the line number that generated the current error */
208 #if HTTP_PARSER_DEBUG
209 #define HTTP_PARSER_ERRNO_LINE(p) ((p)->error_lineno)
210 #else
211 #define HTTP_PARSER_ERRNO_LINE(p) 0
212 #endif
213
214
215 struct http_parser {
216 /** PRIVATE **/
217 unsigned char numerichost;
218 unsigned char type : 2;
219 unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
220 unsigned char state;
221 unsigned char header_state;
222 unsigned char index;
223
224 uint32_t nread;
225 int64_t content_length;
226
227 /** READ-ONLY **/
228 unsigned short http_major;
229 unsigned short http_minor;
230 unsigned short status_code; /* responses only */
231 unsigned char method; /* requests only */
232 unsigned char http_errno : 7;
233
234 /* 1 = Upgrade header was present and the parser has exited because of that.
235 * 0 = No upgrade header present.
236 * Should be checked when http_parser_execute() returns in addition to
237 * error checking.
238 */
239 unsigned char upgrade : 1;
240
241 #if HTTP_PARSER_DEBUG
242 uint32_t error_lineno;
243 #endif
244
245 /** PUBLIC **/
246 void *data; /* A pointer to get hook to the "connection" or "socket" object */
247 };
248
249
250 struct http_parser_settings {
251 http_cb on_message_begin;
252 http_data_cb on_url;
253 http_data_cb on_header_field;
254 http_data_cb on_header_value;
255 http_cb on_headers_complete;
256 http_data_cb on_body;
257 http_cb on_message_complete;
258 };
259
260
261 void http_parser_init(http_parser *parser, enum http_parser_type type, char numerichost);
262
263
264 size_t http_parser_execute(http_parser *parser,
265 const http_parser_settings *settings,
266 const char *data,
267 size_t len);
268
269
270 /* If http_should_keep_alive() in the on_headers_complete or
271 * on_message_complete callback returns true, then this will be should be
272 * the last message on the connection.
273 * If you are the server, respond with the "Connection: close" header.
274 * If you are the client, close the connection.
275 */
276 int http_should_keep_alive(http_parser *parser);
277
278 /* Returns a string version of the HTTP method. */
279 const char *http_method_str(enum http_method m);
280
281 /* Return a string name of the given error */
282 const char *http_errno_name(enum http_errno err);
283
284 /* Return a string description of the given error */
285 const char *http_errno_description(enum http_errno err);
286
287 #ifdef __cplusplus
288 }
289 #endif
290 #endif