Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
response.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014, Peter Thorson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of the WebSocket++ Project nor the
12 * names of its contributors may be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28#ifndef HTTP_PARSER_RESPONSE_IMPL_HPP
29#define HTTP_PARSER_RESPONSE_IMPL_HPP
30
31#include <algorithm>
32#include <istream>
33#include <sstream>
34#include <string>
35
37
38namespace websocketpp {
39namespace http {
40namespace parser {
41
42inline size_t response::consume(char const * buf, size_t len) {
43 if (m_state == DONE) {return 0;}
44
45 if (m_state == BODY) {
46 return this->process_body(buf,len);
47 }
48
49 // copy new header bytes into buffer
50 m_buf->append(buf,len);
51
52 // Search for delimiter in buf. If found read until then. If not read all
53 std::string::iterator begin = m_buf->begin();
54 std::string::iterator end = begin;
55
56
57 for (;;) {
58 // search for delimiter
59 end = std::search(
60 begin,
61 m_buf->end(),
62 header_delimiter,
63 header_delimiter + sizeof(header_delimiter) - 1
64 );
65
66 m_header_bytes += (end-begin+sizeof(header_delimiter));
67
69 // exceeded max header size
70 throw exception("Maximum header size exceeded.",
72 }
73
74 if (end == m_buf->end()) {
75 // we are out of bytes. Discard the processed bytes and copy the
76 // remaining unprecessed bytes to the beginning of the buffer
77 std::copy(begin,end,m_buf->begin());
78 m_buf->resize(static_cast<std::string::size_type>(end-begin));
79
80 m_read += len;
81 m_header_bytes -= m_buf->size();
82
83 return len;
84 }
85
86 //the range [begin,end) now represents a line to be processed.
87
88 if (end-begin == 0) {
89 // we got a blank line
90 if (m_state == RESPONSE_LINE) {
91 throw exception("Incomplete Request",status_code::bad_request);
92 }
93
94 // TODO: grab content-length
95 std::string length = get_header("Content-Length");
96
97 if (length.empty()) {
98 // no content length found, read indefinitely
99 m_read = 0;
100 } else {
101 std::istringstream ss(length);
102
103 if ((ss >> m_read).fail()) {
104 throw exception("Unable to parse Content-Length header",
106 }
107 }
108
109 m_state = BODY;
110
111 // calc header bytes processed (starting bytes - bytes left)
112 size_t read = (
113 len - static_cast<std::string::size_type>(m_buf->end() - end)
114 + sizeof(header_delimiter) - 1
115 );
116
117 // if there were bytes left process them as body bytes
118 if (read < len) {
119 read += this->process_body(buf+read,(len-read));
120 }
121
122 // frees memory used temporarily during header parsing
123 m_buf.reset();
124
125 return read;
126 } else {
127 if (m_state == RESPONSE_LINE) {
128 this->process(begin,end);
129 m_state = HEADERS;
130 } else {
131 this->process_header(begin,end);
132 }
133 }
134
135 begin = end+(sizeof(header_delimiter) - 1);
136 }
137}
138
139inline size_t response::consume(std::istream & s) {
140 char buf[istream_buffer];
141 size_t bytes_read;
142 size_t bytes_processed;
143 size_t total = 0;
144
145 while (s.good()) {
146 s.getline(buf,istream_buffer);
147 bytes_read = static_cast<size_t>(s.gcount());
148
149 if (s.fail() || s.eof()) {
150 bytes_processed = this->consume(buf,bytes_read);
151 total += bytes_processed;
152
153 if (bytes_processed != bytes_read) {
154 // problem
155 break;
156 }
157 } else if (s.bad()) {
158 // problem
159 break;
160 } else {
161 // the delimiting newline was found. Replace the trailing null with
162 // the newline that was discarded, since our raw consume function
163 // expects the newline to be be there.
164 buf[bytes_read-1] = '\n';
165 bytes_processed = this->consume(buf,bytes_read);
166 total += bytes_processed;
167
168 if (bytes_processed != bytes_read) {
169 // problem
170 break;
171 }
172 }
173 }
174
175 return total;
176}
177
178inline std::string response::raw() const {
179 // TODO: validation. Make sure all required fields have been set?
180
181 std::stringstream ret;
182
183 ret << get_version() << " " << m_status_code << " " << m_status_msg;
184 ret << "\r\n" << raw_headers() << "\r\n";
185
186 ret << m_body;
187
188 return ret.str();
189}
190
192 // TODO: validation?
193 m_status_code = code;
194 m_status_msg = get_string(code);
195}
196
197inline void response::set_status(status_code::value code, std::string const &
198 msg)
199{
200 // TODO: validation?
201 m_status_code = code;
202 m_status_msg = msg;
203}
204
205inline void response::process(std::string::iterator begin,
206 std::string::iterator end)
207{
208 std::string::iterator cursor_start = begin;
209 std::string::iterator cursor_end = std::find(begin,end,' ');
210
211 if (cursor_end == end) {
212 throw exception("Invalid response line",status_code::bad_request);
213 }
214
215 set_version(std::string(cursor_start,cursor_end));
216
217 cursor_start = cursor_end+1;
218 cursor_end = std::find(cursor_start,end,' ');
219
220 if (cursor_end == end) {
221 throw exception("Invalid request line",status_code::bad_request);
222 }
223
224 int code;
225
226 std::istringstream ss(std::string(cursor_start,cursor_end));
227
228 if ((ss >> code).fail()) {
229 throw exception("Unable to parse response code",status_code::bad_request);
230 }
231
232 set_status(status_code::value(code),std::string(cursor_end+1,end));
233}
234
235inline size_t response::process_body(char const * buf, size_t len) {
236 // If no content length was set then we read forever and never set m_ready
237 if (m_read == 0) {
238 //m_body.append(buf,len);
239 //return len;
240 m_state = DONE;
241 return 0;
242 }
243
244 // Otherwise m_read is the number of bytes left.
245 size_t to_read;
246
247 if (len >= m_read) {
248 // if we have more bytes than we need read, read only the amount needed
249 // then set done state
250 to_read = m_read;
251 m_state = DONE;
252 } else {
253 // we need more bytes than are available, read them all
254 to_read = len;
255 }
256
257 m_body.append(buf,to_read);
258 m_read -= to_read;
259 return to_read;
260}
261
262} // namespace parser
263} // namespace http
264} // namespace websocketpp
265
266#endif // HTTP_PARSER_RESPONSE_IMPL_HPP
void process_header(std::string::iterator begin, std::string::iterator end)
Process a header line.
Definition parser.hpp:161
void set_version(std::string const &version)
Set HTTP parser Version.
Definition parser.hpp:41
std::string raw_headers() const
Generate and return the HTTP headers as a string.
Definition parser.hpp:179
std::string const & get_header(std::string const &key) const
Get the value of an HTTP header.
Definition parser.hpp:45
std::string const & get_version() const
Get the HTTP version string.
Definition parser.hpp:410
void set_status(status_code::value code)
Set response status code and message.
Definition response.hpp:191
std::string raw() const
Returns the full raw response.
Definition response.hpp:178
size_t consume(char const *buf, size_t len)
Process bytes in the input buffer.
Definition response.hpp:42
size_t const istream_buffer
Number of bytes to use for temporary istream read buffers.
Definition constants.hpp:71
size_t const max_header_size
Maximum size in bytes before rejecting an HTTP header as too big.
Definition constants.hpp:65
Namespace for the WebSocket++ project.
Definition base64.hpp:41
CK_RV ret
char * s
size_t len
uint8_t buf[2048]