staticlib_pion  2.0.2
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Macros
http_parser.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015, alex at staticlibs.net
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // ---------------------------------------------------------------------
18 // pion: a Boost C++ framework for building lightweight HTTP interfaces
19 // ---------------------------------------------------------------------
20 // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion)
21 //
22 // Distributed under the Boost Software License, Version 1.0.
23 // See http://www.boost.org/LICENSE_1_0.txt
24 //
25 
26 #ifndef STATICLIB_PION_HTTP_PARSER_HPP
27 #define STATICLIB_PION_HTTP_PARSER_HPP
28 
29 #include <cstdint>
30 #include <functional>
31 #include <mutex>
32 #include <string>
33 
34 #include "staticlib/config.hpp"
35 #include "staticlib/support.hpp"
36 
40 
41 namespace staticlib {
42 namespace pion {
43 
44 // forward declarations used for finishing HTTP messages
45 class http_request;
46 class http_response;
47 
51 class http_parser {
52 public:
53 
57  static const size_t DEFAULT_CONTENT_MAX;
58 
62  using payload_handler_type = std::function<void(const char *, size_t)>;
63 
86  };
87 
91  class error_category_t : public asio::error_category {
92  public:
98  const char *name() const STATICLIB_NOEXCEPT {
99  return "parser";
100  }
101 
108  std::string message(int ev) const;
109  };
110 
111 protected:
112 
116  static const uint32_t STATUS_MESSAGE_MAX;
117 
121  static const uint32_t METHOD_MAX;
122 
126  static const uint32_t RESOURCE_MAX;
127 
131  static const uint32_t QUERY_STRING_MAX;
132 
136  static const uint32_t HEADER_NAME_MAX;
137 
141  static const uint32_t HEADER_VALUE_MAX;
142 
146  static const uint32_t QUERY_NAME_MAX;
147 
151  static const uint32_t QUERY_VALUE_MAX;
152 
156  static const uint32_t COOKIE_NAME_MAX;
157 
161  static const uint32_t COOKIE_VALUE_MAX;
162 
166  const char * m_read_ptr;
167 
171  const char * m_read_end_ptr;
172 
173 private:
177  enum message_parse_state_type {
178  PARSE_START,
179  PARSE_HEADERS,
180  PARSE_FOOTERS,
181  PARSE_CONTENT,
182  PARSE_CONTENT_NO_LENGTH,
183  PARSE_CHUNKS, PARSE_END
184  };
185 
190  enum header_parse_state_type {
191  PARSE_METHOD_START,
192  PARSE_METHOD,
193  PARSE_URI_STEM,
194  PARSE_URI_QUERY,
195  PARSE_HTTP_VERSION_H,
196  PARSE_HTTP_VERSION_T_1,
197  PARSE_HTTP_VERSION_T_2,
198  PARSE_HTTP_VERSION_P,
199  PARSE_HTTP_VERSION_SLASH,
200  PARSE_HTTP_VERSION_MAJOR_START,
201  PARSE_HTTP_VERSION_MAJOR,
202  PARSE_HTTP_VERSION_MINOR_START,
203  PARSE_HTTP_VERSION_MINOR,
204  PARSE_STATUS_CODE_START,
205  PARSE_STATUS_CODE,
206  PARSE_STATUS_MESSAGE,
207  PARSE_EXPECTING_NEWLINE,
208  PARSE_EXPECTING_CR,
209  PARSE_HEADER_WHITESPACE,
210  PARSE_HEADER_START,
211  PARSE_HEADER_NAME,
212  PARSE_SPACE_BEFORE_HEADER_VALUE,
213  PARSE_HEADER_VALUE,
214  PARSE_EXPECTING_FINAL_NEWLINE,
215  PARSE_EXPECTING_FINAL_CR
216  };
217 
222  enum chunk_parse_state_type {
223  PARSE_CHUNK_SIZE_START,
224  PARSE_CHUNK_SIZE,
225  PARSE_EXPECTING_IGNORED_TEXT_AFTER_CHUNK_SIZE,
226  PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE,
227  PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE,
228  PARSE_CHUNK,
229  PARSE_EXPECTING_CR_AFTER_CHUNK,
230  PARSE_EXPECTING_LF_AFTER_CHUNK,
231  PARSE_EXPECTING_FINAL_CR_OR_FOOTERS_AFTER_LAST_CHUNK,
232  PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK
233  };
234 
238  message_parse_state_type m_message_parse_state;
239 
243  header_parse_state_type m_headers_parse_state;
244 
248  chunk_parse_state_type m_chunked_content_parse_state;
249 
253  payload_handler_type* m_payload_handler = nullptr;
254 
258  uint16_t m_status_code;
259 
263  std::string m_status_message;
264 
268  std::string m_method;
269 
273  std::string m_resource;
274 
278  std::string m_query_string;
279 
283  std::string m_raw_headers;
284 
288  std::string m_header_name;
289 
293  std::string m_header_value;
294 
298  std::string m_chunk_size_str;
299 
303  size_t m_size_of_current_chunk;
304 
308  size_t m_bytes_read_in_current_chunk;
309 
313  size_t m_bytes_content_remaining;
314 
318  size_t m_bytes_content_read;
319 
323  size_t m_bytes_last_read;
324 
328  size_t m_bytes_total_read;
329 
333  size_t m_max_content_length;
334 
338  bool m_parse_headers_only;
339 
343  bool m_save_raw_headers;
344 
348  static error_category_t * m_error_category_ptr;
349 
353  static std::once_flag m_instance_flag;
354 
355 public:
356 
362  http_parser(size_t max_content_length = DEFAULT_CONTENT_MAX) :
363  m_read_ptr(nullptr),
364  m_read_end_ptr(nullptr),
365  m_message_parse_state(PARSE_START),
366  m_headers_parse_state(PARSE_METHOD_START),
367  m_chunked_content_parse_state(PARSE_CHUNK_SIZE_START),
368  m_status_code(0),
369  m_bytes_content_remaining(0),
370  m_bytes_content_read(0),
371  m_bytes_last_read(0),
372  m_bytes_total_read(0),
373  m_max_content_length(max_content_length),
374  m_parse_headers_only(false),
375  m_save_raw_headers(false) { }
376 
380  http_parser(const http_parser&) = delete;
381 
385  http_parser& operator=(const http_parser&) = delete;
386 
390  virtual ~http_parser() STATICLIB_NOEXCEPT { }
391 
403  sl::support::tribool parse(http_message& http_msg, std::error_code& ec);
404 
410  void finish(http_message& http_msg) const;
411 
418  void set_read_buffer(const char *ptr, size_t len) {
419  m_read_ptr = ptr;
420  m_read_end_ptr = ptr + len;
421  }
422 
429  void load_read_pos(const char *&read_ptr, const char *&read_end_ptr) const {
430  read_ptr = m_read_ptr;
431  read_end_ptr = m_read_end_ptr;
432  }
433 
443  if (m_message_parse_state != PARSE_CONTENT_NO_LENGTH) {
444  return true;
445  }
446  m_message_parse_state = PARSE_END;
447  http_msg.concatenate_chunks();
448  finish(http_msg);
449  return false;
450  }
451 
457  void parse_headers_only(bool b = true) {
458  m_parse_headers_only = b;
459  }
460 
467  std::error_code ec;
468  finish_header_parsing(http_msg, ec);
469  }
470 
474  void reset() {
475  m_message_parse_state = PARSE_START;
476  m_headers_parse_state = PARSE_METHOD_START;
477  m_chunked_content_parse_state = PARSE_CHUNK_SIZE_START;
478  m_status_code = 0;
479  m_status_message.erase();
480  m_method.erase();
481  m_resource.erase();
482  m_query_string.erase();
483  m_raw_headers.erase();
484  m_bytes_content_read = m_bytes_last_read = m_bytes_total_read = 0;
485  }
486 
492  bool eof() const {
493  return m_read_ptr == nullptr || m_read_ptr >= m_read_end_ptr;
494  }
495 
501  size_t bytes_available() const {
502  return (eof() ? 0 : (size_t)(m_read_end_ptr - m_read_ptr));
503  }
504 
510  size_t gcount() const {
511  return m_bytes_last_read;
512  }
513 
519  size_t get_total_bytes_read() const {
520  return m_bytes_total_read;
521  }
522 
528  size_t get_content_bytes_read() const {
529  return m_bytes_content_read;
530  }
531 
537  size_t get_max_content_length() const {
538  return m_max_content_length;
539  }
540 
546  const std::string& get_raw_headers() const {
547  return m_raw_headers;
548  }
549 
553  bool get_save_raw_headers() const {
554  return m_save_raw_headers;
555  }
556 
563  return m_parse_headers_only;
564  }
565 
571  bool is_parsing_request() const;
572 
578  bool is_parsing_response() const;
579 
585  void set_payload_handler(payload_handler_type& h) {
586  m_payload_handler = &h;
587  }
588 
594  void set_max_content_length(size_t n) {
595  m_max_content_length = n;
596  }
597 
602  m_max_content_length = DEFAULT_CONTENT_MAX;
603  }
604 
610  void set_save_raw_headers(bool b) {
611  m_save_raw_headers = b;
612  }
613 
626  static bool parse_uri(const std::string& uri, std::string& proto, std::string& host,
627  uint16_t& port, std::string& path, std::string& query);
628 
639  static bool parse_url_encoded(std::unordered_multimap<std::string, std::string, algorithm::ihash, algorithm::iequal_to>& dict,
640  const char *ptr, const size_t len);
641 
653  static bool parse_multipart_form_data(std::unordered_multimap<std::string, std::string, algorithm::ihash, algorithm::iequal_to>& dict,
654  const std::string& content_type, const char *ptr, const size_t len);
655 
667  static bool parse_cookie_header(std::unordered_multimap<std::string, std::string, algorithm::ihash, algorithm::iequal_to>& dict,
668  const char *ptr, const size_t len, bool set_cookie_header);
669 
680  static bool parse_cookie_header(std::unordered_multimap<std::string, std::string, algorithm::ihash, algorithm::iequal_to>& dict,
681  const std::string& cookie_header, bool set_cookie_header);
682 
692  static bool parse_url_encoded(std::unordered_multimap<std::string, std::string, algorithm::ihash, algorithm::iequal_to>& dict,
693  const std::string& query);
694 
705  static bool parse_multipart_form_data(std::unordered_multimap<std::string, std::string, algorithm::ihash, algorithm::iequal_to>& dict,
706  const std::string& content_type, const std::string& form_data);
707 
720  sl::support::tribool finish_header_parsing(http_message& http_msg, std::error_code& ec);
721 
728  std::call_once(m_instance_flag, http_parser::create_error_category);
729  return *m_error_category_ptr;
730  }
731 
732 protected:
733 
740  virtual void finished_parsing_headers(const std::error_code& /* ec */, sl::support::tribool& /* rc */) {
741  // no-op
742  }
743 
756  sl::support::tribool parse_headers(http_message& http_msg, std::error_code& ec);
757 
763  void update_message_with_header_data(http_message& http_msg) const;
764 
776  sl::support::tribool parse_chunks(std::vector<char>& chunk_buffers, std::error_code& ec);
777 
789  sl::support::tribool consume_content(http_message& http_msg, std::error_code& ec);
790 
798  size_t consume_content_as_next_chunk(std::vector<char>& chunk_buffers);
799 
805  static void compute_msg_status(http_message& http_msg, bool msg_parsed_ok);
806 
813  static void set_error(std::error_code& ec, error_value_t ev) {
814  ec = std::error_code(static_cast<int> (ev), get_error_category());
815  }
816 
820  static void create_error_category() {
821  static error_category_t UNIQUE_ERROR_CATEGORY;
822  m_error_category_ptr = &UNIQUE_ERROR_CATEGORY;
823  }
824 
825  // misc functions used by the parsing functions
826 
827  static bool is_digit(int c) {
828  return (c >= '0' && c <= '9');
829  }
830 
831  static bool is_hex_digit(int c) {
832  return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
833  }
834 
835  static bool is_cookie_attribute(const std::string& name, bool set_cookie_header);
836 
837 };
838 
839 } // namespace
840 }
841 
842 #endif // STATICLIB_PION_HTTP_PARSER_HPP