[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / utils / HttpParser.cpp
blob9276d4ca49dcb5b5c2fc5730f24767ec4ed0da6e
1 /*
2 * Copyright (C) 2011-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
8 * This code implements parsing of HTTP requests.
9 * This code was written by Steve Hanov in 2009, no copyright is claimed.
10 * This code is in the public domain.
11 * Code was taken from http://refactormycode.com/codes/778-an-efficient-http-parser
14 #include "HttpParser.h"
16 HttpParser::~HttpParser() = default;
18 void
19 HttpParser::parseHeader()
21 // run the fsm.
22 const int CR = 13;
23 const int LF = 10;
24 const int ANY = 256;
26 enum Action {
27 // make lower case
28 LOWER = 0x1,
30 // convert current character to null.
31 NULLIFY = 0x2,
33 // set the header index to the current position
34 SET_HEADER_START = 0x4,
36 // set the key index to the current position
37 SET_KEY = 0x8,
39 // set value index to the current position.
40 SET_VALUE = 0x10,
42 // store current key/value pair.
43 STORE_KEY_VALUE = 0x20,
45 // sets content start to current position + 1
46 SET_CONTENT_START = 0x40
49 static const struct FSM {
50 State curState;
51 int c;
52 State nextState;
53 unsigned actions;
54 } fsm[] = {
55 { p_request_line, CR, p_request_line_cr, NULLIFY },
56 { p_request_line, ANY, p_request_line, 0 },
57 { p_request_line_cr, LF, p_request_line_crlf, 0 },
58 { p_request_line_crlf, CR, p_request_line_crlfcr, 0 },
59 { p_request_line_crlf, ANY, p_key, SET_HEADER_START | SET_KEY | LOWER },
60 { p_request_line_crlfcr, LF, p_content, SET_CONTENT_START },
61 { p_key, ':', p_key_colon, NULLIFY },
62 { p_key, ANY, p_key, LOWER },
63 { p_key_colon, ' ', p_key_colon_sp, 0 },
64 { p_key_colon_sp, ANY, p_value, SET_VALUE },
65 { p_value, CR, p_value_cr, NULLIFY | STORE_KEY_VALUE },
66 { p_value, ANY, p_value, 0 },
67 { p_value_cr, LF, p_value_crlf, 0 },
68 { p_value_crlf, CR, p_value_crlfcr, 0 },
69 { p_value_crlf, ANY, p_key, SET_KEY | LOWER },
70 { p_value_crlfcr, LF, p_content, SET_CONTENT_START },
71 { p_error, ANY, p_error, 0 }
74 for( unsigned i = _parsedTo; i < _data.length(); ++i) {
75 char c = _data[i];
76 State nextState = p_error;
78 for (const FSM& f : fsm) {
79 if ( f.curState == _state &&
80 ( c == f.c || f.c == ANY ) ) {
82 nextState = f.nextState;
84 if ( f.actions & LOWER ) {
85 _data[i] = tolower( _data[i] );
88 if ( f.actions & NULLIFY ) {
89 _data[i] = 0;
92 if ( f.actions & SET_HEADER_START ) {
93 _headerStart = i;
96 if ( f.actions & SET_KEY ) {
97 _keyIndex = i;
100 if ( f.actions & SET_VALUE ) {
101 _valueIndex = i;
104 if ( f.actions & SET_CONTENT_START ) {
105 _contentStart = i + 1;
108 if ( f.actions & STORE_KEY_VALUE ) {
109 // store position of first character of key.
110 _keys.push_back( _keyIndex );
113 break;
117 _state = nextState;
119 if ( _state == p_content ) {
120 const char* str = getValue("content-length");
121 if ( str ) {
122 _contentLength = atoi( str );
124 break;
128 _parsedTo = _data.length();
132 bool
133 HttpParser::parseRequestLine()
135 size_t sp1;
136 size_t sp2;
138 sp1 = _data.find( ' ', 0 );
139 if ( sp1 == std::string::npos ) return false;
140 sp2 = _data.find( ' ', sp1 + 1 );
141 if ( sp2 == std::string::npos ) return false;
143 _data[sp1] = 0;
144 _data[sp2] = 0;
145 _uriIndex = sp1 + 1;
146 return true;
149 HttpParser::status_t
150 HttpParser::addBytes( const char* bytes, unsigned len )
152 if ( _status != Incomplete ) {
153 return _status;
156 // append the bytes to data.
157 _data.append( bytes, len );
159 if ( _state < p_content ) {
160 parseHeader();
163 if ( _state == p_error ) {
164 _status = Error;
165 } else if ( _state == p_content ) {
166 if ( _contentLength == 0 || _data.length() - _contentStart >= _contentLength ) {
167 if ( parseRequestLine() ) {
168 _status = Done;
169 } else {
170 _status = Error;
175 return _status;
178 const char*
179 HttpParser::getMethod() const
181 return &_data[0];
184 const char*
185 HttpParser::getUri() const
187 return &_data[_uriIndex];
190 const char*
191 HttpParser::getQueryString() const
193 const char* pos = getUri();
194 while( *pos ) {
195 if ( *pos == '?' ) {
196 pos++;
197 break;
199 pos++;
201 return pos;
204 const char*
205 HttpParser::getBody() const
207 if ( _contentLength > 0 ) {
208 return &_data[_contentStart];
209 } else {
210 return NULL;
214 // key should be in lower case.
215 const char*
216 HttpParser::getValue( const char* key ) const
218 for( IntArray::const_iterator iter = _keys.begin();
219 iter != _keys.end(); ++iter )
221 unsigned index = *iter;
222 if ( strcmp( &_data[index], key ) == 0 ) {
223 return &_data[index + strlen(key) + 2];
228 return NULL;
231 unsigned
232 HttpParser::getContentLength() const
234 return _contentLength;