Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
request.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_REQUEST_IMPL_HPP
29#define HTTP_PARSER_REQUEST_IMPL_HPP
30
31#include <algorithm>
32#include <sstream>
33#include <string>
34
36
37namespace websocketpp {
38namespace http {
39namespace parser {
40
41inline size_t request::consume(char const * buf, size_t len) {
42 size_t bytes_processed;
43
44 if (m_ready) {return 0;}
45
46 if (m_body_bytes_needed > 0) {
47 bytes_processed = process_body(buf,len);
48 if (body_ready()) {
49 m_ready = true;
50 }
51 return bytes_processed;
52 }
53
54 // copy new header bytes into buffer
55 m_buf->append(buf,len);
56
57 // Search for delimiter in buf. If found read until then. If not read all
58 std::string::iterator begin = m_buf->begin();
59 std::string::iterator end;
60
61 for (;;) {
62 // search for line delimiter
63 end = std::search(
64 begin,
65 m_buf->end(),
66 header_delimiter,
67 header_delimiter+sizeof(header_delimiter)-1
68 );
69
70 m_header_bytes += (end-begin+sizeof(header_delimiter));
71
73 // exceeded max header size
74 throw exception("Maximum header size exceeded.",
76 }
77
78 if (end == m_buf->end()) {
79 // we are out of bytes. Discard the processed bytes and copy the
80 // remaining unprecessed bytes to the beginning of the buffer
81 std::copy(begin,end,m_buf->begin());
82 m_buf->resize(static_cast<std::string::size_type>(end-begin));
83 m_header_bytes -= m_buf->size();
84
85 return len;
86 }
87
88 //the range [begin,end) now represents a line to be processed.
89 if (end-begin == 0) {
90 // we got a blank line
91 if (m_method.empty() || get_header("Host").empty()) {
92 throw exception("Incomplete Request",status_code::bad_request);
93 }
94
95 bytes_processed = (
96 len - static_cast<std::string::size_type>(m_buf->end()-end)
97 + sizeof(header_delimiter) - 1
98 );
99
100 // frees memory used temporarily during request parsing
101 m_buf.reset();
102
103 // if this was not an upgrade request and has a content length
104 // continue capturing content-length bytes and expose them as a
105 // request body.
106
107 if (prepare_body()) {
108 bytes_processed += process_body(buf+bytes_processed,len-bytes_processed);
109 if (body_ready()) {
110 m_ready = true;
111 }
112 return bytes_processed;
113 } else {
114 m_ready = true;
115
116 // return number of bytes processed (starting bytes - bytes left)
117 return bytes_processed;
118 }
119 } else {
120 if (m_method.empty()) {
121 this->process(begin,end);
122 } else {
123 this->process_header(begin,end);
124 }
125 }
126
127 begin = end+(sizeof(header_delimiter)-1);
128 }
129}
130
131inline std::string request::raw() const {
132 // TODO: validation. Make sure all required fields have been set?
133 std::stringstream ret;
134
135 ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
136 ret << raw_headers() << "\r\n" << m_body;
137
138 return ret.str();
139}
140
141inline std::string request::raw_head() const {
142 // TODO: validation. Make sure all required fields have been set?
143 std::stringstream ret;
144
145 ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
146 ret << raw_headers() << "\r\n";
147
148 return ret.str();
149}
150
151inline void request::set_method(std::string const & method) {
152 if (std::find_if(method.begin(),method.end(),is_not_token_char) != method.end()) {
153 throw exception("Invalid method token.",status_code::bad_request);
154 }
155
156 m_method = method;
157}
158
159inline void request::set_uri(std::string const & uri) {
160 // TODO: validation?
161 m_uri = uri;
162}
163
164inline void request::process(std::string::iterator begin, std::string::iterator
165 end)
166{
167 std::string::iterator cursor_start = begin;
168 std::string::iterator cursor_end = std::find(begin,end,' ');
169
170 if (cursor_end == end) {
171 throw exception("Invalid request line1",status_code::bad_request);
172 }
173
174 set_method(std::string(cursor_start,cursor_end));
175
176 cursor_start = cursor_end+1;
177 cursor_end = std::find(cursor_start,end,' ');
178
179 if (cursor_end == end) {
180 throw exception("Invalid request line2",status_code::bad_request);
181 }
182
183 set_uri(std::string(cursor_start,cursor_end));
184 set_version(std::string(cursor_end+1,end));
185}
186
187} // namespace parser
188} // namespace http
189} // namespace websocketpp
190
191#endif // HTTP_PARSER_REQUEST_IMPL_HPP
size_t process_body(char const *buf, size_t len)
Process body data.
Definition parser.hpp:145
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
bool body_ready() const
Check if the parser is done parsing the body.
Definition parser.hpp:589
bool prepare_body()
Prepare the parser to begin parsing body data.
Definition parser.hpp:119
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
std::string raw() const
Returns the full raw request (including the body)
Definition request.hpp:131
size_t consume(char const *buf, size_t len)
Process bytes in the input buffer.
Definition request.hpp:41
void set_uri(std::string const &uri)
Set the HTTP uri. Must be a valid HTTP uri.
Definition request.hpp:159
void set_method(std::string const &method)
Set the HTTP method. Must be a valid HTTP token.
Definition request.hpp:151
std::string raw_head() const
Returns the raw request headers only (similar to an HTTP HEAD request)
Definition request.hpp:141
bool is_not_token_char(unsigned char c)
Is the character a non-token.
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
size_t len
uint8_t buf[2048]