66#include <aws/cal/hash.h>
77#include <aws/common/encoding.h>
88#include <aws/common/logging.h>
9+ #include <aws/common/string.h>
910#include <aws/http/connection.h>
1011#include <aws/http/private/http_impl.h>
1112#include <aws/http/private/strutil.h>
@@ -73,6 +74,9 @@ struct aws_websocket_client_bootstrap {
7374 * this is what we expect the response's "Sec-WebSocket-Accept" to be */
7475 struct aws_byte_buf expected_sec_websocket_accept ;
7576
77+ /* Values from the request's "Sec-WebSocket-Protocol" values (or NULL if none) */
78+ struct aws_string * expected_sec_websocket_protocol ;
79+
7680 /* Handshake response data */
7781 int response_status ;
7882 struct aws_http_headers * response_headers ;
@@ -152,6 +156,16 @@ int aws_websocket_client_connect(const struct aws_websocket_client_connection_op
152156 return aws_raise_error (AWS_ERROR_INVALID_ARGUMENT );
153157 }
154158
159+ /* Extensions are not currently supported */
160+ struct aws_string * sec_websocket_extensions =
161+ aws_http_headers_get_comma_separated (request_headers , aws_byte_cursor_from_c_str ("Sec-WebSocket-Extensions" ));
162+ if (sec_websocket_extensions != NULL ) {
163+ aws_string_destroy (sec_websocket_extensions );
164+ AWS_LOGF_ERROR (
165+ AWS_LS_HTTP_WEBSOCKET_SETUP , "id=static: 'Sec-WebSocket-Extensions' are not currently supported" );
166+ return aws_raise_error (AWS_ERROR_INVALID_ARGUMENT );
167+ }
168+
155169 /* Create bootstrap */
156170 struct aws_websocket_client_bootstrap * ws_bootstrap =
157171 aws_mem_calloc (options -> allocator , 1 , sizeof (struct aws_websocket_client_bootstrap ));
@@ -175,6 +189,9 @@ int aws_websocket_client_connect(const struct aws_websocket_client_connection_op
175189 goto error ;
176190 }
177191
192+ ws_bootstrap -> expected_sec_websocket_protocol = aws_http_headers_get_comma_separated (
193+ options -> handshake_request , aws_byte_cursor_from_c_str ("Sec-WebSocket-Protocol" ));
194+
178195 /* Initiate HTTP connection */
179196 struct aws_http_client_connection_options http_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT ;
180197 http_options .allocator = ws_bootstrap -> alloc ;
@@ -241,6 +258,7 @@ static void s_ws_bootstrap_destroy(struct aws_websocket_client_bootstrap *ws_boo
241258 aws_http_message_release (ws_bootstrap -> handshake_request );
242259 aws_http_headers_release (ws_bootstrap -> response_headers );
243260 aws_byte_buf_clean_up (& ws_bootstrap -> expected_sec_websocket_accept );
261+ aws_string_destroy (ws_bootstrap -> expected_sec_websocket_protocol );
244262 aws_byte_buf_clean_up (& ws_bootstrap -> response_body );
245263
246264 aws_mem_release (ws_bootstrap -> alloc , ws_bootstrap );
@@ -582,6 +600,38 @@ static int s_ws_bootstrap_validate_header(
582600 return AWS_OP_SUCCESS ;
583601}
584602
603+ static int s_ws_bootstrap_validate_sec_websocket_protocol (const struct aws_websocket_client_bootstrap * ws_bootstrap ) {
604+
605+ /* First handle the easy case:
606+ * If client requested no protocols, then the response should not pick any */
607+ if (ws_bootstrap -> expected_sec_websocket_protocol == NULL ) {
608+ if (aws_http_headers_has (
609+ ws_bootstrap -> response_headers , aws_byte_cursor_from_c_str ("Sec-WebSocket-Protocol" ))) {
610+
611+ AWS_LOGF_ERROR (
612+ AWS_LS_HTTP_WEBSOCKET_SETUP ,
613+ "id=%p: Response has 'Sec-WebSocket-Protocol' header, no protocol was requested" ,
614+ (void * )ws_bootstrap );
615+ return aws_raise_error (AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE );
616+ } else {
617+ return AWS_OP_SUCCESS ;
618+ }
619+ }
620+
621+ /* Check that server has picked one of the requested protocols */
622+ struct aws_byte_cursor response_protocol ;
623+ if (aws_http_headers_get_single (
624+ ws_bootstrap -> response_headers , aws_byte_cursor_from_c_str ("Sec-WebSocket-Protocol" ), & response_protocol )) {
625+ AWS_LOGF_ERROR (
626+ AWS_LS_HTTP_WEBSOCKET_SETUP ,
627+ "id=%p: Response lacks required 'Sec-WebSocket-Protocol' header" ,
628+ (void * )ws_bootstrap );
629+ return aws_raise_error (AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE );
630+ }
631+
632+ YOU ARE HERE
633+ }
634+
585635/* OK, we've got all the headers for the 101 Switching Protocols response.
586636 * Validate the handshake response, install the websocket handler into the channel,
587637 * and invoke the on_connection_setup callback. */
@@ -627,9 +677,66 @@ static int s_ws_bootstrap_validate_response_and_install_websocket_handler(
627677 goto error ;
628678 }
629679
630- /* TODO: validate Sec-WebSocket-Extensions */
680+ /* (step 5 is about validating Sec-WebSocket-Extensions, but we don't support extensions) */
681+ struct aws_string * sec_websocket_extensions = aws_http_headers_get_comma_separated (
682+ ws_bootstrap -> response_headers , aws_byte_cursor_from_c_str ("Sec-WebSocket-Extensions" ));
683+ if (sec_websocket_extensions != NULL ) {
684+ aws_string_destroy (sec_websocket_extensions );
685+ AWS_LOGF_ERROR (
686+ AWS_LS_HTTP_WEBSOCKET_SETUP ,
687+ "id=%p: Response has 'Sec-WebSocket-Extensions' header, but client does not support extensions." ,
688+ (void * )ws_bootstrap );
689+ aws_raise_error (AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE );
690+ goto error ;
691+ }
692+
693+ /* 6. If the response includes a |Sec-WebSocket-Protocol| header field
694+ * and this header field indicates the use of a subprotocol that was
695+ * not present in the client's handshake (the server has indicated a
696+ * subprotocol not requested by the client), the client MUST _Fail
697+ * the WebSocket Connection_. */
698+ if (ws_bootstrap -> sec_websocket_protocol_values ) {
699+ struct aws_byte_cursor response_protocol ;
700+ if (aws_http_headers_get_single (
701+ ws_bootstrap -> response_headers ,
702+ aws_byte_cursor_from_c_str ("Sec-WebSocket-Protocol" ),
703+ & response_protocol )) {
704+
705+ AWS_LOGF_ERROR (
706+ AWS_LS_HTTP_WEBSOCKET_SETUP ,
707+ "id=%p: Response lacks required'Sec-WebSocket-Protocol' header" ,
708+ (void * )ws_bootstrap );
709+ aws_raise_error (AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE );
710+ goto error ;
711+ }
712+
713+ } else {
714+ if (aws_http_headers_has (ws_bootstrap -> response_headers , aws_byte_cursor_from_c_str ("Sec-WebSocket-Protocol" )) {
715+ AWS_LOGF_ERROR (
716+ AWS_LS_HTTP_WEBSOCKET_SETUP ,
717+ "id=%p: Response has 'Sec-WebSocket-Protocol' header, no protocol was requested" ,
718+ (void * )ws_bootstrap );
719+ aws_raise_error (AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE );
720+ goto error ;
721+ }
722+ }
723+ struct aws_byte_cursor response_protocol ;
724+ if (aws_http_headers_get_single (
725+ ws_bootstrap -> response_headers , aws_byte_cursor_from_c_str ("Sec-WebSocket-Protocol" ), & response_protocol ) ==
726+ AWS_OP_SUCCESS ) {
631727
632- /* TODO: validate Sec-WebSocket-Protocol */
728+ if (ws_bootstrap -> sec_websocket_protocol_values == NULL ) {
729+ AWS_LOGF_ERROR (
730+ AWS_LS_HTTP_WEBSOCKET_SETUP ,
731+ "id=%p: Response has 'Sec-WebSocket-Protocol' header, no protocol was requested" ,
732+ (void * )ws_bootstrap );
733+ aws_raise_error (AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE );
734+ goto error ;
735+ }
736+ }
737+ if (s_ws_bootstrap_validate_sec_websocket_protocol (ws_bootstrap )) {
738+ goto error ;
739+ }
633740
634741 /* Insert websocket handler into channel */
635742 struct aws_channel * channel = s_system_vtable -> aws_http_connection_get_channel (http_connection );
0 commit comments