On Feb 3, 2014, at 11:11 AM, bri...@apache.org wrote: > Updated Branches: > refs/heads/master f0f9cb9c3 -> 60ec95053 > > > [TS-2541] Add WebSocket Support
Nice; were you planning to update the docs? > > > Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo > Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/cca82f1b > Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/cca82f1b > Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/cca82f1b > > Branch: refs/heads/master > Commit: cca82f1b910dfea6903e05602b06df53e4979b9b > Parents: 70f8e10 > Author: Brian Geffon <bri...@apache.org> > Authored: Mon Feb 3 11:10:44 2014 -0800 > Committer: Brian Geffon <bri...@apache.org> > Committed: Mon Feb 3 11:10:44 2014 -0800 > > ---------------------------------------------------------------------- > CHANGES | 2 + > proxy/config/remap.config.default | 8 + > proxy/hdrs/HdrToken.cc | 18 +++ > proxy/hdrs/HdrToken.h | 8 +- > proxy/hdrs/MIME.cc | 20 ++- > proxy/hdrs/MIME.h | 8 + > proxy/hdrs/URL.cc | 14 ++ > proxy/hdrs/URL.h | 6 + > proxy/http/HttpClientSession.cc | 1 + > proxy/http/HttpConfig.cc | 5 + > proxy/http/HttpConfig.h | 1 + > proxy/http/HttpDebugNames.cc | 3 +- > proxy/http/HttpSM.cc | 23 ++- > proxy/http/HttpTransact.cc | 284 ++++++++++++++++++++++++++++----- > proxy/http/HttpTransact.h | 33 +++- > proxy/http/HttpTransactHeaders.cc | 7 +- > proxy/http/remap/RemapConfig.cc | 17 +- > 17 files changed, 406 insertions(+), 52 deletions(-) > ---------------------------------------------------------------------- > > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/CHANGES > ---------------------------------------------------------------------- > diff --git a/CHANGES b/CHANGES > index be006e8..fab65c0 100644 > --- a/CHANGES > +++ b/CHANGES > @@ -1,6 +1,8 @@ > -*- coding: utf-8 -*- > Changes with Apache Traffic Server 4.2.0 > > + *) [TS-2541] Add WebSocket support > + > *) [TS-2550] Add inline configuration overrised to the conf_remap plugin. > > *) [TS-2546] Move xptr and _xstrdup to ink_memory.{h,cc}. > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/config/remap.config.default > ---------------------------------------------------------------------- > diff --git a/proxy/config/remap.config.default > b/proxy/config/remap.config.default > index e0cd89a..2198ee4 100644 > --- a/proxy/config/remap.config.default > +++ b/proxy/config/remap.config.default > @@ -149,6 +149,14 @@ > # Example: > # map http://foo.cow.com/ http://bar.cow.com > @src_ip=10.72.118.51-10.72.118.62 @method=GET @method=DELETE > @src_ip=192.168.0.1-192.168.0.254 @action=allow @method=PUT > # > +# Traffic Server supports WebSockets but it must be enabled via remap. > WebSocket upgrades are automatically > +# detected when there exists a remap rule containing a ws:// scheme. > +# > +# Example: > +# map ws://bar.com/ ws://foo.com/ > +# > +# Explaination: When a request comes in with the appropriate upgrade > headers, Traffic Server will use this > +# remap rule in an attempt to establish and maintain a websocket > connection. > # > # Named filters can be created and applied to blocks of mappings > # using the .definefilter, .activatefilter, and .deactivatefilter > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/hdrs/HdrToken.cc > ---------------------------------------------------------------------- > diff --git a/proxy/hdrs/HdrToken.cc b/proxy/hdrs/HdrToken.cc > index 72bbbe1..7977b67 100644 > --- a/proxy/hdrs/HdrToken.cc > +++ b/proxy/hdrs/HdrToken.cc > @@ -145,6 +145,11 @@ static const char *_hdrtoken_strs[] = { > "chunked", > "close", > > + // WS > + "websocket", > + "Sec-WebSocket-Key", > + "Sec-WebSocket-Version", > + > // URL schemes > "file", > "ftp", > @@ -164,6 +169,8 @@ static const char *_hdrtoken_strs[] = { > "mmsu", > "mmst", > "mms", > + "wss", > + "ws", > > // HTTP methods > "CONNECT", > @@ -203,6 +210,8 @@ static HdrTokenTypeBinding > _hdrtoken_strs_type_initializers[] = { > {"mms", HDRTOKEN_TYPE_SCHEME}, > {"mmsu", HDRTOKEN_TYPE_SCHEME}, > {"mmst", HDRTOKEN_TYPE_SCHEME}, > + {"wss", HDRTOKEN_TYPE_SCHEME}, > + {"ws", HDRTOKEN_TYPE_SCHEME}, > > {"CONNECT", HDRTOKEN_TYPE_METHOD}, > {"DELETE", HDRTOKEN_TYPE_METHOD}, > @@ -309,6 +318,8 @@ static HdrTokenFieldInfo > _hdrtoken_strs_field_initializers[] = { > {"@DataInfo", MIME_SLOTID_NONE, MIME_PRESENCE_INT_DATA_INFO, HTIF_NONE}, > {"X-ID", MIME_SLOTID_NONE, MIME_PRESENCE_NONE, (HTIF_COMMAS | HTIF_MULTVALS > | HTIF_HOPBYHOP)}, > {"X-Forwarded-For", MIME_SLOTID_NONE, MIME_PRESENCE_NONE, (HTIF_COMMAS | > HTIF_MULTVALS)}, > + {"Sec-WebSocket-Key", MIME_SLOTID_NONE, MIME_PRESENCE_NONE, HTIF_NONE}, > + {"Sec-WebSocket-Version", MIME_SLOTID_NONE, MIME_PRESENCE_NONE, HTIF_NONE}, > {NULL, 0, 0, 0} > }; > > @@ -473,6 +484,11 @@ static const char *_hdrtoken_commonly_tokenized_strs[] = > { > "chunked", > "close", > > + // WS > + "websocket", > + "Sec-WebSocket-Key", > + "Sec-WebSocket-Version", > + > // URL schemes > "file", > "ftp", > @@ -492,6 +508,8 @@ static const char *_hdrtoken_commonly_tokenized_strs[] = { > "mmsu", > "mmst", > "mms", > + "wss", > + "ws", > > // HTTP methods > "CONNECT", > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/hdrs/HdrToken.h > ---------------------------------------------------------------------- > diff --git a/proxy/hdrs/HdrToken.h b/proxy/hdrs/HdrToken.h > index 052753a..95dc95c 100644 > --- a/proxy/hdrs/HdrToken.h > +++ b/proxy/hdrs/HdrToken.h > @@ -373,11 +373,11 @@ hdrtoken_wks_to_flags(const char *wks) > > // bits 56-60 were used for a benchmark hack, but are now free to be used > // for something else > -#define MIME_PRESENCE_UNUSED_1 (TOK_64_CONST(1) << 56) > -#define MIME_PRESENCE_UNUSED_2 (TOK_64_CONST(1) << 57) > +#define MIME_PRESENCE_UNUSED_1 (TOK_64_CONST(1) << 56) > +#define MIME_PRESENCE_UNUSED_2 (TOK_64_CONST(1) << 57) > #define MIME_PRESENCE_UNUSED_3 (TOK_64_CONST(1) << 58) > -#define MIME_PRESENCE_UNUSED_4 (TOK_64_CONST(1) << 59) > -#define MIME_PRESENCE_UNUSED_5 (TOK_64_CONST(1) << 60) > +#define MIME_PRESENCE_UNUSED_4 (TOK_64_CONST(1) << 59) > +#define MIME_PRESENCE_UNUSED_5 (TOK_64_CONST(1) << 60) > > #define MIME_PRESENCE_XREF (TOK_64_CONST(1) << 61) > #define MIME_PRESENCE_INT_DATA_INFO (TOK_64_CONST(1) << 62) > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/hdrs/MIME.cc > ---------------------------------------------------------------------- > diff --git a/proxy/hdrs/MIME.cc b/proxy/hdrs/MIME.cc > index 0313314..0de0db2 100644 > --- a/proxy/hdrs/MIME.cc > +++ b/proxy/hdrs/MIME.cc > @@ -156,6 +156,8 @@ const char *MIME_FIELD_XREF; > const char *MIME_FIELD_INT_DATA_INFO; > const char *MIME_FIELD_X_ID; > const char *MIME_FIELD_X_FORWARDED_FOR; > +const char *MIME_FIELD_SEC_WEBSOCKET_KEY; > +const char *MIME_FIELD_SEC_WEBSOCKET_VERSION; > > const char *MIME_VALUE_BYTES; > const char *MIME_VALUE_CHUNKED; > @@ -179,6 +181,8 @@ const char *MIME_VALUE_PROXY_REVALIDATE; > const char *MIME_VALUE_PUBLIC; > const char *MIME_VALUE_S_MAXAGE; > const char *MIME_VALUE_NEED_REVALIDATE_ONCE; > +const char *MIME_VALUE_WEBSOCKET; > + > // Cache-control: extension "need-revalidate-once" is used internally by T.S. > // to invalidate a document, and it is not returned/forwarded. > // If a cached document has this extension set (ie, is invalidated), > @@ -265,6 +269,8 @@ int MIME_LEN_XREF; > int MIME_LEN_INT_DATA_INFO; > int MIME_LEN_X_ID; > int MIME_LEN_X_FORWARDED_FOR; > +int MIME_LEN_SEC_WEBSOCKET_KEY; > +int MIME_LEN_SEC_WEBSOCKET_VERSION; > > int MIME_WKSIDX_ACCEPT; > int MIME_WKSIDX_ACCEPT_CHARSET; > @@ -340,7 +346,8 @@ int MIME_WKSIDX_XREF; > int MIME_WKSIDX_INT_DATA_INFO; > int MIME_WKSIDX_X_ID; > int MIME_WKSIDX_X_FORWARDED_FOR; > - > +int MIME_WKSIDX_SEC_WEBSOCKET_KEY; > +int MIME_WKSIDX_SEC_WEBSOCKET_VERSION; > > /*********************************************************************** > * * > @@ -684,6 +691,9 @@ mime_init() > MIME_FIELD_X_ID = hdrtoken_string_to_wks("X-ID"); > MIME_FIELD_X_FORWARDED_FOR = hdrtoken_string_to_wks("X-Forwarded-For"); > > + MIME_FIELD_SEC_WEBSOCKET_KEY = > hdrtoken_string_to_wks("Sec-WebSocket-Key"); > + MIME_FIELD_SEC_WEBSOCKET_VERSION = > hdrtoken_string_to_wks("Sec-WebSocket-Version"); > + > > MIME_LEN_ACCEPT = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT); > MIME_LEN_ACCEPT_CHARSET = > hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_CHARSET); > @@ -760,6 +770,10 @@ mime_init() > MIME_LEN_X_ID = hdrtoken_wks_to_length(MIME_FIELD_X_ID); > MIME_LEN_X_FORWARDED_FOR = > hdrtoken_wks_to_length(MIME_FIELD_X_FORWARDED_FOR); > > + MIME_LEN_SEC_WEBSOCKET_KEY = > hdrtoken_wks_to_length(MIME_FIELD_SEC_WEBSOCKET_KEY); > + MIME_LEN_SEC_WEBSOCKET_VERSION = > hdrtoken_wks_to_length(MIME_FIELD_SEC_WEBSOCKET_VERSION); > + > + > MIME_WKSIDX_ACCEPT = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT); > MIME_WKSIDX_ACCEPT_CHARSET = > hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_CHARSET); > MIME_WKSIDX_ACCEPT_ENCODING = > hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_ENCODING); > @@ -833,6 +847,8 @@ mime_init() > MIME_WKSIDX_XREF = hdrtoken_wks_to_index(MIME_FIELD_XREF); > MIME_WKSIDX_X_ID = hdrtoken_wks_to_index(MIME_FIELD_X_ID); > MIME_WKSIDX_X_FORWARDED_FOR = > hdrtoken_wks_to_index(MIME_FIELD_X_FORWARDED_FOR); > + MIME_WKSIDX_SEC_WEBSOCKET_KEY = > hdrtoken_wks_to_index(MIME_FIELD_SEC_WEBSOCKET_KEY); > + MIME_WKSIDX_SEC_WEBSOCKET_VERSION = > hdrtoken_wks_to_index(MIME_FIELD_SEC_WEBSOCKET_VERSION); > > MIME_VALUE_BYTES = hdrtoken_string_to_wks("bytes"); > MIME_VALUE_CHUNKED = hdrtoken_string_to_wks("chunked"); > @@ -856,6 +872,8 @@ mime_init() > MIME_VALUE_PUBLIC = hdrtoken_string_to_wks("public"); > MIME_VALUE_S_MAXAGE = hdrtoken_string_to_wks("s-maxage"); > MIME_VALUE_NEED_REVALIDATE_ONCE = > hdrtoken_string_to_wks("need-revalidate-once"); > + MIME_VALUE_WEBSOCKET = hdrtoken_string_to_wks("websocket"); > + > > mime_init_date_format_table(); > mime_init_cache_control_cooking_masks(); > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/hdrs/MIME.h > ---------------------------------------------------------------------- > diff --git a/proxy/hdrs/MIME.h b/proxy/hdrs/MIME.h > index a75e56a..9c7b721 100644 > --- a/proxy/hdrs/MIME.h > +++ b/proxy/hdrs/MIME.h > @@ -367,6 +367,8 @@ extern const char *MIME_FIELD_XREF; > extern const char *MIME_FIELD_INT_DATA_INFO; > extern const char *MIME_FIELD_X_ID; > extern const char *MIME_FIELD_X_FORWARDED_FOR; > +extern const char *MIME_FIELD_SEC_WEBSOCKET_KEY; > +extern const char *MIME_FIELD_SEC_WEBSOCKET_VERSION; > > extern const char *MIME_VALUE_BYTES; > extern const char *MIME_VALUE_CHUNKED; > @@ -390,6 +392,7 @@ extern const char *MIME_VALUE_PROXY_REVALIDATE; > extern const char *MIME_VALUE_PUBLIC; > extern const char *MIME_VALUE_S_MAXAGE; > extern const char *MIME_VALUE_NEED_REVALIDATE_ONCE; > +extern const char *MIME_VALUE_WEBSOCKET; > > extern int MIME_LEN_ACCEPT; > extern int MIME_LEN_ACCEPT_CHARSET; > @@ -489,6 +492,9 @@ extern int MIME_LEN_PUBLIC; > extern int MIME_LEN_S_MAXAGE; > extern int MIME_LEN_NEED_REVALIDATE_ONCE; > > +extern int MIME_LEN_SEC_WEBSOCKET_KEY; > +extern int MIME_LEN_SEC_WEBSOCKET_VERSION; > + > extern int MIME_WKSIDX_ACCEPT; > extern int MIME_WKSIDX_ACCEPT_CHARSET; > extern int MIME_WKSIDX_ACCEPT_ENCODING; > @@ -562,6 +568,8 @@ extern int MIME_WKSIDX_WWW_AUTHENTICATE; > extern int MIME_WKSIDX_XREF; > extern int MIME_WKSIDX_INT_DATA_INFO; > extern int MIME_WKSIDX_X_ID; > +extern int MIME_WKSIDX_SEC_WEBSOCKET_KEY; > +extern int MIME_WKSIDX_SEC_WEBSOCKET_VERSION; > > /*********************************************************************** > * * > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/hdrs/URL.cc > ---------------------------------------------------------------------- > diff --git a/proxy/hdrs/URL.cc b/proxy/hdrs/URL.cc > index 976a9c4..2dea36f 100644 > --- a/proxy/hdrs/URL.cc > +++ b/proxy/hdrs/URL.cc > @@ -33,6 +33,8 @@ const char *URL_SCHEME_FTP; > const char *URL_SCHEME_GOPHER; > const char *URL_SCHEME_HTTP; > const char *URL_SCHEME_HTTPS; > +const char *URL_SCHEME_WSS; > +const char *URL_SCHEME_WS; > const char *URL_SCHEME_MAILTO; > const char *URL_SCHEME_NEWS; > const char *URL_SCHEME_NNTP; > @@ -52,6 +54,8 @@ int URL_WKSIDX_FTP; > int URL_WKSIDX_GOPHER; > int URL_WKSIDX_HTTP; > int URL_WKSIDX_HTTPS; > +int URL_WKSIDX_WS; > +int URL_WKSIDX_WSS; > int URL_WKSIDX_MAILTO; > int URL_WKSIDX_NEWS; > int URL_WKSIDX_NNTP; > @@ -71,6 +75,8 @@ int URL_LEN_FTP; > int URL_LEN_GOPHER; > int URL_LEN_HTTP; > int URL_LEN_HTTPS; > +int URL_LEN_WS; > +int URL_LEN_WSS; > int URL_LEN_MAILTO; > int URL_LEN_NEWS; > int URL_LEN_NNTP; > @@ -106,6 +112,8 @@ url_init() > URL_SCHEME_GOPHER = hdrtoken_string_to_wks("gopher"); > URL_SCHEME_HTTP = hdrtoken_string_to_wks("http"); > URL_SCHEME_HTTPS = hdrtoken_string_to_wks("https"); > + URL_SCHEME_WSS = hdrtoken_string_to_wks("wss"); > + URL_SCHEME_WS = hdrtoken_string_to_wks("ws"); > URL_SCHEME_MAILTO = hdrtoken_string_to_wks("mailto"); > URL_SCHEME_NEWS = hdrtoken_string_to_wks("news"); > URL_SCHEME_NNTP = hdrtoken_string_to_wks("nntp"); > @@ -125,6 +133,8 @@ url_init() > URL_SCHEME_GOPHER && > URL_SCHEME_HTTP && > URL_SCHEME_HTTPS && > + URL_SCHEME_WS && > + URL_SCHEME_WSS && > URL_SCHEME_MAILTO && > URL_SCHEME_NEWS && > URL_SCHEME_NNTP && > @@ -145,6 +155,8 @@ url_init() > URL_WKSIDX_GOPHER = hdrtoken_wks_to_index(URL_SCHEME_GOPHER); > URL_WKSIDX_HTTP = hdrtoken_wks_to_index(URL_SCHEME_HTTP); > URL_WKSIDX_HTTPS = hdrtoken_wks_to_index(URL_SCHEME_HTTPS); > + URL_WKSIDX_WS = hdrtoken_wks_to_index(URL_SCHEME_WS); > + URL_WKSIDX_WSS = hdrtoken_wks_to_index(URL_SCHEME_WSS); > URL_WKSIDX_MAILTO = hdrtoken_wks_to_index(URL_SCHEME_MAILTO); > URL_WKSIDX_NEWS = hdrtoken_wks_to_index(URL_SCHEME_NEWS); > URL_WKSIDX_NNTP = hdrtoken_wks_to_index(URL_SCHEME_NNTP); > @@ -164,6 +176,8 @@ url_init() > URL_LEN_GOPHER = hdrtoken_wks_to_length(URL_SCHEME_GOPHER); > URL_LEN_HTTP = hdrtoken_wks_to_length(URL_SCHEME_HTTP); > URL_LEN_HTTPS = hdrtoken_wks_to_length(URL_SCHEME_HTTPS); > + URL_LEN_WS = hdrtoken_wks_to_length(URL_SCHEME_WS); > + URL_LEN_WSS = hdrtoken_wks_to_length(URL_SCHEME_WSS); > URL_LEN_MAILTO = hdrtoken_wks_to_length(URL_SCHEME_MAILTO); > URL_LEN_NEWS = hdrtoken_wks_to_length(URL_SCHEME_NEWS); > URL_LEN_NNTP = hdrtoken_wks_to_length(URL_SCHEME_NNTP); > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/hdrs/URL.h > ---------------------------------------------------------------------- > diff --git a/proxy/hdrs/URL.h b/proxy/hdrs/URL.h > index 30f1711..c60d1c2 100644 > --- a/proxy/hdrs/URL.h > +++ b/proxy/hdrs/URL.h > @@ -91,6 +91,8 @@ extern const char *URL_SCHEME_FTP; > extern const char *URL_SCHEME_GOPHER; > extern const char *URL_SCHEME_HTTP; > extern const char *URL_SCHEME_HTTPS; > +extern const char *URL_SCHEME_WS; > +extern const char *URL_SCHEME_WSS; > extern const char *URL_SCHEME_MAILTO; > extern const char *URL_SCHEME_NEWS; > extern const char *URL_SCHEME_NNTP; > @@ -110,6 +112,8 @@ extern int URL_WKSIDX_FTP; > extern int URL_WKSIDX_GOPHER; > extern int URL_WKSIDX_HTTP; > extern int URL_WKSIDX_HTTPS; > +extern int URL_WKSIDX_WS; > +extern int URL_WKSIDX_WSS; > extern int URL_WKSIDX_MAILTO; > extern int URL_WKSIDX_NEWS; > extern int URL_WKSIDX_NNTP; > @@ -129,6 +133,8 @@ extern int URL_LEN_FTP; > extern int URL_LEN_GOPHER; > extern int URL_LEN_HTTP; > extern int URL_LEN_HTTPS; > +extern int URL_LEN_WS; > +extern int URL_LEN_WSS; > extern int URL_LEN_MAILTO; > extern int URL_LEN_NEWS; > extern int URL_LEN_NNTP; > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/HttpClientSession.cc > ---------------------------------------------------------------------- > diff --git a/proxy/http/HttpClientSession.cc b/proxy/http/HttpClientSession.cc > index 5db6275..c518044 100644 > --- a/proxy/http/HttpClientSession.cc > +++ b/proxy/http/HttpClientSession.cc > @@ -285,6 +285,7 @@ HttpClientSession::do_io_close(int alerrno) > HTTP_DECREMENT_DYN_STAT(http_current_active_client_connections_stat); > } > } > + > // Prevent double closing > ink_release_assert(read_state != HCS_CLOSED); > > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/HttpConfig.cc > ---------------------------------------------------------------------- > diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc > index 61ba66b..419de41 100644 > --- a/proxy/http/HttpConfig.cc > +++ b/proxy/http/HttpConfig.cc > @@ -140,6 +140,11 @@ register_stat_callbacks() > RECD_INT, RECP_NON_PERSISTENT, > (int) http_current_active_client_connections_stat, > RecRawStatSyncSum); > HTTP_CLEAR_DYN_STAT(http_current_active_client_connections_stat); > + RecRegisterRawStat(http_rsb, RECT_PROCESS, > + > "proxy.process.http.websocket.current_active_client_connections", > + RECD_INT, RECP_NON_PERSISTENT, > + (int) > http_websocket_current_active_client_connections_stat, RecRawStatSyncSum); > + HTTP_CLEAR_DYN_STAT(http_websocket_current_active_client_connections_stat); > // Current Transaction Stats > RecRegisterRawStat(http_rsb, RECT_PROCESS, > "proxy.process.http.current_client_transactions", > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/HttpConfig.h > ---------------------------------------------------------------------- > diff --git a/proxy/http/HttpConfig.h b/proxy/http/HttpConfig.h > index e4790a9..54cf273 100644 > --- a/proxy/http/HttpConfig.h > +++ b/proxy/http/HttpConfig.h > @@ -66,6 +66,7 @@ enum > http_background_fill_current_count_stat, > http_current_client_connections_stat, > http_current_active_client_connections_stat, > + http_websocket_current_active_client_connections_stat, > http_current_client_transactions_stat, > http_total_incoming_connections_stat, > http_current_parent_proxy_transactions_stat, > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/HttpDebugNames.cc > ---------------------------------------------------------------------- > diff --git a/proxy/http/HttpDebugNames.cc b/proxy/http/HttpDebugNames.cc > index c5a3728..0211294 100644 > --- a/proxy/http/HttpDebugNames.cc > +++ b/proxy/http/HttpDebugNames.cc > @@ -396,7 +396,8 @@ > HttpDebugNames::get_action_name(HttpTransact::StateMachineAction_t e) > return ("HTTP_API_POST_REMAP"); > case HttpTransact::HTTP_POST_REMAP_SKIP: > return ("HTTP_POST_REMAP_SKIP"); > - > + case HttpTransact::HTTP_POST_REMAP_UPGRADE: > + return ("HTTP_POST_REMAP_UPGRADE"); > } > > return ("unknown state name"); > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/HttpSM.cc > ---------------------------------------------------------------------- > diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc > index 41f8cf1..8618728 100644 > --- a/proxy/http/HttpSM.cc > +++ b/proxy/http/HttpSM.cc > @@ -1583,9 +1583,19 @@ HttpSM::handle_api_return() > } > case HttpTransact::SERVER_READ: > { > - setup_server_transfer(); > - perform_cache_write_action(); > - tunnel.tunnel_run(); > + if (unlikely(t_state.did_upgrade_succeed)) { > + // We've sucessfully handled the upgrade, let's now setup > + // a blind tunnel. > + if(t_state.is_websocket) { > + > HTTP_INCREMENT_DYN_STAT(http_websocket_current_active_client_connections_stat); > + } > + > + setup_blind_tunnel(true); > + } else { > + setup_server_transfer(); > + perform_cache_write_action(); > + tunnel.tunnel_run(); > + } > break; > } > case HttpTransact::SERVE_FROM_CACHE: > @@ -2739,6 +2749,11 @@ HttpSM::tunnel_handler(int event, void *data) > ink_assert(data == &tunnel); > // The tunnel calls this when it is done > terminate_sm = true; > + > + if (unlikely(t_state.is_websocket)) { > + > HTTP_DECREMENT_DYN_STAT(http_websocket_current_active_client_connections_stat); > + } > + > return 0; > } > > @@ -6136,6 +6151,7 @@ HttpSM::setup_server_transfer_to_cache_only() > void > HttpSM::setup_server_transfer() > { > + DebugSM("http", "Setup Server Transfer"); > int64_t alloc_index, hdr_size; > int64_t nbytes; > > @@ -6806,6 +6822,7 @@ HttpSM::set_next_state() > break; > } > > + case HttpTransact::HTTP_POST_REMAP_UPGRADE: > case HttpTransact::HTTP_POST_REMAP_SKIP: > { > call_transact_and_set_next_state(NULL); > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/HttpTransact.cc > ---------------------------------------------------------------------- > diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc > index a3187b2..9692d99 100644 > --- a/proxy/http/HttpTransact.cc > +++ b/proxy/http/HttpTransact.cc > @@ -757,6 +757,11 @@ HttpTransact::StartRemapRequest(State* s) > > if (s->api_skip_all_remapping) { > Debug ("http_trans", "API request to skip remapping"); > + > + if (s->is_upgrade_request && s->post_remap_upgrade_return_point) { > + TRANSACT_RETURN(HTTP_POST_REMAP_SKIP, > s->post_remap_upgrade_return_point); > + } > + > TRANSACT_RETURN(HTTP_POST_REMAP_SKIP, HttpTransact::HandleRequest); > } > > @@ -965,12 +970,150 @@ done: > } else { > s->hdr_info.client_response.clear(); //anything previously set is invalid > from this point forward > DebugTxn("http_trans", "END HttpTransact::EndRemapRequest"); > + > + if (s->is_upgrade_request && s->post_remap_upgrade_return_point) { > + TRANSACT_RETURN(HTTP_API_POST_REMAP, > s->post_remap_upgrade_return_point); > + } > + > TRANSACT_RETURN(HTTP_API_POST_REMAP, HttpTransact::HandleRequest); > } > > ink_assert(!"not reached"); > } > > +bool HttpTransact::handle_upgrade_request(State *s) { > + // Quickest way to determine that this is defintely not an upgrade. > + /* RFC 6455 The method of the request MUST be GET, and the HTTP version > MUST > + be at least 1.1. */ > + if (!s->hdr_info.client_request.presence(MIME_PRESENCE_UPGRADE) || > + !s->hdr_info.client_request.presence(MIME_PRESENCE_CONNECTION) || > + s->method != HTTP_WKSIDX_GET || > + s->hdr_info.client_request.version_get() < HTTPVersion(1, 1)) { > + return false; > + } > + > + MIMEField *upgrade_hdr = > s->hdr_info.client_request.field_find(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE); > + MIMEField *connection_hdr = > s->hdr_info.client_request.field_find(MIME_FIELD_CONNECTION, > MIME_LEN_CONNECTION); > + > + StrList connection_hdr_vals; > + const char *upgrade_hdr_val = NULL; > + int upgrade_hdr_val_len = 0; > + > + if ( !upgrade_hdr || > + !connection_hdr || > + connection_hdr->value_get_comma_list(&connection_hdr_vals) == 0 || > + (upgrade_hdr_val = upgrade_hdr->value_get(&upgrade_hdr_val_len)) == > NULL) { > + DebugTxn("http_trans_upgrade", "Transaction wasn't a valid upgrade > request, proceeding as a normal HTTP request."); > + return false; > + } > + > + /* > + * In order for this request to be treated as a normal upgrade request we > must have a Connection: Upgrade header > + * and a Upgrade: header, with a non-empty value, otherwise we just assume > it's not an Upgrade Request, after > + * we've verified that, we will try to match this upgrade to a known > upgrade type such as Websockets. > + */ > + bool connection_contains_upgrade = false; > + // Next, let's validate that the Connection header contains an Upgrade key > + for(int i = 0; i < connection_hdr_vals.count; ++i) { > + Str *val = connection_hdr_vals.get_idx(i); > + if (ptr_len_casecmp(val->str, val->len, MIME_FIELD_UPGRADE, > MIME_LEN_UPGRADE) == 0) { > + connection_contains_upgrade = true; > + break; > + } > + } > + > + if (!connection_contains_upgrade) { > + DebugTxn("http_trans_upgrade", "Transaction wasn't a valid upgrade > request, proceeding as a normal HTTP request, missing Connection upgrade > header."); > + return false; > + } > + > + > + // Mark this request as an upgrade request. > + s->is_upgrade_request = true; > + > + /* > + RFC 6455 > + The request MUST contain an |Upgrade| header field whose value > + MUST include the "websocket" keyword. > + The request MUST contain a |Connection| header field whose value > + MUST include the "Upgrade" token. // Checked Above > + The request MUST include a header field with the name > + |Sec-WebSocket-Key|. > + The request MUST include a header field with the name > + |Sec-WebSocket-Version|. The value of this header field MUST be > + 13. > + */ > + if (hdrtoken_tokenize(upgrade_hdr_val, upgrade_hdr_val_len, > &s->upgrade_token_wks) >= 0) { > + if (s->upgrade_token_wks == MIME_VALUE_WEBSOCKET) { > + MIMEField *sec_websocket_key = > s->hdr_info.client_request.field_find(MIME_FIELD_SEC_WEBSOCKET_KEY, > MIME_LEN_SEC_WEBSOCKET_KEY); > + MIMEField *sec_websocket_ver = > s->hdr_info.client_request.field_find(MIME_FIELD_SEC_WEBSOCKET_VERSION, > MIME_LEN_SEC_WEBSOCKET_VERSION); > + > + if (sec_websocket_key && > + sec_websocket_ver && > + sec_websocket_ver->value_get_int() == 13) { > + DebugTxn("http_trans_upgrade", "Transaction wants upgrade to > websockets"); > + handle_websocket_upgrade_pre_remap(s); > + return true; > + } else { > + DebugTxn("http_trans_upgrade", "Unable to upgrade connection to > websockets, invalid headers (RFC 6455)."); > + } > + } > + } else { > + DebugTxn("http_trans_upgrade", "Transaction requested upgrade for > unknown protocol: %s", upgrade_hdr_val); > + } > + > + build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Invalid Upgrade > Request", "request#syntax_error", > + "Invalid Upgrade Request"); > + > + // we want our modify_request method to just return while we fail out from > here. > + // this seems like the preferred option because the user wanted to do an > upgrade but sent a bad protocol. > + TRANSACT_RETURN_VAL(PROXY_SEND_ERROR_CACHE_NOOP, NULL, true); > +} > + > +void > +HttpTransact::handle_websocket_upgrade_pre_remap(State *s) { > + DebugTxn("http_trans_websocket_upgrade_pre_remap", "Prepping transaction > before remap."); > + > + /* > + * We will use this opportunity to set everything up so that during the > remap stage we can deal with > + * ws:// and wss:// remap rules, and then we will take over again post > remap. > + */ > + s->is_websocket = true; > + s->post_remap_upgrade_return_point = > HttpTransact::handle_websocket_upgrade_post_remap; > + > + /* let's modify the url scheme to be wss or ws, so remapping will happen > as expected */ > + URL *url = s->hdr_info.client_request.url_get(); > + if (url->scheme_get_wksidx() == URL_WKSIDX_HTTP) { > + DebugTxn("http_trans_websocket_upgrade_pre_remap", "Changing scheme to > WS for remapping."); > + url->scheme_set(URL_SCHEME_WS, URL_LEN_WS); > + } else if (url->scheme_get_wksidx() == URL_WKSIDX_HTTPS) { > + DebugTxn("http_trans_websocket_upgrade_pre_remap", "Changing scheme to > WSS for remapping."); > + url->scheme_set(URL_SCHEME_WSS, URL_LEN_WSS); > + } else { > + DebugTxn("http_trans_websocket_upgrade_pre_remap", "Invalid scheme for > websocket upgrade"); > + build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Invalid Upgrade > Request", "request#syntax_error", > + "Invalid Upgrade Request"); > + TRANSACT_RETURN(PROXY_SEND_ERROR_CACHE_NOOP, NULL); > + } > + > + TRANSACT_RETURN(HTTP_API_READ_REQUEST_HDR, > HttpTransact::StartRemapRequest); > +} > + > +void > +HttpTransact::handle_websocket_upgrade_post_remap(State *s) { > + DebugTxn("http_trans_websocket_upgrade_post_remap", "Remap is complete, > start websocket upgrade"); > + > + TRANSACT_RETURN(HTTP_API_POST_REMAP, > HttpTransact::handle_websocket_connection); > +} > + > +void > +HttpTransact::handle_websocket_connection(State *s) { > + DebugTxn("http_trans_websocket", "START handle_websocket_connection"); > + > + HandleRequest(s); > +} > + > + > void > HttpTransact::ModifyRequest(State* s) > { > @@ -1078,6 +1221,13 @@ HttpTransact::ModifyRequest(State* s) > > DebugTxn("http_trans", "END HttpTransact::ModifyRequest"); > > + DebugTxn("http_trans", "Checking if transaction wants to upgrade"); > + if(handle_upgrade_request(s)) { > + // everything should be handled by the upgrade handler. > + DebugTxn("http_trans", "Transaction will be upgraded by the appropriate > upgrade handler."); > + return; > + } > + > TRANSACT_RETURN(HTTP_API_READ_REQUEST_HDR, HttpTransact::StartRemapRequest); > } > > @@ -1129,7 +1279,6 @@ HttpTransact::handleIfRedirect(State *s) > return false; > } > > - > void > HttpTransact::HandleRequest(State* s) > { > @@ -1158,6 +1307,7 @@ HttpTransact::HandleRequest(State* s) > if (is_debug_tag_set("http_chdr_describe")) { > obj_describe(s->hdr_info.client_request.m_http, 1); > } > + > // at this point we are guaranteed that the request is good and acceptable. > // initialize some state variables from the request (client version, > // client keep-alive, cache action, etc. > @@ -1251,6 +1401,7 @@ HttpTransact::HandleRequest(State* s) > TRANSACT_RETURN(HttpTransact::PROXY_SEND_ERROR_CACHE_NOOP, NULL); > } > } > + > // Added to skip the dns if the document is in the cache. > // DNS is requested before cache lookup only if there are rules in > cache.config , parent.config or > // if the newly added varible doc_in_cache_skip_dns is not enabled > @@ -5142,7 +5293,8 @@ HttpTransact::RequestError_t > HttpTransact::check_request_validity(State* s, HTTP > > if (!((scheme == URL_WKSIDX_HTTP) && (method == HTTP_WKSIDX_GET))) { > if (scheme != URL_WKSIDX_HTTP && scheme != URL_WKSIDX_HTTPS && > - method != HTTP_WKSIDX_CONNECT) { > + method != HTTP_WKSIDX_CONNECT && > + ((scheme == URL_WKSIDX_WS || scheme == URL_WKSIDX_WSS) && > !s->is_websocket)) { > if (scheme < 0) { > return NO_REQUEST_SCHEME; > } else { > @@ -5471,6 +5623,31 @@ > HttpTransact::initialize_state_variables_from_request(State* s, HTTPHdr* > obsolet > } > > s->next_hop_scheme = s->scheme = > incoming_request->url_get()->scheme_get_wksidx(); > + > + // With websockets we need to make an outgoing request > + // as http or https. > + // We switch back to HTTP or HTTPS for the next hop > + // I think this is required to properly establish outbound WSS connections, > + // you'll need to force the next hop to be https. > + if (s->is_websocket) { > + if (s->next_hop_scheme == URL_WKSIDX_WS) { > + DebugTxn("http_trans", "Switching WS next hop scheme to http."); > + s->next_hop_scheme = URL_WKSIDX_HTTP; > + s->scheme = URL_WKSIDX_HTTP; > + //s->request_data.hdr->url_get()->scheme_set(URL_SCHEME_HTTP, > URL_LEN_HTTP); > + } else if (s->next_hop_scheme == URL_WKSIDX_WSS) { > + DebugTxn("http_trans", "Switching WSS next hop scheme to https."); > + s->next_hop_scheme = URL_WKSIDX_HTTPS; > + s->scheme = URL_WKSIDX_HTTPS; > + //s->request_data.hdr->url_get()->scheme_set(URL_SCHEME_HTTPS, > URL_LEN_HTTPS); > + } else { > + Error("Scheme doesn't match websocket...!"); > + } > + > + s->current.mode = GENERIC_PROXY; > + s->cache_info.action = CACHE_DO_NO_ACTION; > + } > + > s->method = incoming_request->method_get_wksidx(); > > if (s->method == HTTP_WKSIDX_GET) { > @@ -5520,6 +5697,7 @@ > HttpTransact::initialize_state_variables_from_request(State* s, HTTPHdr* > obsolet > s->hdr_info.request_content_length = HTTP_UNDEFINED_CL; > } > s->request_data.hdr = &s->hdr_info.client_request; > + > s->request_data.hostname_str = s->arena.str_store(host_name, host_len); > ats_ip_copy(&s->request_data.src_ip, &s->client_info.addr); > memset(&s->request_data.dest_ip, 0, sizeof(s->request_data.dest_ip)); > @@ -5570,6 +5748,11 @@ > HttpTransact::initialize_state_variables_from_response(State* s, HTTPHdr* > incomi > s->current.server->keep_alive = > is_header_keep_alive(s->hdr_info.server_response.version_get(), > > s->hdr_info.server_request.version_get(), c_hdr); > > + // Don't allow an upgrade request to Keep Alive > + if (s->is_upgrade_request) { > + s->current.server->keep_alive = HTTP_NO_KEEPALIVE; > + } > + > if (s->current.server->keep_alive == HTTP_KEEPALIVE) { > if (!s->cop_test_page) > DebugTxn("http_hdrs", "[initialize_state_variables_from_response]" > "Server is keep-alive."); > @@ -6668,44 +6851,53 @@ > HttpTransact::handle_request_keep_alive_headers(State* s, HTTPVersion ver, > HTTPH > > // Since connection headers are hop-to-hop, strip the > // the ones we received from the user-agent > - heads->field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION); > heads->field_delete(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION); > + heads->field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION); > > - > - // Insert K-A headers as necessary > - switch (ka_action) { > - case KA_CONNECTION: > - ink_assert(s->current.server->keep_alive != HTTP_NO_KEEPALIVE); > - if (ver == HTTPVersion(1, 0)) { > - if (s->current.request_to == PARENT_PROXY || > - s->current.request_to == ICP_SUGGESTED_HOST) { > - heads->value_set(MIME_FIELD_PROXY_CONNECTION, > MIME_LEN_PROXY_CONNECTION, "keep-alive", 10); > - } else { > - heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, > "keep-alive", 10); > + if (!s->is_upgrade_request) { > + // Insert K-A headers as necessary > + switch (ka_action) { > + case KA_CONNECTION: > + ink_assert(s->current.server->keep_alive != HTTP_NO_KEEPALIVE); > + if (ver == HTTPVersion(1, 0)) { > + if (s->current.request_to == PARENT_PROXY || > + s->current.request_to == ICP_SUGGESTED_HOST) { > + heads->value_set(MIME_FIELD_PROXY_CONNECTION, > MIME_LEN_PROXY_CONNECTION, "keep-alive", 10); > + } else { > + heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, > "keep-alive", 10); > + } > } > - } > - // NOTE: if the version is 1.1 we don't need to do > - // anything since keep-alive is assumed > - break; > - case KA_DISABLED: > - case KA_CLOSE: > - if (s->current.server->keep_alive != HTTP_NO_KEEPALIVE || (ver == > HTTPVersion(1, 1))) { > - /* Had keep-alive */ > - s->current.server->keep_alive = HTTP_NO_KEEPALIVE; > - if (s->current.request_to == PARENT_PROXY || > - s->current.request_to == ICP_SUGGESTED_HOST) { > - heads->value_set(MIME_FIELD_PROXY_CONNECTION, > MIME_LEN_PROXY_CONNECTION, "close", 5); > - } else { > - heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, > "close", 5); > + // NOTE: if the version is 1.1 we don't need to do > + // anything since keep-alive is assumed > + break; > + case KA_DISABLED: > + case KA_CLOSE: > + if (s->current.server->keep_alive != HTTP_NO_KEEPALIVE || (ver == > HTTPVersion(1, 1))) { > + /* Had keep-alive */ > + s->current.server->keep_alive = HTTP_NO_KEEPALIVE; > + if (s->current.request_to == PARENT_PROXY || > + s->current.request_to == ICP_SUGGESTED_HOST) { > + heads->value_set(MIME_FIELD_PROXY_CONNECTION, > MIME_LEN_PROXY_CONNECTION, "close", 5); > + } else { > + heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, > "close", 5); > + } > } > + // Note: if we are 1.1, we always need to send the close > + // header since persistant connnections are the default > + break; > + case KA_UNKNOWN: > + default: > + ink_assert(0); > + break; > + } > + } else { /* websocket connection */ > + s->current.server->keep_alive = HTTP_NO_KEEPALIVE; > + s->client_info.keep_alive = HTTP_NO_KEEPALIVE; > + heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, > MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE); > + > + if (s->is_websocket) { > + heads->value_set(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE, "websocket", 9); > } > - // Note: if we are 1.1, we always need to send the close > - // header since persistant connnections are the default > - break; > - case KA_UNKNOWN: > - default: > - ink_assert(0); > - break; > } > } /* End > HttpTransact::handle_request_keep_alive_headers */ > > @@ -6736,6 +6928,24 @@ > HttpTransact::handle_response_keep_alive_headers(State* s, HTTPVersion ver, > HTTP > heads->field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION); > heads->field_delete(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION); > > + // Handle the upgrade cases > + if (s->is_upgrade_request && > + heads->status_get() == HTTP_STATUS_SWITCHING_PROTOCOL && > + s->source == SOURCE_HTTP_ORIGIN_SERVER) { > + s->client_info.keep_alive = HTTP_NO_KEEPALIVE; > + if (s->is_websocket) { > + DebugTxn("http_trans", "transaction successfully upgraded to > websockets."); > + //s->transparent_passthrough = true; > + heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, > MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE); > + heads->value_set(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE, "websocket", 9); > + } > + > + // We set this state so that we can jump to our blind forwarding state > once > + // the response is sent to the client. > + s->did_upgrade_succeed = true; > + return; > + } > + > int c_hdr_field_len; > const char *c_hdr_field_str; > if (s->client_info.proxy_connect_hdr) { > @@ -7585,7 +7795,9 @@ HttpTransact::build_request(State* s, HTTPHdr* > base_request, HTTPHdr* outgoing_r > } > > if (s->current.server == &s->server_info && > - (s->next_hop_scheme == URL_WKSIDX_HTTP || s->next_hop_scheme == > URL_WKSIDX_HTTPS)) { > + (s->next_hop_scheme == URL_WKSIDX_HTTP || s->next_hop_scheme == > URL_WKSIDX_HTTPS || > + s->next_hop_scheme == URL_WKSIDX_WS || s->next_hop_scheme == > URL_WKSIDX_WSS)) { > + DebugTxn("http_trans", "[build_request] removing host name from url"); > HttpTransactHeaders::remove_host_name_from_url(outgoing_request); > } > > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/HttpTransact.h > ---------------------------------------------------------------------- > diff --git a/proxy/http/HttpTransact.h b/proxy/http/HttpTransact.h > index ad3152b..21d8a40 100644 > --- a/proxy/http/HttpTransact.h > +++ b/proxy/http/HttpTransact.h > @@ -79,12 +79,20 @@ > } > > > -#define TRANSACT_RETURN(n, r) \ > +#define TRANSACT_SETUP_RETURN(n, r) \ > s->next_action = n; \ > s->transact_return_point = r; \ > DebugSpecific((s->state_machine && s->state_machine->debug_on), "http_trans", > "Next action %s; %s", #n, #r); \ > + > +#define TRANSACT_RETURN(n, r) \ > +TRANSACT_SETUP_RETURN(n, r) \ > return; \ > > +#define TRANSACT_RETURN_VAL(n, r, v) \ > +TRANSACT_SETUP_RETURN(n, r) \ > +return v; \ > + > + > #define SET_UNPREPARE_CACHE_ACTION(C) \ > { \ > if (C.action == HttpTransact::CACHE_PREPARE_TO_DELETE) { \ > @@ -499,7 +507,8 @@ public: > HTTP_REMAP_REQUEST, > HTTP_API_POST_REMAP, > HTTP_POST_REMAP_SKIP, > - > + HTTP_POST_REMAP_UPGRADE, > + > HTTP_API_OS_DNS, > HTTP_API_SEND_REQUEST_HDR, > HTTP_API_READ_CACHE_HDR, > @@ -894,6 +903,16 @@ public: > StateMachineAction_t next_action; // out > StateMachineAction_t api_next_action; // out > void (*transact_return_point) (HttpTransact::State* s); // out > + > + // We keep this so we can jump back to the upgrade handler after remap > is complete > + bool is_upgrade_request; > + void (*post_remap_upgrade_return_point) (HttpTransact::State* s); // > out > + const char *upgrade_token_wks; > + > + // Some WebSocket state > + bool is_websocket; > + bool did_upgrade_succeed; > + > char *internal_msg_buffer; // out > char *internal_msg_buffer_type; // out > int64_t internal_msg_buffer_size; // out > @@ -1031,6 +1050,11 @@ public: > next_action(STATE_MACHINE_ACTION_UNDEFINED), > api_next_action(STATE_MACHINE_ACTION_UNDEFINED), > transact_return_point(NULL), > + is_upgrade_request(false), > + post_remap_upgrade_return_point(NULL), > + upgrade_token_wks(NULL), > + is_websocket(false), > + did_upgrade_succeed(false), > internal_msg_buffer(0), > internal_msg_buffer_type(0), > internal_msg_buffer_size(0), > @@ -1259,6 +1283,10 @@ public: > static void merge_warning_header(HTTPHdr* cached_header, HTTPHdr* > response_header); > static void SetCacheFreshnessLimit(State* s); > static void HandleApiErrorJump(State *); > + static void handle_websocket_upgrade_pre_remap(State *s); > + static void handle_websocket_upgrade_post_remap(State *s); > + static bool handle_upgrade_request(State *s); > + static void handle_websocket_connection(State *s); > > static void HandleCacheOpenReadPush(State* s, bool read_successful); > static void HandlePushResponseHdr(State* s); > @@ -1298,6 +1326,7 @@ public: > static bool is_request_cache_lookupable(State* s); > static bool is_request_valid(State* s, HTTPHdr* incoming_request); > static bool is_request_retryable(State* s); > + > static bool is_response_cacheable(State* s, HTTPHdr* request, HTTPHdr* > response); > static bool is_response_valid(State* s, HTTPHdr* incoming_response); > > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/HttpTransactHeaders.cc > ---------------------------------------------------------------------- > diff --git a/proxy/http/HttpTransactHeaders.cc > b/proxy/http/HttpTransactHeaders.cc > index b5ab0fe..0cebb0f 100644 > --- a/proxy/http/HttpTransactHeaders.cc > +++ b/proxy/http/HttpTransactHeaders.cc > @@ -68,9 +68,12 @@ HttpTransactHeaders::is_this_method_supported(int > the_scheme, int the_method) > { > if (the_method == HTTP_WKSIDX_CONNECT) { > return true; > - } else if (the_scheme == URL_WKSIDX_HTTP || the_scheme == URL_WKSIDX_HTTPS) > + } else if (the_scheme == URL_WKSIDX_HTTP || the_scheme == > URL_WKSIDX_HTTPS) { > return is_this_http_method_supported(the_method); > - else > + } else if ((the_scheme == URL_WKSIDX_WS || the_scheme == URL_WKSIDX_WSS) && > + the_method == HTTP_WKSIDX_GET) { > + return true; > + } else > return false; > } > > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cca82f1b/proxy/http/remap/RemapConfig.cc > ---------------------------------------------------------------------- > diff --git a/proxy/http/remap/RemapConfig.cc b/proxy/http/remap/RemapConfig.cc > index 787fbb0..c138557 100644 > --- a/proxy/http/remap/RemapConfig.cc > +++ b/proxy/http/remap/RemapConfig.cc > @@ -1082,12 +1082,23 @@ remap_parse_config_bti(const char * path, > BUILD_TABLE_INFO * bti) > // includes support for FILE scheme > if ((fromScheme != URL_SCHEME_HTTP && fromScheme != URL_SCHEME_HTTPS && > fromScheme != URL_SCHEME_FILE && > - fromScheme != URL_SCHEME_TUNNEL) || > + fromScheme != URL_SCHEME_TUNNEL && > + fromScheme != URL_SCHEME_WS && > + fromScheme != URL_SCHEME_WSS) || > (toScheme != URL_SCHEME_HTTP && toScheme != URL_SCHEME_HTTPS && > - toScheme != URL_SCHEME_TUNNEL)) { > - errStr = "Only http, https, and tunnel remappings are supported"; > + toScheme != URL_SCHEME_TUNNEL && toScheme != URL_SCHEME_WS && > + toScheme != URL_SCHEME_WSS)) { > + errStr = "Only http, https, ws, wss, and tunnel remappings are > supported"; > goto MAP_ERROR; > } > + > + // If mapping from WS or WSS we must map out to WS or WSS > + if ( (fromScheme == URL_SCHEME_WSS || fromScheme == URL_SCHEME_WS) && > + (toScheme != URL_SCHEME_WSS && toScheme != URL_SCHEME_WS)) { > + errStr = "WS or WSS can only be mapped out to WS or WSS."; > + goto MAP_ERROR; > + } > + > // Check if a tag is specified. > if (bti->paramv[3] != NULL) { > if (maptype == FORWARD_MAP_REFERER) { >