Menu

[r224]: / trunk / boost / network / protocol / http / parser.hpp  Maximize  Restore  History

Download this file

315 lines (252 with data), 12.1 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
// This file is part of the Boost Network library
// Based on the Pion Network Library (r421)
// Copyright Atomic Labs, Inc. 2007-2008
// See http://cpp-netlib.sourceforge.net for library home page.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_NETWORK_PROTOCOL_HTTP_PARSER_HPP
#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_HPP
#include <boost/network/protocol/http/traits.hpp>
#include <boost/network/traits/string.hpp>
#include <boost/network/message.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/cstdint.hpp>
#include <boost/noncopyable.hpp>
#include <string>
namespace boost { namespace network { namespace http {
// forward declarations used to finish HTTP requests
template <typename Tag>
class basic_request;
// forward declarations used to finish HTTP requests
template <typename Tag>
class basic_response;
/// an incremental HTTP 1.0/1.1 protocol parser
template <typename Tag, typename ParserTraits = parser_traits<Tag> >
class basic_parser :
private boost::noncopyable
{
public:
// import types from ParserTraits template
typedef ParserTraits traits_type;
typedef typename string<Tag>::type string_type;
// default destructor
virtual ~basic_parser() {}
/**
* creates a new HTTP protocol parser
*
* @param is_request if true, the message is parsed as an HTTP request;
* if false, the message is parsed as an HTTP response
*/
basic_parser(const bool is_request) :
m_is_request(is_request), m_read_ptr(NULL), m_read_end_ptr(NULL),
m_headers_parse_state(is_request ? PARSE_METHOD_START : PARSE_HTTP_VERSION_H),
m_chunked_content_parse_state(PARSE_CHUNK_SIZE_START),
m_status_code(0), m_bytes_last_read(0), m_bytes_total_read(0)
{}
/**
* parses an HTTP message up to the end of the headers using bytes
* available in the read buffer
*
* @param http_msg the HTTP message object to populate from parsing
*
* @return boost::tribool result of parsing:
* false = message has an error,
* true = finished parsing HTTP headers,
* indeterminate = not yet finished parsing HTTP headers
*/
boost::tribool parse_http_headers(basic_message<Tag>& http_msg);
/**
* parses a chunked HTTP message-body using bytes available in the read buffer
*
* @param chunk_buffers buffers to be populated from parsing chunked content
*
* @return boost::tribool result of parsing:
* false = message has an error,
* true = finished parsing message,
* indeterminate = message is not yet finished
*/
boost::tribool parse_chunks(types::chunk_cache_t& chunk_buffers);
/**
* prepares the payload content buffer and consumes any content remaining
* in the parser's read buffer
*
* @param http_msg the HTTP message object to consume content for
* @return unsigned long number of content bytes consumed, if any
*/
std::size_t consume_content(basic_message<Tag>& http_msg);
/**
* consume the bytes available in the read buffer, converting them into
* the next chunk for the HTTP message
*
* @param chunk_buffers buffers to be populated from parsing chunked content
* @return unsigned long number of content bytes consumed, if any
*/
std::size_t consume_content_as_next_chunk(types::chunk_cache_t& chunk_buffers);
/**
* finishes parsing an HTTP request message (copies over request-only data)
*
* @param http_request the HTTP request object to finish
*/
void finish(basic_request<Tag>& http_request);
/**
* finishes an HTTP response message (copies over response-only data)
*
* @param http_request the HTTP response object to finish
*/
void finish(basic_response<Tag>& http_response);
/**
* resets the location and size of the read buffer
*
* @param ptr pointer to the first bytes available to be read
* @param len number of bytes available to be read
*/
inline void set_read_buffer(const char *ptr, std::size_t len) {
m_read_ptr = ptr;
m_read_end_ptr = ptr + len;
}
/**
* saves the current read position bookmark
*
* @param read_ptr points to the next character to be consumed in the read_buffer
* @param read_end_ptr points to the end of the read_buffer (last byte + 1)
*/
inline void save_read_position(const char *&read_ptr, const char *&read_end_ptr) const {
read_ptr = m_read_ptr;
read_end_ptr = m_read_end_ptr;
}
/// resets the parser to its initial state
inline void reset(void);
/// returns true if there are no more bytes available in the read buffer
inline bool eof(void) const {
return m_read_ptr == NULL || m_read_ptr >= m_read_end_ptr;
}
/// returns the number of bytes read during the last parse operation
inline std::size_t gcount(void) const { return m_bytes_last_read; }
/// returns the total number of bytes read while parsing the HTTP message
inline std::size_t bytes_read(void) const { return m_bytes_total_read; }
/// returns the number of bytes available in the read buffer
inline std::size_t bytes_available(void) const {
return (eof() ? 0 : (m_read_end_ptr - m_read_ptr));
}
protected:
/**
* parse key-value pairs out of a url-encoded string
* (i.e. this=that&a=value)
*
* @param params container for key-values string pairs
* @param ptr points to the start of the encoded string
* @param len length of the encoded string, in bytes
*
* @return bool true if successful
*/
static bool parse_url_encoded(types::query_params& params,
const char *ptr, const std::size_t len);
/**
* parse key-value pairs out of a "Cookie" request header
* (i.e. this=that; a=value)
*
* @param params container for key-values string pairs
* @param cookie_header header string to be parsed
*
* @return bool true if successful
*/
static bool parse_cookie_header(types::cookie_params& params,
const string_type& cookie_header);
/// true if the message is an HTTP request; false if it is an HTTP response
const bool m_is_request;
/// points to the next character to be consumed in the read_buffer
const char * m_read_ptr;
/// points to the end of the read_buffer (last byte + 1)
const char * m_read_end_ptr;
private:
// returns true if the argument is a special character
inline static bool is_special(int c) {
switch (c) {
case '(': case ')': case '<': case '>': case '@':
case ',': case ';': case ':': case '\\': case '"':
case '/': case '[': case ']': case '?': case '=':
case '{': case '}': case ' ': case '\t':
return true;
default:
return false;
}
}
// returns true if the argument is a character
inline static bool is_char(int c) {
return(c >= 0 && c <= 127);
}
// returns true if the argument is a control character
inline static bool is_control(int c) {
return( (c >= 0 && c <= 31) || c == 127);
}
// returns true if the argument is a digit
inline static bool is_digit(int c) {
return(c >= '0' && c <= '9');
}
// returns true if the argument is a hexadecimal digit
inline static bool is_hex_digit(int c) {
return((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
/// state used to keep track of where we are in parsing the HTTP headers
enum headers_parse_state_t {
PARSE_METHOD_START, PARSE_METHOD, PARSE_URI_STEM, PARSE_URI_QUERY,
PARSE_HTTP_VERSION_H, PARSE_HTTP_VERSION_T_1, PARSE_HTTP_VERSION_T_2,
PARSE_HTTP_VERSION_P, PARSE_HTTP_VERSION_SLASH,
PARSE_HTTP_VERSION_MAJOR_START, PARSE_HTTP_VERSION_MAJOR,
PARSE_HTTP_VERSION_MINOR_START, PARSE_HTTP_VERSION_MINOR,
PARSE_STATUS_CODE_START, PARSE_STATUS_CODE, PARSE_STATUS_MESSAGE,
PARSE_EXPECTING_NEWLINE, PARSE_EXPECTING_CR,
PARSE_HEADER_WHITESPACE, PARSE_HEADER_START, PARSE_HEADER_NAME,
PARSE_SPACE_BEFORE_HEADER_VALUE, PARSE_HEADER_VALUE,
PARSE_EXPECTING_FINAL_NEWLINE, PARSE_EXPECTING_FINAL_CR
};
/// state used to keep track of where we are in parsing chunked content
enum chunked_content_parse_state_t {
PARSE_CHUNK_SIZE_START, PARSE_CHUNK_SIZE,
PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE,
PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE, PARSE_CHUNK,
PARSE_EXPECTING_CR_AFTER_CHUNK, PARSE_EXPECTING_LF_AFTER_CHUNK,
PARSE_EXPECTING_FINAL_CR_AFTER_LAST_CHUNK,
PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK
};
/// the current state of parsing HTTP headers
headers_parse_state_t m_headers_parse_state;
/// the current state of parsing chunked content
chunked_content_parse_state_t m_chunked_content_parse_state;
/// Used for parsing the HTTP response status code
boost::uint16_t m_status_code;
/// Used for parsing the HTTP response status message
string_type m_status_message;
/// Used for parsing the request method
string_type m_method;
/// Used for parsing the name of resource requested
string_type m_resource;
/// Used for parsing the query string portion of a URI
string_type m_query_string;
/// Used for parsing the name of HTTP headers
string_type m_header_name;
/// Used for parsing the value of HTTP headers
string_type m_header_value;
/// Used for parsing the chunk size
string_type m_chunk_size_str;
/// Used for parsing the current chunk
std::vector<char> m_current_chunk;
/// number of bytes in the chunk currently being parsed
std::size_t m_size_of_current_chunk;
/// number of bytes read so far in the chunk currently being parsed
std::size_t m_bytes_read_in_current_chunk;
/// number of bytes read during last parse operation
std::size_t m_bytes_last_read;
/// total number of bytes read while parsing the HTTP message
std::size_t m_bytes_total_read;
};
/// typedef for the default HTTP protocol parser implementation
typedef basic_parser<tags::default_> parser;
}; // namespace http
}; // namespace network
}; // namespace boost
// import implementation file
#include <boost/network/protocol/http/impl/parser.ipp>
#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_HPP