From 529d96dc6085c5ce3bbe71b05e2e080fbf35dd68 Mon Sep 17 00:00:00 2001 From: Michael Haberler Date: Sun, 10 Aug 2014 12:30:01 +0200 Subject: [PATCH] protocol selection: enable FILTER_PROTOCOL_CONNECTION to choose and set a protocol So far agreeable protocol names were limited to what struct libwebsocket_protocols had to offer. With the wildcard matching of protocol name in an earlier commit, FILTER_PROTOCOL_CONNECTION can now inspect and parse the WSI_TOKEN_PROTOCOL header, and explicitly set a protocol by calling libwebsocket_set_protocol(wsi, name, ) The Sec-WebSocket-Protocol: reply will contain only the default or matched protocol name as selected in FILTER_PROTOCOL_CONNECTION. The current protocol name can be accessed via const char *libwebsockets_get_protocol_name(struct libwebsocket *wsi). A LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION callback would do roughly this: lws_hdr_copy(wsi, protocols, sizeof protocols, WSI_TOKEN_PROTOCOL); ..inspect protocols and choose a proto name and struct libwebsocket_protocols: ..call libwebsocket_set_protocol(wsi,name, ); Also deals with issue #147 (incorrect Sec-WebSocket-Protocol: reply). --- lib/libwebsockets.c | 8 ++++++++ lib/libwebsockets.h | 8 ++++++++ lib/private-libwebsockets.h | 1 + lib/server-handshake.c | 9 +++++---- lib/server.c | 11 +++++++++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index ee88e2e1b..8ef87c1bb 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -669,6 +669,14 @@ libwebsockets_get_protocol(struct libwebsocket *wsi) return wsi->protocol; } +LWS_VISIBLE const char * +libwebsockets_get_protocol_name(struct libwebsocket *wsi) +{ + if (wsi->selected_protocol) + return wsi->selected_protocol; + return wsi->protocol->name; +} + LWS_VISIBLE int libwebsocket_is_final_fragment(struct libwebsocket *wsi) { diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 203c54e1c..3bc7be2b1 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -1036,6 +1036,11 @@ LWS_VISIBLE LWS_EXTERN void libwebsocket_set_timeout(struct libwebsocket *wsi, enum pending_timeout reason, int secs); +LWS_VISIBLE LWS_EXTERN void +libwebsocket_set_protocol(struct libwebsocket *wsi, + char *protocol_name, + struct libwebsocket_protocols *proto); + /* * IMPORTANT NOTICE! * @@ -1095,6 +1100,9 @@ LWS_VISIBLE LWS_EXTERN int libwebsockets_return_http_status( LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * libwebsockets_get_protocol(struct libwebsocket *wsi); +LWS_VISIBLE LWS_EXTERN const char * +libwebsockets_get_protocol_name(struct libwebsocket *wsi); + LWS_VISIBLE LWS_EXTERN int libwebsocket_callback_on_writable(struct libwebsocket_context *context, struct libwebsocket *wsi); diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 4194498ec..7e27fbc22 100755 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -576,6 +576,7 @@ struct libwebsocket { struct lws_io_watcher w_write; #endif /* LWS_USE_LIBEV */ const struct libwebsocket_protocols *protocol; + char *selected_protocol; #ifndef LWS_NO_EXTENSIONS struct libwebsocket_extension * active_extensions[LWS_MAX_EXTENSIONS_ACTIVE]; diff --git a/lib/server-handshake.c b/lib/server-handshake.c index 56cf9a13e..200187f46 100644 --- a/lib/server-handshake.c +++ b/lib/server-handshake.c @@ -217,10 +217,11 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) { LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: "); - n = lws_hdr_copy(wsi, p, 128, WSI_TOKEN_PROTOCOL); - if (n < 0) - goto bail; - p += n; + const char *proto = wsi->selected_protocol ? wsi->selected_protocol : + wsi->protocol->name; + lwsl_debug("replying with selected proto='%s'\n", proto); + strcpy(p, proto); + p += strlen(proto); } #ifndef LWS_NO_EXTENSIONS diff --git a/lib/server.c b/lib/server.c index 5b0b23de2..cc2a3a362 100644 --- a/lib/server.c +++ b/lib/server.c @@ -950,3 +950,14 @@ lws_server_get_canonical_hostname(struct libwebsocket_context *context, lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname); } + +LWS_VISIBLE void +libwebsocket_set_protocol(struct libwebsocket *wsi, + char *protocol_name, + struct libwebsocket_protocols *proto) +{ + wsi->selected_protocol = protocol_name; + if (proto) + wsi->protocol = proto; +} +