Updated Branches:
  refs/heads/master f0f9cb9c3 -> 60ec95053

[TS-2541] Add WebSocket Support


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 <[email protected]>
Authored: Mon Feb 3 11:10:44 2014 -0800
Committer: Brian Geffon <[email protected]>
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) {

Reply via email to