2 * This code implements parsing of HTTP requests.
3 * This code was written by Steve Hanov in 2009, no copyright is claimed.
4 * This code is in the public domain.
5 * Code was taken from http://refactormycode.com/codes/778-an-efficient-http-parser
7 * Copyright (C) 2011-2013 Team XBMC
10 * This Program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * This Program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with XBMC; see the file COPYING. If not, see
22 * <http://www.gnu.org/licenses/>.
26 #include "HttpParser.h"
28 HttpParser::HttpParser() :
43 HttpParser::~HttpParser()
49 HttpParser::parseHeader()
60 // convert current character to null.
63 // set the header index to the current position
64 SET_HEADER_START = 0x4,
66 // set the key index to the current position
69 // set value index to the current position.
72 // store current key/value pair.
73 STORE_KEY_VALUE = 0x20,
75 // sets content start to current position + 1
76 SET_CONTENT_START = 0x40
79 static const struct FSM {
85 { p_request_line, CR, p_request_line_cr, NULLIFY },
86 { p_request_line, ANY, p_request_line, 0 },
87 { p_request_line_cr, LF, p_request_line_crlf, 0 },
88 { p_request_line_crlf, CR, p_request_line_crlfcr, 0 },
89 { p_request_line_crlf, ANY, p_key, SET_HEADER_START | SET_KEY | LOWER },
90 { p_request_line_crlfcr, LF, p_content, SET_CONTENT_START },
91 { p_key, ':', p_key_colon, NULLIFY },
92 { p_key, ANY, p_key, LOWER },
93 { p_key_colon, ' ', p_key_colon_sp, 0 },
94 { p_key_colon_sp, ANY, p_value, SET_VALUE },
95 { p_value, CR, p_value_cr, NULLIFY | STORE_KEY_VALUE },
96 { p_value, ANY, p_value, 0 },
97 { p_value_cr, LF, p_value_crlf, 0 },
98 { p_value_crlf, CR, p_value_crlfcr, 0 },
99 { p_value_crlf, ANY, p_key, SET_KEY | LOWER },
100 { p_value_crlfcr, LF, p_content, SET_CONTENT_START },
101 { p_error, ANY, p_error, 0 }
104 for( unsigned i = _parsedTo; i < _data.length(); ++i) {
106 State nextState = p_error;
108 for ( unsigned d = 0; d < sizeof(fsm) / sizeof(FSM); ++d ) {
109 if ( fsm[d].curState == _state &&
110 ( c == fsm[d].c || fsm[d].c == ANY ) ) {
112 nextState = fsm[d].nextState;
114 if ( fsm[d].actions & LOWER ) {
115 _data[i] = tolower( _data[i] );
118 if ( fsm[d].actions & NULLIFY ) {
122 if ( fsm[d].actions & SET_HEADER_START ) {
126 if ( fsm[d].actions & SET_KEY ) {
130 if ( fsm[d].actions & SET_VALUE ) {
134 if ( fsm[d].actions & SET_CONTENT_START ) {
135 _contentStart = i + 1;
138 if ( fsm[d].actions & STORE_KEY_VALUE ) {
139 // store position of first character of key.
140 _keys.push_back( _keyIndex );
149 if ( _state == p_content ) {
150 const char* str = getValue("content-length");
152 _contentLength = atoi( str );
158 _parsedTo = _data.length();
163 HttpParser::parseRequestLine()
168 sp1 = _data.find( ' ', 0 );
169 if ( sp1 == std::string::npos ) return false;
170 sp2 = _data.find( ' ', sp1 + 1 );
171 if ( sp2 == std::string::npos ) return false;
180 HttpParser::addBytes( const char* bytes, unsigned len )
182 if ( _status != Incomplete ) {
186 // append the bytes to data.
187 _data.append( bytes, len );
189 if ( _state < p_content ) {
193 if ( _state == p_error ) {
195 } else if ( _state == p_content ) {
196 if ( _contentLength == 0 || _data.length() - _contentStart >= _contentLength ) {
197 if ( parseRequestLine() ) {
209 HttpParser::getMethod()
217 return &_data[_uriIndex];
221 HttpParser::getQueryString()
223 const char* pos = getUri();
235 HttpParser::getBody()
237 if ( _contentLength > 0 ) {
238 return &_data[_contentStart];
244 // key should be in lower case.
246 HttpParser::getValue( const char* key )
248 for( IntArray::iterator iter = _keys.begin();
249 iter != _keys.end(); ++iter )
251 unsigned index = *iter;
252 if ( strcmp( &_data[index], key ) == 0 ) {
253 return &_data[index + strlen(key) + 2];
262 HttpParser::getContentLength()
264 return _contentLength;