Use unparsed_uri to build Sec-WebSocket-Location header.

Release note: Changed Sec-WebSocket-Location to include the query part.

BUG= https://code.google.com/p/pywebsocket/issues/detail?id=68
Review URL: https://codereview.appspot.com/7568046
diff --git a/src/mod_pywebsocket/handshake/_base.py b/src/mod_pywebsocket/handshake/_base.py
index fdc0ac4..c993a58 100644
--- a/src/mod_pywebsocket/handshake/_base.py
+++ b/src/mod_pywebsocket/handshake/_base.py
@@ -106,7 +106,7 @@
 
 
 def parse_host_header(request):
-    fields = request.headers_in['Host'].split(':', 1)
+    fields = request.headers_in[common.HOST_HEADER].split(':', 1)
     if len(fields) == 1:
         return fields[0], get_default_port(request.is_https())
     try:
diff --git a/src/mod_pywebsocket/handshake/hybi00.py b/src/mod_pywebsocket/handshake/hybi00.py
index 26d153e..8757717 100644
--- a/src/mod_pywebsocket/handshake/hybi00.py
+++ b/src/mod_pywebsocket/handshake/hybi00.py
@@ -112,7 +112,7 @@
     if (port != get_default_port(request.is_https())):
         location_parts.append(':')
         location_parts.append(str(port))
-    location_parts.append(request.uri)
+    location_parts.append(request.unparsed_uri)
     return ''.join(location_parts)
 
 
diff --git a/src/mod_pywebsocket/standalone.py b/src/mod_pywebsocket/standalone.py
index dba1d68..e9f0837 100755
--- a/src/mod_pywebsocket/standalone.py
+++ b/src/mod_pywebsocket/standalone.py
@@ -226,11 +226,23 @@
         self.headers_in = request_handler.headers
 
     def get_uri(self):
-        """Getter to mimic request.uri."""
+        """Getter to mimic request.uri.
+
+        This method returns the raw data at the Request-URI part of the
+        Request-Line, while the uri method on the request object of mod_python
+        returns the path portion after parsing the raw data. This behavior is
+        kept for compatibility.
+        """
 
         return self._request_handler.path
     uri = property(get_uri)
 
+    def get_unparsed_uri(self):
+        """Getter to mimic request.unparsed_uri."""
+
+        return self._request_handler.path
+    unparsed_uri = property(get_unparsed_uri)
+
     def get_method(self):
         """Getter to mimic request.method."""
 
diff --git a/src/test/mock.py b/src/test/mock.py
index 02d8371..b4757cc 100644
--- a/src/test/mock.py
+++ b/src/test/mock.py
@@ -186,6 +186,7 @@
         See the document of mod_python Request for details.
         """
         self.uri = uri
+        self.unparsed_uri = uri
         self.connection = connection
         self.method = method
         self.protocol = protocol
diff --git a/src/test/test_handshake_hybi00.py b/src/test/test_handshake_hybi00.py
index 7818faf..73f9f27 100755
--- a/src/test/test_handshake_hybi00.py
+++ b/src/test/test_handshake_hybi00.py
@@ -43,6 +43,12 @@
 from test import mock
 
 
+_TEST_KEY1 = '4 @1  46546xW%0l 1 5'
+_TEST_KEY2 = '12998 5 Y3 1  .P00'
+_TEST_KEY3 = '^n:ds[4U'
+_TEST_CHALLENGE_RESPONSE = '8jKS\'y:G*Co,Wxa-'
+
+
 _GOOD_REQUEST = (
     80,
     'GET',
@@ -50,13 +56,13 @@
     {
         'Host': 'example.com',
         'Connection': 'Upgrade',
-        'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+        'Sec-WebSocket-Key2': _TEST_KEY2,
         'Sec-WebSocket-Protocol': 'sample',
         'Upgrade': 'WebSocket',
-        'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+        'Sec-WebSocket-Key1': _TEST_KEY1,
         'Origin': 'http://example.com',
     },
-    '^n:ds[4U')
+    _TEST_KEY3)
 
 _GOOD_REQUEST_CAPITALIZED_HEADER_VALUES = (
     80,
@@ -65,13 +71,28 @@
     {
         'Host': 'example.com',
         'Connection': 'UPGRADE',
-        'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+        'Sec-WebSocket-Key2': _TEST_KEY2,
         'Sec-WebSocket-Protocol': 'sample',
         'Upgrade': 'WEBSOCKET',
-        'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+        'Sec-WebSocket-Key1': _TEST_KEY1,
         'Origin': 'http://example.com',
     },
-    '^n:ds[4U')
+    _TEST_KEY3)
+
+_GOOD_REQUEST_CASE_MIXED_HEADER_NAMES = (
+    80,
+    'GET',
+    '/demo',
+    {
+        'hOsT': 'example.com',
+        'cOnNeCtIoN': 'Upgrade',
+        'sEc-wEbsOcKeT-kEy2': _TEST_KEY2,
+        'sEc-wEbsOcKeT-pRoToCoL': 'sample',
+        'uPgRaDe': 'WebSocket',
+        'sEc-wEbsOcKeT-kEy1': _TEST_KEY1,
+        'oRiGiN': 'http://example.com',
+    },
+    _TEST_KEY3)
 
 _GOOD_RESPONSE_DEFAULT_PORT = (
     'HTTP/1.1 101 WebSocket Protocol Handshake\r\n'
@@ -80,8 +101,8 @@
     'Sec-WebSocket-Location: ws://example.com/demo\r\n'
     'Sec-WebSocket-Origin: http://example.com\r\n'
     'Sec-WebSocket-Protocol: sample\r\n'
-    '\r\n'
-    '8jKS\'y:G*Co,Wxa-')
+    '\r\n' +
+    _TEST_CHALLENGE_RESPONSE)
 
 _GOOD_RESPONSE_SECURE = (
     'HTTP/1.1 101 WebSocket Protocol Handshake\r\n'
@@ -90,8 +111,8 @@
     'Sec-WebSocket-Location: wss://example.com/demo\r\n'
     'Sec-WebSocket-Origin: http://example.com\r\n'
     'Sec-WebSocket-Protocol: sample\r\n'
-    '\r\n'
-    '8jKS\'y:G*Co,Wxa-')
+    '\r\n' +
+    _TEST_CHALLENGE_RESPONSE)
 
 _GOOD_REQUEST_NONDEFAULT_PORT = (
     8081,
@@ -100,13 +121,13 @@
     {
         'Host': 'example.com:8081',
         'Connection': 'Upgrade',
-        'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+        'Sec-WebSocket-Key2': _TEST_KEY2,
         'Sec-WebSocket-Protocol': 'sample',
         'Upgrade': 'WebSocket',
-        'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+        'Sec-WebSocket-Key1': _TEST_KEY1,
         'Origin': 'http://example.com',
     },
-    '^n:ds[4U')
+    _TEST_KEY3)
 
 _GOOD_RESPONSE_NONDEFAULT_PORT = (
     'HTTP/1.1 101 WebSocket Protocol Handshake\r\n'
@@ -115,8 +136,8 @@
     'Sec-WebSocket-Location: ws://example.com:8081/demo\r\n'
     'Sec-WebSocket-Origin: http://example.com\r\n'
     'Sec-WebSocket-Protocol: sample\r\n'
-    '\r\n'
-    '8jKS\'y:G*Co,Wxa-')
+    '\r\n' +
+    _TEST_CHALLENGE_RESPONSE)
 
 _GOOD_RESPONSE_SECURE_NONDEF = (
     'HTTP/1.1 101 WebSocket Protocol Handshake\r\n'
@@ -125,8 +146,8 @@
     'Sec-WebSocket-Location: wss://example.com:8081/demo\r\n'
     'Sec-WebSocket-Origin: http://example.com\r\n'
     'Sec-WebSocket-Protocol: sample\r\n'
-    '\r\n'
-    '8jKS\'y:G*Co,Wxa-')
+    '\r\n' +
+    _TEST_CHALLENGE_RESPONSE)
 
 _GOOD_REQUEST_NO_PROTOCOL = (
     80,
@@ -135,12 +156,12 @@
     {
         'Host': 'example.com',
         'Connection': 'Upgrade',
-        'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+        'Sec-WebSocket-Key2': _TEST_KEY2,
         'Upgrade': 'WebSocket',
-        'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+        'Sec-WebSocket-Key1': _TEST_KEY1,
         'Origin': 'http://example.com',
     },
-    '^n:ds[4U')
+    _TEST_KEY3)
 
 _GOOD_RESPONSE_NO_PROTOCOL = (
     'HTTP/1.1 101 WebSocket Protocol Handshake\r\n'
@@ -148,8 +169,8 @@
     'Connection: Upgrade\r\n'
     'Sec-WebSocket-Location: ws://example.com/demo\r\n'
     'Sec-WebSocket-Origin: http://example.com\r\n'
-    '\r\n'
-    '8jKS\'y:G*Co,Wxa-')
+    '\r\n' +
+    _TEST_CHALLENGE_RESPONSE)
 
 _GOOD_REQUEST_WITH_OPTIONAL_HEADERS = (
     80,
@@ -158,15 +179,15 @@
     {
         'Host': 'example.com',
         'Connection': 'Upgrade',
-        'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+        'Sec-WebSocket-Key2': _TEST_KEY2,
         'EmptyValue': '',
         'Sec-WebSocket-Protocol': 'sample',
         'AKey': 'AValue',
         'Upgrade': 'WebSocket',
-        'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+        'Sec-WebSocket-Key1': _TEST_KEY1,
         'Origin': 'http://example.com',
     },
-    '^n:ds[4U')
+    _TEST_KEY3)
 
 # TODO(tyoshino): Include \r \n in key3, challenge response.
 
@@ -196,6 +217,31 @@
     ''.join(map(chr, [0x0b, 0x99, 0xfa, 0x55, 0xbd, 0x01, 0x23, 0x7b,
                       0x45, 0xa2, 0xf1, 0xd0, 0x87, 0x8a, 0xee, 0xeb])))
 
+_GOOD_REQUEST_WITH_QUERY_PART = (
+    80,
+    'GET',
+    '/demo?e=mc2',
+    {
+        'Host': 'example.com',
+        'Connection': 'Upgrade',
+        'Sec-WebSocket-Key2': _TEST_KEY2,
+        'Sec-WebSocket-Protocol': 'sample',
+        'Upgrade': 'WebSocket',
+        'Sec-WebSocket-Key1': _TEST_KEY1,
+        'Origin': 'http://example.com',
+    },
+    _TEST_KEY3)
+
+_GOOD_RESPONSE_WITH_QUERY_PART = (
+    'HTTP/1.1 101 WebSocket Protocol Handshake\r\n'
+    'Upgrade: WebSocket\r\n'
+    'Connection: Upgrade\r\n'
+    'Sec-WebSocket-Location: ws://example.com/demo?e=mc2\r\n'
+    'Sec-WebSocket-Origin: http://example.com\r\n'
+    'Sec-WebSocket-Protocol: sample\r\n'
+    '\r\n' +
+    _TEST_CHALLENGE_RESPONSE)
+
 _BAD_REQUESTS = (
     (  # HTTP request
         80,
@@ -221,13 +267,13 @@
         {
             'Host': 'example.com',
             'Connection': 'Upgrade',
-            'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+            'Sec-WebSocket-Key2': _TEST_KEY2,
             'Sec-WebSocket-Protocol': 'sample',
             'Upgrade': 'WebSocket',
-            'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+            'Sec-WebSocket-Key1': _TEST_KEY1,
             'Origin': 'http://example.com',
         },
-        '^n:ds[4U'),
+        _TEST_KEY3),
     (  # Missing Upgrade
         80,
         'GET',
@@ -235,12 +281,12 @@
         {
             'Host': 'example.com',
             'Connection': 'Upgrade',
-            'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+            'Sec-WebSocket-Key2': _TEST_KEY2,
             'Sec-WebSocket-Protocol': 'sample',
-            'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+            'Sec-WebSocket-Key1': _TEST_KEY1,
             'Origin': 'http://example.com',
         },
-        '^n:ds[4U'),
+        _TEST_KEY3),
     (  # Wrong Upgrade
         80,
         'GET',
@@ -248,13 +294,13 @@
         {
             'Host': 'example.com',
             'Connection': 'Upgrade',
-            'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+            'Sec-WebSocket-Key2': _TEST_KEY2,
             'Sec-WebSocket-Protocol': 'sample',
             'Upgrade': 'NonWebSocket',
-            'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+            'Sec-WebSocket-Key1': _TEST_KEY1,
             'Origin': 'http://example.com',
         },
-        '^n:ds[4U'),
+        _TEST_KEY3),
     (  # Empty WebSocket-Protocol
         80,
         'GET',
@@ -262,13 +308,13 @@
         {
             'Host': 'example.com',
             'Connection': 'Upgrade',
-            'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+            'Sec-WebSocket-Key2': _TEST_KEY2,
             'Sec-WebSocket-Protocol': '',
             'Upgrade': 'WebSocket',
-            'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+            'Sec-WebSocket-Key1': _TEST_KEY1,
             'Origin': 'http://example.com',
         },
-        '^n:ds[4U'),
+        _TEST_KEY3),
     (  # Wrong port number format
         80,
         'GET',
@@ -276,13 +322,13 @@
         {
             'Host': 'example.com:0x50',
             'Connection': 'Upgrade',
-            'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+            'Sec-WebSocket-Key2': _TEST_KEY2,
             'Sec-WebSocket-Protocol': 'sample',
             'Upgrade': 'WebSocket',
-            'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+            'Sec-WebSocket-Key1': _TEST_KEY1,
             'Origin': 'http://example.com',
         },
-        '^n:ds[4U'),
+        _TEST_KEY3),
     (  # Header/connection port mismatch
         8080,
         'GET',
@@ -290,13 +336,13 @@
         {
             'Host': 'example.com',
             'Connection': 'Upgrade',
-            'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+            'Sec-WebSocket-Key2': _TEST_KEY2,
             'Sec-WebSocket-Protocol': 'sample',
             'Upgrade': 'WebSocket',
-            'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+            'Sec-WebSocket-Key1': _TEST_KEY1,
             'Origin': 'http://example.com',
         },
-        '^n:ds[4U'),
+        _TEST_KEY3),
     (  # Illegal WebSocket-Protocol
         80,
         'GET',
@@ -304,13 +350,13 @@
         {
             'Host': 'example.com',
             'Connection': 'Upgrade',
-            'Sec-WebSocket-Key2': '12998 5 Y3 1  .P00',
+            'Sec-WebSocket-Key2': _TEST_KEY2,
             'Sec-WebSocket-Protocol': 'illegal\x09protocol',
             'Upgrade': 'WebSocket',
-            'Sec-WebSocket-Key1': '4 @1  46546xW%0l 1 5',
+            'Sec-WebSocket-Key1': _TEST_KEY1,
             'Origin': 'http://example.com',
         },
-        '^n:ds[4U'),
+        _TEST_KEY3),
 )
 
 
@@ -365,6 +411,13 @@
         self.assertEqual(_GOOD_RESPONSE_DEFAULT_PORT,
                          request.connection.written_data())
 
+    def test_good_request_case_mixed_header_names(self):
+        request = _create_request(_GOOD_REQUEST_CASE_MIXED_HEADER_NAMES)
+        handshaker = Handshaker(request, mock.MockDispatcher())
+        handshaker.do_handshake()
+        self.assertEqual(_GOOD_RESPONSE_DEFAULT_PORT,
+                         request.connection.written_data())
+
     def test_good_request_secure_default_port(self):
         request = _create_request(_GOOD_REQUEST)
         request.connection.local_addr = ('0.0.0.0', 443)
@@ -418,6 +471,14 @@
                          request.connection.written_data())
         self.assertEqual('sample', request.ws_protocol)
 
+    def test_good_request_with_query_part(self):
+        request = _create_request(_GOOD_REQUEST_WITH_QUERY_PART)
+        handshaker = Handshaker(request, mock.MockDispatcher())
+        handshaker.do_handshake()
+        self.assertEqual(_GOOD_RESPONSE_WITH_QUERY_PART,
+                         request.connection.written_data())
+        self.assertEqual('ws://example.com/demo?e=mc2', request.ws_location)
+
     def test_bad_requests(self):
         for request in map(_create_request, _BAD_REQUESTS):
             handshaker = Handshaker(request, mock.MockDispatcher())