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