r46996 - apply patch from lukasa, refs #8193

hawkowl-TA+aISz0psMTMxyoc4vAAJOcrHinNvQL0E9HWUfgJXw@public.gmane.org Tue, 15 Mar 2016 06:47:59 -0600 (MDT)
Newsgroups gmane.comp.python.twisted.commits
Message-ID <[email protected]>
Author: hawkowl
Date: Tue Mar 15 06:47:54 2016
New Revision: 46996

Added:
   branches/httpchannel-proxy-8193-2/twisted/topfiles/8193.misc
Modified:
   branches/httpchannel-proxy-8193-2/twisted/web/http.py
   branches/httpchannel-proxy-8193-2/twisted/web/test/test_web.py

Log:
apply patch from lukasa, refs #8193

Modified: branches/httpchannel-proxy-8193-2/twisted/web/http.py
==============================================================================
--- branches/httpchannel-proxy-8193-2/twisted/web/http.py	(original)
+++ branches/httpchannel-proxy-8193-2/twisted/web/http.py	Tue Mar 15 06:47:54 2016
@@ -97,11 +97,14 @@
 from twisted.python.components import proxyForInterface
 from twisted.internet import interfaces, reactor, protocol, address
 from twisted.internet.defer import Deferred
+from twisted.internet.interfaces import IProtocol
 from twisted.protocols import policies, basic
 
 from twisted.web.iweb import IRequest, IAccessLogFormatter
 from twisted.web.http_headers import Headers
 
+H2_ENABLED = False
+
 from twisted.web._responses import (
     SWITCHING,
 
@@ -1978,6 +1981,88 @@
 
 
 
+class _GenericHTTPChannelProtocol(proxyForInterface(IProtocol, "_channel")):
+    """
+    A proxy object that wraps one of the HTTP protocol objects, and switches
+    between them depending on TLS negotiated protocol.
+
+    @ivar _negotiatedProtocol: The protocol negotiated with ALPN or NPN, if
+        any.
+    @type _negotiatedProtocol: Either a bytestring containing the ALPN token
+        for the negotiated protocol, or C{None} if no protocol has yet been
+        negotiated.
+
+    @ivar _channel: The object capable of behaving like a L{HTTPChannel} that
+        is backing this object. By default this is a L{HTTPChannel}, but if a
+        HTTP protocol upgrade takes place this may be a different channel
+        object. Must implement L{IProtocol}.
+    @type _channel: L{HTTPChannel}
+
+    @ivar _requestFactory: A callable to use to build L{IRequest} objects.
+    @type _requestFactory: L{IRequest}
+
+    @ivar _site: A reference to the creating L{twisted.web.server.Site} object.
+    @type _site: L{twisted.web.server.Site}
+    """
+    _negotiatedProtocol = None
+    _requestFactory = Request
+    _site = None
+
+
+    @property
+    def requestFactory(self):
+        return self._channel.requestFactory
+
+
+    @requestFactory.setter
+    def requestFactory(self, value):
+        self._requestFactory = value
+        self._channel.requestFactory = value
+
+
+    @property
+    def site(self):
+        return self._channel.site
+
+
+    @site.setter
+    def site(self, value):
+        self._site = value
+        self._channel.site = value
+
+
+    def dataReceived(self, data):
+        """
+        A override of L{IProtocol.dataReceived} that checks what protocol we're
+        using.
+        """
+        if self._negotiatedProtocol is None:
+            try:
+                negotiatedProtocol = self.transport.negotiatedProtocol
+            except AttributeError:
+                # Plaintext HTTP, always HTTP/1.1
+                negotiatedProtocol = b'http/1.1'
+
+            if negotiatedProtocol is None:
+                negotiatedProtocol = b'http/1.1'
+
+            if negotiatedProtocol == b'h2' and H2_ENABLED:
+                raise AssertionError("HTTP/2 support is not yet merged.")
+
+            self._negotiatedProtocol = negotiatedProtocol
+
+        return self._channel.dataReceived(data)
+
+
+
+def _genericHTTPChannelProtocolFactory(self):
+    """
+    Returns an appropriately initialized _GenericHTTPChannelProtocol.
+    """
+    return _GenericHTTPChannelProtocol(HTTPChannel())
+
+
+
 class HTTPFactory(protocol.ServerFactory):
     """
     Factory for HTTP server.
@@ -2001,7 +2086,7 @@
         timestamps.
     """
 
-    protocol = HTTPChannel
+    protocol = _genericHTTPChannelProtocolFactory
 
     logPath = None
 

Modified: branches/httpchannel-proxy-8193-2/twisted/web/test/test_web.py
==============================================================================
--- branches/httpchannel-proxy-8193-2/twisted/web/test/test_web.py	(original)
+++ branches/httpchannel-proxy-8193-2/twisted/web/test/test_web.py	Tue Mar 15 06:47:54 2016
@@ -320,7 +320,7 @@
         else:
             validator = b"If-Not-Match: " + etag
         for line in [b"GET / HTTP/1.1", validator, b""]:
-            self.channel.lineReceived(line)
+            self.channel.dataReceived(line + b'\r\n')
         result = self.transport.getvalue()
         self.assertEqual(httpCode(result), http.OK)
         self.assertEqual(httpBody(result), b"correct")
@@ -346,7 +346,7 @@
         """
         for line in [b"GET / HTTP/1.1",
                      b"If-Modified-Since: " + http.datetimeToString(100), b""]:
-            self.channel.lineReceived(line)
+            self.channel.dataReceived(line + b'\r\n')
         result = self.transport.getvalue()
         self.assertEqual(httpCode(result), http.NOT_MODIFIED)
         self.assertEqual(httpBody(result), b"")
@@ -414,7 +414,7 @@
         with an empty response body.
         """
         for line in [b"GET / HTTP/1.1", b"If-None-Match: MatchingTag", b""]:
-            self.channel.lineReceived(line)
+            self.channel.dataReceived(line + b'\r\n')
         result = self.transport.getvalue()
         self.assertEqual(httpHeader(result, b"ETag"), b"MatchingTag")
         self.assertEqual(httpCode(result), http.NOT_MODIFIED)
@@ -432,7 +432,7 @@
         """
         for line in [b"GET /with-content-type HTTP/1.1",
                      b"If-None-Match: MatchingTag", b""]:
-            self.channel.lineReceived(line)
+            self.channel.dataReceived(line + b'\r\n')
         result = self.transport.getvalue()
         self.assertEqual(httpCode(result), http.NOT_MODIFIED)
         self.assertEqual(httpBody(result), b"")
@@ -1311,7 +1311,7 @@
         """
         self.site._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % (
             25, 'Oct', 2004, 12, 31, 59)
-        self.request.requestHeaders.addRawHeader(b'user-agent', 
+        self.request.requestHeaders.addRawHeader(b'user-agent',
                                                  b'Malicious Web" Evil')
         self.assertLogs(
             b'"1.2.3.4" - - [25/Oct/2004:12:31:59 +0000] '