2
0
mirror of https://github.com/boostorg/asio.git synced 2026-01-28 06:42:08 +00:00
Files
asio/example/http/server2/request_parser.cpp
Christopher Kohlhoff 2c41e180c1 Merge from trunk. Fixes #3095, #3216, #3098, #3107, #1341, #2754, #3157, #2620, #2618.
........
  r54373 | chris_kohlhoff | 2009-06-26 21:03:14 +1000 (Fri, 26 Jun 2009) | 2 lines
  
  Fix doc generation for array reference parameters.
........
  r54376 | chris_kohlhoff | 2009-06-26 23:35:04 +1000 (Fri, 26 Jun 2009) | 2 lines
  
  Fix bug in hash resize. Ref #3095.
........
  r54377 | chris_kohlhoff | 2009-06-26 23:55:24 +1000 (Fri, 26 Jun 2009) | 3 lines
  
  Remove a local variable that was hiding the ec parameter and preventing
  error codes from being correctly propagated. Ref #3216.
........
  r54390 | chris_kohlhoff | 2009-06-27 12:17:49 +1000 (Sat, 27 Jun 2009) | 2 lines
  
  Fix failures reported when the tests are built with _GLIBCXX_DEBUG. Ref #3098.
........
  r54392 | chris_kohlhoff | 2009-06-27 15:24:16 +1000 (Sat, 27 Jun 2009) | 2 lines
  
  Fix custom memory allocation for timers. Ref #3107.
........
  r54393 | chris_kohlhoff | 2009-06-27 17:07:40 +1000 (Sat, 27 Jun 2009) | 2 lines
  
  Fix various g++ warnings. Ref #1341.
........
  r54400 | chris_kohlhoff | 2009-06-27 17:52:11 +1000 (Sat, 27 Jun 2009) | 4 lines
  
  Use boost::throw_exception() rather than throw keyword to allow asio to be
  used when exception support is disabled. Note that the SSL wrappers still
  require exception support. Refs #2754.
........
  r54407 | chris_kohlhoff | 2009-06-27 19:13:24 +1000 (Sat, 27 Jun 2009) | 2 lines
  
  Make links to function overloads more obvious.
........
  r54466 | chris_kohlhoff | 2009-06-28 23:07:43 +1000 (Sun, 28 Jun 2009) | 2 lines
  
  Add header file information to reference docs. Refs #3157.
........
  r54467 | chris_kohlhoff | 2009-06-28 23:20:17 +1000 (Sun, 28 Jun 2009) | 4 lines
  
  Treat 0-byte reads and writes as no-ops to comply with the documented type
  requirements for SyncReadStream, AsyncReadStream, SyncWriteStream and
  AsyncWriteStream.
........
  r54498 | chris_kohlhoff | 2009-06-29 19:32:41 +1000 (Mon, 29 Jun 2009) | 2 lines
  
  Add enum values to doc index. Refs #2620.
........


[SVN r54499]
2009-06-29 13:36:06 +00:00

327 lines
6.3 KiB
C++

//
// request_parser.cpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//
#include "request_parser.hpp"
#include "request.hpp"
namespace http {
namespace server2 {
request_parser::request_parser()
: state_(method_start)
{
}
void request_parser::reset()
{
state_ = method_start;
}
boost::tribool request_parser::consume(request& req, char input)
{
switch (state_)
{
case method_start:
if (!is_char(input) || is_ctl(input) || is_tspecial(input))
{
return false;
}
else
{
state_ = method;
req.method.push_back(input);
return boost::indeterminate;
}
case method:
if (input == ' ')
{
state_ = uri;
return boost::indeterminate;
}
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
{
return false;
}
else
{
req.method.push_back(input);
return boost::indeterminate;
}
case uri_start:
if (is_ctl(input))
{
return false;
}
else
{
state_ = uri;
req.uri.push_back(input);
return boost::indeterminate;
}
case uri:
if (input == ' ')
{
state_ = http_version_h;
return boost::indeterminate;
}
else if (is_ctl(input))
{
return false;
}
else
{
req.uri.push_back(input);
return boost::indeterminate;
}
case http_version_h:
if (input == 'H')
{
state_ = http_version_t_1;
return boost::indeterminate;
}
else
{
return false;
}
case http_version_t_1:
if (input == 'T')
{
state_ = http_version_t_2;
return boost::indeterminate;
}
else
{
return false;
}
case http_version_t_2:
if (input == 'T')
{
state_ = http_version_p;
return boost::indeterminate;
}
else
{
return false;
}
case http_version_p:
if (input == 'P')
{
state_ = http_version_slash;
return boost::indeterminate;
}
else
{
return false;
}
case http_version_slash:
if (input == '/')
{
req.http_version_major = 0;
req.http_version_minor = 0;
state_ = http_version_major_start;
return boost::indeterminate;
}
else
{
return false;
}
case http_version_major_start:
if (is_digit(input))
{
req.http_version_major = req.http_version_major * 10 + input - '0';
state_ = http_version_major;
return boost::indeterminate;
}
else
{
return false;
}
case http_version_major:
if (input == '.')
{
state_ = http_version_minor_start;
return boost::indeterminate;
}
else if (is_digit(input))
{
req.http_version_major = req.http_version_major * 10 + input - '0';
return boost::indeterminate;
}
else
{
return false;
}
case http_version_minor_start:
if (is_digit(input))
{
req.http_version_minor = req.http_version_minor * 10 + input - '0';
state_ = http_version_minor;
return boost::indeterminate;
}
else
{
return false;
}
case http_version_minor:
if (input == '\r')
{
state_ = expecting_newline_1;
return boost::indeterminate;
}
else if (is_digit(input))
{
req.http_version_minor = req.http_version_minor * 10 + input - '0';
return boost::indeterminate;
}
else
{
return false;
}
case expecting_newline_1:
if (input == '\n')
{
state_ = header_line_start;
return boost::indeterminate;
}
else
{
return false;
}
case header_line_start:
if (input == '\r')
{
state_ = expecting_newline_3;
return boost::indeterminate;
}
else if (!req.headers.empty() && (input == ' ' || input == '\t'))
{
state_ = header_lws;
return boost::indeterminate;
}
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
{
return false;
}
else
{
req.headers.push_back(header());
req.headers.back().name.push_back(input);
state_ = header_name;
return boost::indeterminate;
}
case header_lws:
if (input == '\r')
{
state_ = expecting_newline_2;
return boost::indeterminate;
}
else if (input == ' ' || input == '\t')
{
return boost::indeterminate;
}
else if (is_ctl(input))
{
return false;
}
else
{
state_ = header_value;
req.headers.back().value.push_back(input);
return boost::indeterminate;
}
case header_name:
if (input == ':')
{
state_ = space_before_header_value;
return boost::indeterminate;
}
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
{
return false;
}
else
{
req.headers.back().name.push_back(input);
return boost::indeterminate;
}
case space_before_header_value:
if (input == ' ')
{
state_ = header_value;
return boost::indeterminate;
}
else
{
return false;
}
case header_value:
if (input == '\r')
{
state_ = expecting_newline_2;
return boost::indeterminate;
}
else if (is_ctl(input))
{
return false;
}
else
{
req.headers.back().value.push_back(input);
return boost::indeterminate;
}
case expecting_newline_2:
if (input == '\n')
{
state_ = header_line_start;
return boost::indeterminate;
}
else
{
return false;
}
case expecting_newline_3:
return (input == '\n');
default:
return false;
}
}
bool request_parser::is_char(int c)
{
return c >= 0 && c <= 127;
}
bool request_parser::is_ctl(int c)
{
return (c >= 0 && c <= 31) || (c == 127);
}
bool request_parser::is_tspecial(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;
}
}
bool request_parser::is_digit(int c)
{
return c >= '0' && c <= '9';
}
} // namespace server2
} // namespace http