From: Andy Green Date: Sun, 6 Mar 2011 10:29:35 +0000 (+0000) Subject: create server extension response dynamically X-Git-Tag: 1.2~145 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c511482c78a2b9722ca6280cfe4b55f9d09ab1d2;p=profile%2Fivi%2Flibwebsockets.git create server extension response dynamically This goes through the extentsions the client requested, selects the ones that we support at the server, and then further calls back to the appropriate protocol callback in user code to check it's OK to actually use that extension in this context. If it is (callback unhandled == it is) then it's added to the list of extensions sent back to the client. Accepted extensions are also added to the connection's active extension list and the private "user" memory allocation for the extension context is done and bound to the connection. Signed-off-by: Andy Green --- diff --git a/lib/handshake.c b/lib/handshake.c index c3e9ed5..51cd558 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -239,6 +239,11 @@ handshake_0405(struct libwebsocket *wsi) char *m = mask_summing_buf; int nonce_len = 0; int accept_len; + char *c; + char ext_name[128]; + struct libwebsocket_extension * ext; + int ext_count = 0; + int more = 1; if (!wsi->utf8_token[WSI_TOKEN_HOST].token_len || !wsi->utf8_token[WSI_TOKEN_KEY].token_len) { @@ -352,6 +357,103 @@ handshake_0405(struct libwebsocket *wsi) p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len; } + /* + * Figure out which extensions the client has that we want to + * enable on this connection, and give him back the list + */ + + if (wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) { + strcpy(p, "\x0d\x0aSec-WebSocket-Extensions: "); + p += strlen("\x0d\x0aSec-WebSocket-Extensions: "); + + /* + * break down the list of client extensions + * and go through them + */ + + c = wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token; + n = 0; + while (more) { + + if (*c && *c != ',') { + ext_name[n] = *c++; + if (n < sizeof(ext_name) - 1) + n++; + continue; + } + ext_name[n] = '\0'; + if (!*c) + more = 0; + + /* check a client's extension against our support */ + + ext = wsi->protocol->owning_server->extensions; + + while (ext && ext->callback) { + + if (strcmp(ext_name, ext->name)) { + ext++; + continue; + } + + /* + * oh, we do support this one he + * asked for... but let's ask user + * code if it's OK to apply it on this + * particular connection + protocol + */ + + n = wsi->protocol->owning_server-> + protocols[0].callback( + wsi->protocol->owning_server, + wsi, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + wsi->user_space, ext_name, 0); + + /* + * zero return from callback means + * go ahead and allow the extension, + * it's what we get if the callback is + * unhandled + */ + + if (n) { + ext++; + continue; + } + + /* apply it */ + + if (ext_count) + *p++ = ','; + p += sprintf(p, ext_name); + ext_count++; + + /* instantiate the extension on this conn */ + + wsi->active_extensions_user[ + wsi->count_active_extensions] = + malloc(ext->per_session_data_size); + wsi->active_extensions[ + wsi->count_active_extensions] = ext; + + /* allow him to construct his context */ + + ext->callback(wsi->protocol->owning_server, + wsi, LWS_EXT_CALLBACK_CONSTRUCT, + wsi->active_extensions_user[ + wsi->count_active_extensions], NULL, 0); + + wsi->count_active_extensions++; + + ext++; + } + + n = 0; + } + } + + /* end of response packet */ strcpy(p, "\x0d\x0a\x0d\x0a"); diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index c59bbdd..39c537f 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -1733,6 +1733,8 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) * specific callback for each one. The list is ended with an * entry that has a NULL callback pointer. * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want * to listen using SSL, set to the filepath to fetch the * server cert from, otherwise NULL for unencrypted diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 5402ee1..eded025 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -63,6 +63,7 @@ enum libwebsocket_callback_reasons { LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, /* external poll() management support */ LWS_CALLBACK_ADD_POLL_FD, LWS_CALLBACK_DEL_POLL_FD, @@ -70,6 +71,11 @@ enum libwebsocket_callback_reasons { LWS_CALLBACK_CLEAR_MODE_POLL_FD, }; +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_DESTROY, +}; + enum libwebsocket_write_protocol { LWS_WRITE_TEXT, LWS_WRITE_BINARY, @@ -315,6 +321,17 @@ struct libwebsocket_context; * Notice the callback is coming to protocols[0] all the time, * because there is no specific protocol handshook yet. * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * * The next four reasons are optional and only need taking care of if you * will be integrating libwebsockets sockets into an external polling * array. @@ -415,8 +432,8 @@ struct libwebsocket_extension { const char *name; int (*callback)(struct libwebsocket_context *context, struct libwebsocket *wsi, - enum libwebsocket_callback_reasons reason, void *user, - void *in, size_t len); + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); size_t per_session_data_size; }; diff --git a/libwebsockets-api-doc.html b/libwebsockets-api-doc.html index 239f393..0a039e9 100644 --- a/libwebsockets-api-doc.html +++ b/libwebsockets-api-doc.html @@ -241,6 +241,9 @@ interface name, eg, "eth2" specific callback for each one. The list is ended with an entry that has a NULL callback pointer. It's not const because we write the owning_server member +
extensions +
NULL or array of libwebsocket_extension structs listing the +extensions this context supports
ssl_cert_filepath
If libwebsockets was compiled to use ssl, and you want to listen using SSL, set to the filepath to fetch the @@ -648,6 +651,19 @@ optional, if you don't handle it everything is fine.

Notice the callback is coming to protocols[0] all the time, because there is no specific protocol handshook yet. + +

LWS_CALLBACK_CONFIRM_EXTENSION_OKAY

+
+When the server handshake code +sees that it does support a requested extension, before +accepting the extension by additing to the list sent back to +the client it gives this callback just to check that it's okay +to use that extension. It calls back to the requested protocol +and with in being the extension name, len is 0 and user is +valid. Note though at this time the ESTABLISHED callback hasn't +happened yet so if you initialize user content there, user +content during this callback might not be useful for anything. +Notice this callback comes to protocols[0].

The next four reasons are optional and only need taking care of if you will be integrating libwebsockets sockets into an external polling