This file is indexed.

/usr/include/pion/http/parser.hpp is in libpion-dev 5.0.7+dfsg-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
// ---------------------------------------------------------------------
// pion:  a Boost C++ framework for building lightweight HTTP interfaces
// ---------------------------------------------------------------------
// Copyright (C) 2007-2014 Splunk Inc.  (https://github.com/splunk/pion)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//

#ifndef __PION_HTTP_PARSER_HEADER__
#define __PION_HTTP_PARSER_HEADER__

#include <string>
#include <boost/noncopyable.hpp>
#include <boost/function/function2.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/system/error_code.hpp>
#include <boost/thread/once.hpp>
#include <pion/config.hpp>
#include <pion/logger.hpp>
#include <pion/http/message.hpp>

#ifndef BOOST_SYSTEM_NOEXCEPT
    #define BOOST_SYSTEM_NOEXCEPT BOOST_NOEXCEPT
#endif


namespace pion {    // begin namespace pion
namespace http {    // begin namespace http


// forward declarations used for finishing HTTP messages
class request;
class response;

///
/// parser: parses HTTP messages
///
class PION_API parser :
    private boost::noncopyable
{

public:

    /// maximum length for HTTP payload content
    static const std::size_t        DEFAULT_CONTENT_MAX;

    /// callback type used to consume payload content
    typedef boost::function2<void, const char *, std::size_t>   payload_handler_t;
    
    /// class-specific error code values
    enum error_value_t {
        ERROR_METHOD_CHAR = 1,
        ERROR_METHOD_SIZE,
        ERROR_URI_CHAR,
        ERROR_URI_SIZE,
        ERROR_QUERY_CHAR,
        ERROR_QUERY_SIZE,
        ERROR_VERSION_EMPTY,
        ERROR_VERSION_CHAR,
        ERROR_STATUS_EMPTY,
        ERROR_STATUS_CHAR,
        ERROR_HEADER_CHAR,
        ERROR_HEADER_NAME_SIZE,
        ERROR_HEADER_VALUE_SIZE,
        ERROR_INVALID_CONTENT_LENGTH,
        ERROR_CHUNK_CHAR,
        ERROR_MISSING_CHUNK_DATA,
        ERROR_MISSING_HEADER_DATA,
        ERROR_MISSING_TOO_MUCH_CONTENT,
    };
    
    /// class-specific error category
    class error_category_t
        : public boost::system::error_category
    {
    public:
        const char *name() const BOOST_SYSTEM_NOEXCEPT { return "parser"; }
        std::string message(int ev) const {
            switch (ev) {
            case ERROR_METHOD_CHAR:
                return "invalid method character";
            case ERROR_METHOD_SIZE:
                return "method exceeds maximum size";
            case ERROR_URI_CHAR:
                return "invalid URI character";
            case ERROR_URI_SIZE:
                return "method exceeds maximum size";
            case ERROR_QUERY_CHAR:
                return "invalid query string character";
            case ERROR_QUERY_SIZE:
                return "query string exceeds maximum size";
            case ERROR_VERSION_EMPTY:
                return "HTTP version undefined";
            case ERROR_VERSION_CHAR:
                return "invalid version character";
            case ERROR_STATUS_EMPTY:
                return "HTTP status undefined";
            case ERROR_STATUS_CHAR:
                return "invalid status character";
            case ERROR_HEADER_CHAR:
                return "invalid header character";
            case ERROR_HEADER_NAME_SIZE:
                return "header name exceeds maximum size";
            case ERROR_HEADER_VALUE_SIZE:
                return "header value exceeds maximum size";
            case ERROR_INVALID_CONTENT_LENGTH:
                return "invalid Content-Length header";
            case ERROR_CHUNK_CHAR:
                return "invalid chunk character";
            case ERROR_MISSING_HEADER_DATA:
                return "missing header data";
            case ERROR_MISSING_CHUNK_DATA:
                return "missing chunk data";
            case ERROR_MISSING_TOO_MUCH_CONTENT:
                return "missing too much content";
            }
            return "parser error";
        }
    };

    /**
     * creates new parser objects
     *
     * @param is_request if true, the message is parsed as an HTTP request;
     *                   if false, the message is parsed as an HTTP response
     * @param max_content_length maximum length for HTTP payload content
     */
    parser(const bool is_request, std::size_t max_content_length = DEFAULT_CONTENT_MAX)
        : m_logger(PION_GET_LOGGER("pion.http.parser")), m_is_request(is_request),
        m_read_ptr(NULL), m_read_end_ptr(NULL), m_message_parse_state(PARSE_START),
        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_content_remaining(0), m_bytes_content_read(0),
        m_bytes_last_read(0), m_bytes_total_read(0),
        m_max_content_length(max_content_length),
        m_parse_headers_only(false), m_save_raw_headers(false)
    {}

    /// default destructor
    virtual ~parser() {}

    /**
     * parses an HTTP message including all payload content it might contain
     *
     * @param http_msg the HTTP message object to populate from parsing
     * @param ec error_code contains additional information for parsing errors
     *
     * @return boost::tribool result of parsing:
     *                        false = message has an error,
     *                        true = finished parsing HTTP message,
     *                        indeterminate = not yet finished parsing HTTP message
     */
    boost::tribool parse(http::message& http_msg, boost::system::error_code& ec);

    /**
     * attempts to continue parsing despite having missed data (length is known but content is not)
     *
     * @param http_msg the HTTP message object to populate from parsing
     * @param len the length in bytes of the missing data
     * @param ec error_code contains additional information for parsing errors
     *
     * @return boost::tribool result of parsing:
     *                        false = message has an error,
     *                        true = finished parsing HTTP message,
     *                        indeterminate = not yet finished parsing HTTP message
     */
    boost::tribool parse_missing_data(http::message& http_msg, std::size_t len,
        boost::system::error_code& ec);

    /**
     * finishes parsing an HTTP response message
     *
     * @param http_msg the HTTP message object to finish
     */
    void finish(http::message& http_msg) const;

    /**
     * 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, size_t len) {
        m_read_ptr = ptr;
        m_read_end_ptr = ptr + len;
    }

    /**
     * loads a 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 load_read_pos(const char *&read_ptr, const char *&read_end_ptr) const {
        read_ptr = m_read_ptr;
        read_end_ptr = m_read_end_ptr;
    }

    /**
     * checks to see if a premature EOF was encountered while parsing.  This
     * should be called if there is no more data to parse, and if the last
     * call to the parse() function returned boost::indeterminate
     *
     * @param http_msg the HTTP message object being parsed
     * @return true if premature EOF, false if message is OK & finished parsing
     */
    inline bool check_premature_eof(http::message& http_msg) {
        if (m_message_parse_state != PARSE_CONTENT_NO_LENGTH)
            return true;
        m_message_parse_state = PARSE_END;
        http_msg.concatenate_chunks();
        finish(http_msg);
        return false;
    }

    /**
     * controls headers-only parsing (default is disabled; content parsed also)
     *
     * @param b if true, then the parse() function returns true after headers
     */
    inline void parse_headers_only(bool b = true) { m_parse_headers_only = b; }

    /**
     * skip parsing all headers and parse payload content only
     *
     * @param http_msg the HTTP message object being parsed
     */
    inline void skip_header_parsing(http::message& http_msg) {
        boost::system::error_code ec;
        finish_header_parsing(http_msg, ec);
    }
    
    /// resets the parser to its initial state
    inline void reset(void) {
        m_message_parse_state = PARSE_START;
        m_headers_parse_state = (m_is_request ? PARSE_METHOD_START : PARSE_HTTP_VERSION_H);
        m_chunked_content_parse_state = PARSE_CHUNK_SIZE_START;
        m_status_code = 0;
        m_status_message.erase();
        m_method.erase();
        m_resource.erase();
        m_query_string.erase();
        m_raw_headers.erase();
        m_bytes_content_read = m_bytes_last_read = m_bytes_total_read = 0;
    }

    /// 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 available in the read buffer
    inline std::size_t bytes_available(void) const { return (eof() ? 0 : (std::size_t)(m_read_end_ptr - m_read_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 get_total_bytes_read(void) const { return m_bytes_total_read; }

    /// returns the total number of bytes read while parsing the payload content
    inline std::size_t get_content_bytes_read(void) const { return m_bytes_content_read; }

    /// returns the maximum length for HTTP payload content
    inline std::size_t get_max_content_length(void) const { return m_max_content_length; }

    /// returns the raw HTTP headers saved by the parser
    inline const std::string& get_raw_headers(void) const { return m_raw_headers; }

    /// returns true if the parser is saving raw HTTP header contents
    inline bool get_save_raw_headers(void) const { return m_save_raw_headers; }

    /// returns true if parsing headers only
    inline bool get_parse_headers_only(void) { return m_parse_headers_only; }
    
    /// returns true if the parser is being used to parse an HTTP request
    inline bool is_parsing_request(void) const { return m_is_request; }

    /// returns true if the parser is being used to parse an HTTP response
    inline bool is_parsing_response(void) const { return ! m_is_request; }

    /// defines a callback function to be used for consuming payload content
    inline void set_payload_handler(payload_handler_t& h) { m_payload_handler = h; }

    /// sets the maximum length for HTTP payload content
    inline void set_max_content_length(std::size_t n) { m_max_content_length = n; }

    /// resets the maximum length for HTTP payload content to the default value
    inline void reset_max_content_length(void) { m_max_content_length = DEFAULT_CONTENT_MAX; }

    /// sets parameter for saving raw HTTP header content
    inline void set_save_raw_headers(bool b) { m_save_raw_headers = b; }

    /// sets the logger to be used
    inline void set_logger(logger log_ptr) { m_logger = log_ptr; }

    /// returns the logger currently in use
    inline logger get_logger(void) { return m_logger; }


    /**
     * parses a URI string
     *
     * @param uri the string to parse
     * @param proto will be set to the protocol (i.e. "http")
     * @param host will be set to the hostname (i.e. "www.cloudmeter.com")
     * @param port host port number to use for connection (i.e. 80)
     * @param path uri stem or file path
     * @param query uri query string
     *
     * @return true if the URI was successfully parsed, false if there was an error
     */
    static bool parse_uri(const std::string& uri, std::string& proto, 
                         std::string& host, boost::uint16_t& port, std::string& path,
                         std::string& query);

    /**
     * parse key-value pairs out of a url-encoded string
     * (i.e. this=that&a=value)
     * 
     * @param dict dictionary for key-values 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(ihash_multimap& dict,
                                const char *ptr, const std::size_t len);

    /**
     * parse key-value pairs out of a multipart/form-data payload content
     * (http://www.ietf.org/rfc/rfc2388.txt)
     *
     * @param dict dictionary for key-values pairs
     * @param content_type value of the content-type HTTP header
     * @param ptr points to the start of the encoded data
     * @param len length of the encoded data, in bytes
     *
     * @return bool true if successful
     */
    static bool parse_multipart_form_data(ihash_multimap& dict,
                                          const std::string& content_type,
                                          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 dict dictionary for key-values pairs
     * @param ptr points to the start of the header string to be parsed
     * @param len length of the encoded string, in bytes
     * @param set_cookie_header set true if parsing Set-Cookie response header
     * 
     * @return bool true if successful
     */
    static bool parse_cookie_header(ihash_multimap& dict,
                                  const char *ptr, const std::size_t len,
                                  bool set_cookie_header);

    /**
     * parse key-value pairs out of a "Cookie" request header
     * (i.e. this=that; a=value)
     * 
     * @param dict dictionary for key-values pairs
     * @param cookie_header header string to be parsed
     * @param set_cookie_header set true if parsing Set-Cookie response header
     * 
     * @return bool true if successful
     */
    static inline bool parse_cookie_header(ihash_multimap& dict,
        const std::string& cookie_header, bool set_cookie_header)
    {
        return parse_cookie_header(dict, cookie_header.c_str(), cookie_header.size(), set_cookie_header);
    }

    /**
     * parse key-value pairs out of a url-encoded string
     * (i.e. this=that&a=value)
     * 
     * @param dict dictionary for key-values pairs
     * @param query the encoded query string to be parsed
     * 
     * @return bool true if successful
     */
    static inline bool parse_url_encoded(ihash_multimap& dict,
        const std::string& query)
    {
        return parse_url_encoded(dict, query.c_str(), query.size());
    }
    
    /**
     * parse key-value pairs out of a multipart/form-data payload content
     * (http://www.ietf.org/rfc/rfc2388.txt)
     *
     * @param dict dictionary for key-values pairs
     * @param content_type value of the content-type HTTP header
     * @param form_data the encoded form data
     *
     * @return bool true if successful
     */
    static inline bool parse_multipart_form_data(ihash_multimap& dict,
                                                 const std::string& content_type,
                                                 const std::string& form_data)
    {
        return parse_multipart_form_data(dict, content_type, form_data.c_str(), form_data.size());
    }
    
    /**
     * should be called after parsing HTTP headers, to prepare for payload content parsing
     * available in the read buffer
     *
     * @param http_msg the HTTP message object to populate from parsing
     * @param ec error_code contains additional information for parsing errors
     *
     * @return boost::tribool result of parsing:
     *                        false = message has an error,
     *                        true = finished parsing HTTP message (no content),
     *                        indeterminate = payload content is available to be parsed
     */
    boost::tribool finish_header_parsing(http::message& http_msg,
                                         boost::system::error_code& ec);

    /**
     * parses an X-Forwarded-For HTTP header, and extracts from it an IP
     * address that best matches the client's public IP address (if any are found)
     *
     * @param header the X-Forwarded-For HTTP header to parse
     * @param public_ip the extract IP address, if found
     *
     * @return bool true if a public IP address was found and extracted
     */
    static bool parse_forwarded_for(const std::string& header, std::string& public_ip);
    
    /// returns an instance of parser::error_category_t
    static inline error_category_t& get_error_category(void) {
        boost::call_once(parser::create_error_category, m_instance_flag);
        return *m_error_category_ptr;
    }


protected:

    /// Called after we have finished parsing the HTTP message headers
    virtual void finished_parsing_headers(const boost::system::error_code& ec) {}
    
    /**
     * 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
     * @param ec error_code contains additional information for parsing errors
     *
     * @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_headers(http::message& http_msg, boost::system::error_code& ec);

    /**
     * updates an http::message object with data obtained from parsing headers
     *
     * @param http_msg the HTTP message object to populate from parsing
     */
    void update_message_with_header_data(http::message& http_msg) const;

    /**
     * parses a chunked HTTP message-body using bytes available in the read buffer
     *
     * @param chunk_buffers buffers to be populated from parsing chunked content
     * @param ec error_code contains additional information for parsing errors
     *
     * @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(http::message::chunk_cache_t& chunk_buffers,
        boost::system::error_code& ec);

    /**
     * consumes payload content in the parser's read buffer 
     *
     * @param http_msg the HTTP message object to consume content for
     * @param ec error_code contains additional information for parsing errors
     *  
     * @return boost::tribool result of parsing:
     *                        false = message has an error,
     *                        true = finished parsing message,
     *                        indeterminate = message is not yet finished
     */
    boost::tribool consume_content(http::message& http_msg,
        boost::system::error_code& ec);

    /**
     * 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 std::size_t number of content bytes consumed, if any
     */
    std::size_t consume_content_as_next_chunk(http::message::chunk_cache_t& chunk_buffers);

    /**
     * compute and sets a HTTP Message data integrity status
     * @param http_msg target HTTP message 
     * @param msg_parsed_ok message parsing result
     */
    static void compute_msg_status(http::message& http_msg, bool msg_parsed_ok);

    /**
     * sets an error code
     *
     * @param ec error code variable to define
     * @param ev error value to raise
     */
    static inline void set_error(boost::system::error_code& ec, error_value_t ev) {
        ec = boost::system::error_code(static_cast<int>(ev), get_error_category());
    }

    /// creates the unique parser error_category_t
    static void create_error_category(void);


    // misc functions used by the parsing functions
    inline static bool is_char(int c);
    inline static bool is_control(int c);
    inline static bool is_special(int c);
    inline static bool is_digit(int c);
    inline static bool is_hex_digit(int c);
    inline static bool is_cookie_attribute(const std::string& name, bool set_cookie_header);


    /// maximum length for response status message
    static const boost::uint32_t        STATUS_MESSAGE_MAX;

    /// maximum length for the request method
    static const boost::uint32_t        METHOD_MAX;

    /// maximum length for the resource requested
    static const boost::uint32_t        RESOURCE_MAX;

    /// maximum length for the query string
    static const boost::uint32_t        QUERY_STRING_MAX;

    /// maximum length for an HTTP header name
    static const boost::uint32_t        HEADER_NAME_MAX;

    /// maximum length for an HTTP header value
    static const boost::uint32_t        HEADER_VALUE_MAX;

    /// maximum length for the name of a query string variable
    static const boost::uint32_t        QUERY_NAME_MAX;

    /// maximum length for the value of a query string variable
    static const boost::uint32_t        QUERY_VALUE_MAX;

    /// maximum length for the name of a cookie name
    static const boost::uint32_t        COOKIE_NAME_MAX;

    /// maximum length for the value of a cookie; also used for path and domain
    static const boost::uint32_t        COOKIE_VALUE_MAX;


    /// primary logging interface used by this class
    mutable logger                      m_logger;

    /// 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:

    /// state used to keep track of where we are in parsing the HTTP message
    enum message_parse_state_t {
        PARSE_START, PARSE_HEADERS, PARSE_FOOTERS, PARSE_CONTENT,
        PARSE_CONTENT_NO_LENGTH, PARSE_CHUNKS, PARSE_END
    };

    /// state used to keep track of where we are in parsing the HTTP headers
    /// (only used if message_parse_state_t == PARSE_HEADERS)
    enum header_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
    /// (only used if message_parse_state_t == PARSE_CHUNKS)
    enum chunk_parse_state_t {
        PARSE_CHUNK_SIZE_START, PARSE_CHUNK_SIZE,
        PARSE_EXPECTING_IGNORED_TEXT_AFTER_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_OR_FOOTERS_AFTER_LAST_CHUNK, 
        PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK
    };


    /// the current state of parsing HTTP headers
    message_parse_state_t               m_message_parse_state;

    /// the current state of parsing HTTP headers
    header_parse_state_t                m_headers_parse_state;

    /// the current state of parsing chunked content
    chunk_parse_state_t                 m_chunked_content_parse_state;
    
    /// if defined, this function is used to consume payload content
    payload_handler_t                   m_payload_handler;

    /// Used for parsing the HTTP response status code
    boost::uint16_t                     m_status_code;

    /// Used for parsing the HTTP response status message
    std::string                         m_status_message;

    /// Used for parsing the request method
    std::string                         m_method;

    /// Used for parsing the name of resource requested
    std::string                         m_resource;

    /// Used for parsing the query string portion of a URI
    std::string                         m_query_string;

    /// Used to store the raw contents of HTTP headers when m_save_raw_headers is true
    std::string                         m_raw_headers;

    /// Used for parsing the name of HTTP headers
    std::string                         m_header_name;

    /// Used for parsing the value of HTTP headers
    std::string                         m_header_value;

    /// Used for parsing the chunk size
    std::string                         m_chunk_size_str;

    /// 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 payload content bytes that have not yet been read
    std::size_t                         m_bytes_content_remaining;

    /// number of bytes read so far into the message's payload content
    std::size_t                         m_bytes_content_read;

    /// 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;

    /// maximum length for HTTP payload content
    std::size_t                         m_max_content_length;
    
    /// if true, then only HTTP headers will be parsed (no content parsing)
    bool                                m_parse_headers_only;

    /// if true, the raw contents of HTTP headers are stored into m_raw_headers
    bool                                m_save_raw_headers;

    /// points to a single and unique instance of the parser error_category_t
    static error_category_t *           m_error_category_ptr;
        
    /// used to ensure thread safety of the parser error_category_t
    static boost::once_flag             m_instance_flag;
};


// inline functions for parser

inline bool parser::is_char(int c)
{
    return(c >= 0 && c <= 127);
}

inline bool parser::is_control(int c)
{
    return( (c >= 0 && c <= 31) || c == 127);
}

inline bool parser::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;
    }
}

inline bool parser::is_digit(int c)
{
    return(c >= '0' && c <= '9');
}

inline bool parser::is_hex_digit(int c)
{
    return((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}

inline bool parser::is_cookie_attribute(const std::string& name, bool set_cookie_header)
{
    return (name.empty() || name[0] == '$' || (set_cookie_header &&
        (
            // This is needed because of a very lenient determination in parse_cookie_header() of what
            // qualifies as a cookie-pair in a Set-Cookie header.
            // According to RFC 6265, everything after the first semicolon is a cookie attribute, but RFC 2109,
            // which is obsolete, allowed multiple comma separated cookies.
            // parse_cookie_header() is very conservatively assuming that any <name>=<value> pair in a
            // Set-Cookie header is a cookie-pair unless <name> is a known cookie attribute.
               boost::algorithm::iequals(name, "Comment")
            || boost::algorithm::iequals(name, "Domain")
            || boost::algorithm::iequals(name, "Max-Age")
            || boost::algorithm::iequals(name, "Path")
            || boost::algorithm::iequals(name, "Secure")
            || boost::algorithm::iequals(name, "Version")
            || boost::algorithm::iequals(name, "Expires")
            || boost::algorithm::iequals(name, "HttpOnly")
        )
    ));
}

}   // end namespace http
}   // end namespace pion

#endif