r47308 - merge forward

hawkowl-TA+aISz0psMTMxyoc4vAAJOcrHinNvQL0E9HWUfgJXw@public.gmane.org Sat, 23 Apr 2016 09:28:49 -0600 (MDT)
Newsgroups gmane.comp.python.twisted.commits
Message-ID <[email protected]>
Author: hawkowl
Date: Sat Apr 23 09:28:45 2016
New Revision: 47308

Modified:
   branches/proper-upgrade-8301-2/twisted/web/error.py
   branches/proper-upgrade-8301-2/twisted/web/http.py
   branches/proper-upgrade-8301-2/twisted/web/server.py

Log:
merge forward

Modified: branches/proper-upgrade-8301-2/twisted/web/error.py
==============================================================================
--- branches/proper-upgrade-8301-2/twisted/web/error.py	(original)
+++ branches/proper-upgrade-8301-2/twisted/web/error.py	Sat Apr 23 09:28:45 2016
@@ -385,3 +385,9 @@
 
     def __str__(self):
         return repr(self)
+
+
+class CannotUpgrade(Exception):
+    """
+    Can't do a http upgrade.
+    """

Modified: branches/proper-upgrade-8301-2/twisted/web/http.py
==============================================================================
--- branches/proper-upgrade-8301-2/twisted/web/http.py	(original)
+++ branches/proper-upgrade-8301-2/twisted/web/http.py	Sat Apr 23 09:28:45 2016
@@ -100,6 +100,7 @@
 from twisted.internet.interfaces import IProtocol
 from twisted.protocols import policies, basic
 
+from twisted.web.error import CannotUpgrade
 from twisted.web.iweb import IRequest, IAccessLogFormatter
 from twisted.web.http_headers import Headers
 
@@ -2012,8 +2013,14 @@
     _negotiatedProtocol = None
     _requestFactory = Request
     _site = None
+    _buffering = False
+    _replay = False
 
 
+    def __init__(self, *args, **kwargs):
+        self._buffer = []
+        super(_GenericHTTPChannelProtocol, self).__init__(*args, **kwargs)
+
     @property
     def factory(self):
         """
@@ -2052,17 +2059,65 @@
         self._channel.site = value
 
 
+    def _upgrade(self):
+        """
+        Look at the headers and determine if they want us to upgrade.
+        """
+        content = b"".join(self._buffer).split(b"\r\n\r\n", 1)[0].split("\r\n")
+        headers = {}
+
+        for line in content[1:]:
+            key, val = line.split(b":", 1)
+            headers[key.lower()] = val.lstrip()
+
+        if b"connection" not in headers or b"upgrade" not in headers:
+            print("not negotiating")
+            return b"http/1.1"
+
+        else:
+            if not b"upgrade" in headers[b"connection"].lower().split(b", "):
+                # connection is there and upgrade is there but its not saying to upgrade
+                return b"http/1.1"
+
+            for upgrade in headers[b"upgrade"].split(b", "):
+
+                upgrader = self.site.upgradeables.get(upgrade.lower())
+
+                if upgrader:
+                    try:
+                        self._channel, self._replay = upgrader(self, headers)
+                    except CannotUpgrade:
+                        pass
+
+                return b"http/1.1"
+
+            return None
+
+
+    def _bufferData(self, data):
+
+        self._buffer.append(data)
+        if b"\r\n\r\n" in data:
+            self._negotiatedProtocol = self._upgrade()
+
+            if self._negotiatedProtocol == b"http/1.1":
+                for x in self._buffer:
+                    self._channel.dataReceived(x)
+            self._buffering = False
+            self._buffer = []
+
+
     def dataReceived(self, data):
         """
         A override of L{IProtocol.dataReceived} that checks what protocol we're
         using.
         """
-        if self._negotiatedProtocol is None:
+        if not self._buffering and self._negotiatedProtocol is None:
             try:
                 negotiatedProtocol = self._channel.transport.negotiatedProtocol
             except AttributeError:
-                # Plaintext HTTP, always HTTP/1.1
-                negotiatedProtocol = b'http/1.1'
+                self._buffering = True
+                return self._bufferData(data)
 
             if negotiatedProtocol is None:
                 negotiatedProtocol = b'http/1.1'
@@ -2076,7 +2131,11 @@
 
             self._negotiatedProtocol = negotiatedProtocol
 
-        return self._channel.dataReceived(data)
+        elif self._buffering:
+            self._bufferData(data)
+
+        else:
+            return self._channel.dataReceived(data)
 
 
 

Modified: branches/proper-upgrade-8301-2/twisted/web/server.py
==============================================================================
--- branches/proper-upgrade-8301-2/twisted/web/server.py	(original)
+++ branches/proper-upgrade-8301-2/twisted/web/server.py	Sat Apr 23 09:28:45 2016
@@ -38,7 +38,7 @@
 from twisted.python import log, reflect, failure, components
 from twisted import copyright
 from twisted.web import resource
-from twisted.web.error import UnsupportedMethod
+from twisted.web.error import UnsupportedMethod, CannotUpgrade
 
 from twisted.python.versions import Version
 from twisted.python.deprecate import deprecatedModuleAttribute
@@ -615,6 +615,15 @@
 version = networkString("TwistedWeb/%s" % (copyright.version,))
 
 
+
+def H2C(self, headers):
+    print("Negotiating H2C!")
+
+    raise CannotUpgrade()
+
+    return None, True
+
+
 class Site(http.HTTPFactory):
     """
     A web site: manage log, sessions, and resources.
@@ -647,6 +656,7 @@
         http.HTTPFactory.__init__(self, *args, **kwargs)
         self.sessions = {}
         self.resource = resource
+        self.upgradeables = {}
         if requestFactory is not None:
             self.requestFactory = requestFactory