1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9 
10 #ifndef BOOST_BEAST_WEBSOCKET_RFC6455_HPP
11 #define BOOST_BEAST_WEBSOCKET_RFC6455_HPP
12 
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/core/static_string.hpp>
15 #include <boost/beast/core/string.hpp>
16 #include <boost/beast/http/empty_body.hpp>
17 #include <boost/beast/http/message.hpp>
18 #include <boost/beast/http/string_body.hpp>
19 #include <array>
20 #include <cstdint>
21 
22 namespace boost {
23 namespace beast {
24 namespace websocket {
25 
26 /// The type of object holding HTTP Upgrade requests
27 using request_type = http::request<http::empty_body>;
28 
29 /// The type of object holding HTTP Upgrade responses
30 using response_type = http::response<http::string_body>;
31 
32 /** Returns `true` if the specified HTTP request is a WebSocket Upgrade.
33 
34     This function returns `true` when the passed HTTP Request
35     indicates a WebSocket Upgrade. It does not validate the
36     contents of the fields: it just trivially accepts requests
37     which could only possibly be a valid or invalid WebSocket
38     Upgrade message.
39 
40     Callers who wish to manually read HTTP requests in their
41     server implementation can use this function to determine if
42     the request should be routed to an instance of
43     @ref websocket::stream.
44 
45     @par Example
46     @code
47     void handle_connection(net::ip::tcp::socket& sock)
48     {
49         boost::beast::flat_buffer buffer;
50         boost::beast::http::request<boost::beast::http::string_body> req;
51         boost::beast::http::read(sock, buffer, req);
52         if(boost::beast::websocket::is_upgrade(req))
53         {
54             boost::beast::websocket::stream<decltype(sock)> ws{std::move(sock)};
55             ws.accept(req);
56         }
57     }
58     @endcode
59 
60     @param req The HTTP Request object to check.
61 
62     @return `true` if the request is a WebSocket Upgrade.
63 */
64 template<class Allocator>
65 bool
66 is_upgrade(beast::http::header<true,
67     http::basic_fields<Allocator>> const& req);
68 
69 /** Close status codes.
70 
71     These codes accompany close frames.
72 
73     @see <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455 7.4.1 Defined Status Codes</a>
74 */
75 enum close_code : std::uint16_t
76 {
77     /// Normal closure; the connection successfully completed whatever purpose for which it was created.
78     normal          = 1000,
79 
80     /// The endpoint is going away, either because of a server failure or because the browser is navigating away from the page that opened the connection.
81     going_away      = 1001,
82 
83     /// The endpoint is terminating the connection due to a protocol error.
84     protocol_error  = 1002,
85 
86     /// The connection is being terminated because the endpoint received data of a type it cannot accept (for example, a text-only endpoint received binary data).
87     unknown_data    = 1003,
88 
89     /// The endpoint is terminating the connection because a message was received that contained inconsistent data (e.g., non-UTF-8 data within a text message).
90     bad_payload     = 1007,
91 
92     /// The endpoint is terminating the connection because it received a message that violates its policy. This is a generic status code, used when codes 1003 and 1009 are not suitable.
93     policy_error    = 1008,
94 
95     /// The endpoint is terminating the connection because a data frame was received that is too large.
96     too_big         = 1009,
97 
98     /// The client is terminating the connection because it expected the server to negotiate one or more extension, but the server didn't.
99     needs_extension = 1010,
100 
101     /// The server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.
102     internal_error  = 1011,
103 
104     /// The server is terminating the connection because it is restarting.
105     service_restart = 1012,
106 
107     /// The server is terminating the connection due to a temporary condition, e.g. it is overloaded and is casting off some of its clients.
108     try_again_later = 1013,
109 
110     //----
111     //
112     // The following are illegal on the wire
113     //
114 
115     /** Used internally to mean "no error"
116 
117         This code is reserved and may not be sent.
118     */
119     none            = 0,
120 
121     /** Reserved for future use by the WebSocket standard.
122 
123         This code is reserved and may not be sent.
124     */
125     reserved1       = 1004,
126 
127     /** No status code was provided even though one was expected.
128 
129         This code is reserved and may not be sent.
130     */
131     no_status       = 1005,
132 
133     /** Connection was closed without receiving a close frame
134 
135         This code is reserved and may not be sent.
136     */
137     abnormal        = 1006,
138 
139     /** Reserved for future use by the WebSocket standard.
140 
141         This code is reserved and may not be sent.
142     */
143     reserved2       = 1014,
144 
145     /** Reserved for future use by the WebSocket standard.
146 
147         This code is reserved and may not be sent.
148     */
149     reserved3       = 1015
150 
151     //
152     //----
153 
154     //last = 5000 // satisfy warnings
155 };
156 
157 /// The type representing the reason string in a close frame.
158 using reason_string = static_string<123, char>;
159 
160 /// The type representing the payload of ping and pong messages.
161 using ping_data = static_string<125, char>;
162 
163 /** Description of the close reason.
164 
165     This object stores the close code (if any) and the optional
166     utf-8 encoded implementation defined reason string.
167 */
168 struct close_reason
169 {
170     /// The close code.
171     std::uint16_t code = close_code::none;
172 
173     /// The optional utf8-encoded reason string.
174     reason_string reason;
175 
176     /** Default constructor.
177 
178         The code will be none. Default constructed objects
179         will explicitly convert to bool as `false`.
180     */
181     close_reason() = default;
182 
183     /// Construct from a code.
close_reasonboost::beast::websocket::close_reason184     close_reason(std::uint16_t code_)
185         : code(code_)
186     {
187     }
188 
189     /// Construct from a reason string. code is @ref close_code::normal.
close_reasonboost::beast::websocket::close_reason190     close_reason(string_view s)
191         : code(close_code::normal)
192         , reason(s)
193     {
194     }
195 
196     /// Construct from a reason string literal. code is @ref close_code::normal.
close_reasonboost::beast::websocket::close_reason197     close_reason(char const* s)
198         : code(close_code::normal)
199         , reason(s)
200     {
201     }
202 
203     /// Construct from a close code and reason string.
close_reasonboost::beast::websocket::close_reason204     close_reason(close_code code_, string_view s)
205         : code(code_)
206         , reason(s)
207     {
208     }
209 
210     /// Returns `true` if a code was specified
operator boolboost::beast::websocket::close_reason211     operator bool() const
212     {
213         return code != close_code::none;
214     }
215 };
216 
217 } // websocket
218 } // beast
219 } // boost
220 
221 #include <boost/beast/websocket/impl/rfc6455.hpp>
222 
223 #endif
224