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 WEBSOCKETPP_PROCESSOR_BASE_HPP
29 #define WEBSOCKETPP_PROCESSOR_BASE_HPP
30
31 #include <websocketpp/close.hpp>
32 #include <websocketpp/utilities.hpp>
33 #include <websocketpp/uri.hpp>
34
35 #include <websocketpp/common/cpp11.hpp>
36 #include <websocketpp/common/system_error.hpp>
37
38 #include <string>
39
40 namespace websocketpp {
41 namespace processor {
42
43 /// Constants related to processing WebSocket connections
44 namespace constants {
45
46 static char const upgrade_token[] = "websocket";
47 static char const connection_token[] = "Upgrade";
48 static char const handshake_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
49
50 } // namespace constants
51
52
53 /// Processor class related error codes
54 namespace error_cat {
55 enum value {
56 BAD_REQUEST = 0, // Error was the result of improperly formatted user input
57 INTERNAL_ERROR = 1, // Error was a logic error internal to WebSocket++
58 PROTOCOL_VIOLATION = 2,
59 MESSAGE_TOO_BIG = 3,
60 PAYLOAD_VIOLATION = 4 // Error was due to receiving invalid payload data
61 };
62 } // namespace error_cat
63
64 /// Error code category and codes used by all processor types
65 namespace error {
66 enum processor_errors {
67 /// Catch-all error for processor policy errors that don't fit in other
68 /// categories
69 general = 1,
70
71 /// Error was the result of improperly formatted user input
72 bad_request,
73
74 /// Processor encountered a protocol violation in an incoming message
75 protocol_violation,
76
77 /// Processor encountered a message that was too large
78 message_too_big,
79
80 /// Processor encountered invalid payload data.
81 invalid_payload,
82
83 /// The processor method was called with invalid arguments
84 invalid_arguments,
85
86 /// Opcode was invalid for requested operation
87 invalid_opcode,
88
89 /// Control frame too large
90 control_too_big,
91
92 /// Illegal use of reserved bit
93 invalid_rsv_bit,
94
95 /// Fragmented control message
96 fragmented_control,
97
98 /// Continuation without message
99 invalid_continuation,
100
101 /// Clients may not send unmasked frames
102 masking_required,
103
104 /// Servers may not send masked frames
105 masking_forbidden,
106
107 /// Payload length not minimally encoded
108 non_minimal_encoding,
109
110 /// Not supported on 32 bit systems
111 requires_64bit,
112
113 /// Invalid UTF-8 encoding
114 invalid_utf8,
115
116 /// Operation required not implemented functionality
117 not_implemented,
118
119 /// Invalid HTTP method
120 invalid_http_method,
121
122 /// Invalid HTTP version
123 invalid_http_version,
124
125 /// Invalid HTTP status
126 invalid_http_status,
127
128 /// Missing Required Header
129 missing_required_header,
130
131 /// Embedded SHA-1 library error
132 sha1_library,
133
134 /// No support for this feature in this protocol version.
135 no_protocol_support,
136
137 /// Reserved close code used
138 reserved_close_code,
139
140 /// Invalid close code used
141 invalid_close_code,
142
143 /// Using a reason requires a close code
144 reason_requires_code,
145
146 /// Error parsing subprotocols
147 subprotocol_parse_error,
148
149 /// Error parsing extensions
150 extension_parse_error,
151
152 /// Extension related operation was ignored because extensions are disabled
153 extensions_disabled,
154
155 /// Short Ke3 read. Hybi00 requires a third key to be read from the 8 bytes
156 /// after the handshake. Less than 8 bytes were read.
157 short_key3
158 };
159
160 /// Category for processor errors
161 class processor_category : public lib::error_category {
162 public:
processor_category()163 processor_category() {}
164
name() const165 char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
166 return "websocketpp.processor";
167 }
168
message(int value) const169 std::string message(int value) const {
170 switch(value) {
171 case error::general:
172 return "Generic processor error";
173 case error::bad_request:
174 return "invalid user input";
175 case error::protocol_violation:
176 return "Generic protocol violation";
177 case error::message_too_big:
178 return "A message was too large";
179 case error::invalid_payload:
180 return "A payload contained invalid data";
181 case error::invalid_arguments:
182 return "invalid function arguments";
183 case error::invalid_opcode:
184 return "invalid opcode";
185 case error::control_too_big:
186 return "Control messages are limited to fewer than 125 characters";
187 case error::invalid_rsv_bit:
188 return "Invalid use of reserved bits";
189 case error::fragmented_control:
190 return "Control messages cannot be fragmented";
191 case error::invalid_continuation:
192 return "Invalid message continuation";
193 case error::masking_required:
194 return "Clients may not send unmasked frames";
195 case error::masking_forbidden:
196 return "Servers may not send masked frames";
197 case error::non_minimal_encoding:
198 return "Payload length was not minimally encoded";
199 case error::requires_64bit:
200 return "64 bit frames are not supported on 32 bit systems";
201 case error::invalid_utf8:
202 return "Invalid UTF8 encoding";
203 case error::not_implemented:
204 return "Operation required not implemented functionality";
205 case error::invalid_http_method:
206 return "Invalid HTTP method.";
207 case error::invalid_http_version:
208 return "Invalid HTTP version.";
209 case error::invalid_http_status:
210 return "Invalid HTTP status.";
211 case error::missing_required_header:
212 return "A required HTTP header is missing";
213 case error::sha1_library:
214 return "SHA-1 library error";
215 case error::no_protocol_support:
216 return "The WebSocket protocol version in use does not support this feature";
217 case error::reserved_close_code:
218 return "Reserved close code used";
219 case error::invalid_close_code:
220 return "Invalid close code used";
221 case error::reason_requires_code:
222 return "Using a close reason requires a valid close code";
223 case error::subprotocol_parse_error:
224 return "Error parsing subprotocol header";
225 case error::extension_parse_error:
226 return "Error parsing extension header";
227 case error::extensions_disabled:
228 return "Extensions are disabled";
229 case error::short_key3:
230 return "Short Hybi00 Key 3 read";
231 default:
232 return "Unknown";
233 }
234 }
235 };
236
237 /// Get a reference to a static copy of the processor error category
get_processor_category()238 inline lib::error_category const & get_processor_category() {
239 static processor_category instance;
240 return instance;
241 }
242
243 /// Create an error code with the given value and the processor category
make_error_code(error::processor_errors e)244 inline lib::error_code make_error_code(error::processor_errors e) {
245 return lib::error_code(static_cast<int>(e), get_processor_category());
246 }
247
248 /// Converts a processor error_code into a websocket close code
249 /**
250 * Looks up the appropriate WebSocket close code that should be sent after an
251 * error of this sort occurred.
252 *
253 * If the error is not in the processor category close::status::blank is
254 * returned.
255 *
256 * If the error isn't normally associated with reasons to close a connection
257 * (such as errors intended to be used internally or delivered to client
258 * applications, ex: invalid arguments) then
259 * close::status::internal_endpoint_error is returned.
260 */
to_ws(lib::error_code ec)261 inline close::status::value to_ws(lib::error_code ec) {
262 if (ec.category() != get_processor_category()) {
263 return close::status::blank;
264 }
265
266 switch (ec.value()) {
267 case error::protocol_violation:
268 case error::control_too_big:
269 case error::invalid_opcode:
270 case error::invalid_rsv_bit:
271 case error::fragmented_control:
272 case error::invalid_continuation:
273 case error::masking_required:
274 case error::masking_forbidden:
275 case error::reserved_close_code:
276 case error::invalid_close_code:
277 return close::status::protocol_error;
278 case error::invalid_payload:
279 case error::invalid_utf8:
280 return close::status::invalid_payload;
281 case error::message_too_big:
282 return close::status::message_too_big;
283 default:
284 return close::status::internal_endpoint_error;
285 }
286 }
287
288 } // namespace error
289 } // namespace processor
290 } // namespace websocketpp
291
292 _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
293 template<> struct is_error_code_enum<websocketpp::processor::error::processor_errors>
294 {
295 static bool const value = true;
296 };
297 _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
298
299 #endif //WEBSOCKETPP_PROCESSOR_BASE_HPP
300