r47316 - 100% coverage
hawkowl-TA+aISz0psMTMxyoc4vAAJOcrHinNvQL0E9HWUfgJXw@public.gmane.org Mon, 25 Apr 2016 08:10:08 -0600 (MDT)
| Newsgroups | gmane.comp.python.twisted.commits |
|---|---|
| Message-ID | <[email protected]> |
Author: hawkowl
Date: Mon Apr 25 08:09:57 2016
New Revision: 47316
Modified:
branches/proper-upgrade-8301-2/twisted/web/http.py
branches/proper-upgrade-8301-2/twisted/web/server.py
branches/proper-upgrade-8301-2/twisted/web/test/test_http.py
branches/proper-upgrade-8301-2/twisted/web/test/test_web.py
Log:
100% coverage
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 Mon Apr 25 08:09:57 2016
@@ -91,7 +91,7 @@
# twisted imports
from twisted import copyright
from twisted.python.compat import (
- _PY3, unicode, intToBytes, networkString, nativeString, iterbytes)
+ _PY3, unicode, intToBytes, networkString, nativeString)
from twisted.python.deprecate import deprecated
from twisted.python import log
from twisted.python.versions import Version
@@ -2104,6 +2104,7 @@
if requestLine[2].lower() == b"http/1.0":
# It's HTTP/1.0, return that.
+ self._replay = True
return b"http/1.0"
if not requestLine[2].lower() == b"http/1.1":
@@ -2123,6 +2124,7 @@
if b"upgrade" not in headers:
# Regular HTTP/1.1, no "Upgrade"
+ self._replay = True
return b"http/1.1"
for upgrade in headers[b"upgrade"].split(b","):
@@ -2148,6 +2150,7 @@
pass
# Negotiation failed!
+ self._replay = True
return b"http/1.1"
@@ -2166,8 +2169,8 @@
self._negotiatedProtocol = self._upgrade()
self._buffering = False
- if self._negotiatedProtocol in [b"http/1.1", b"http/1.0"]:
- res = self.dataReceived(self._buffer)
+ if self._replay:
+ self.dataReceived(self._buffer)
del self._buffer
@@ -2181,7 +2184,6 @@
return self._bufferData(data)
elif self._negotiatedProtocol is None:
-
try:
# Does ALPN/NPN/some other transport negotiation have the
# protocol the client desires negotiated?
@@ -2195,7 +2197,6 @@
self._channel.transport)
elif negotiatedProtocol in [b"http/1.1", None]:
-
if getattr(self.factory, "_upgradeables"):
# We can upgrade to different protocols through HTTP/1.1
# Upgrade, so we need to check the request to see if it
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 Mon Apr 25 08:09:57 2016
@@ -37,7 +37,7 @@
from twisted.web.http import unquote, _version as version
from twisted.python import log, reflect, failure, components
from twisted.web import resource
-from twisted.web.error import UnsupportedMethod, CannotUpgrade
+from twisted.web.error import UnsupportedMethod
from twisted.python.versions import Version
from twisted.python.deprecate import deprecatedModuleAttribute
Modified: branches/proper-upgrade-8301-2/twisted/web/test/test_http.py
==============================================================================
--- branches/proper-upgrade-8301-2/twisted/web/test/test_http.py (original)
+++ branches/proper-upgrade-8301-2/twisted/web/test/test_http.py Mon Apr 25 08:09:57 2016
@@ -8,7 +8,6 @@
from __future__ import absolute_import, division
import random, cgi, base64
-import math
try:
from urlparse import urlparse, urlunsplit, clear_cache
@@ -22,8 +21,9 @@
from twisted.trial.unittest import TestCase
from twisted.web import http, http_headers
from twisted.web.http import (
- _respondToUpgrade, HTTPFactory, PotentialDataLoss, _DataLoss, _version,
+ HTTPFactory, PotentialDataLoss, _DataLoss, _version,
_IdentityTransferDecoder)
+from twisted.web.error import CannotUpgrade
from twisted.internet.protocol import Protocol, Factory
from twisted.internet.task import Clock
from twisted.internet.error import ConnectionLost
@@ -2537,6 +2537,7 @@
sub(["category", "message"], warnings[0]))
+
class Pitocol(Protocol):
"""
A protocol that writes pi to the transport.
@@ -2546,8 +2547,6 @@
A C{dataReceived} that expects "GO" and will then write out
"3.14" * C{piTimes}. If there's any other data, that won't
"""
- if not protoself.connected:
- self.fail("dataReceived called when disconnected!")
if data == b"GO":
for i in range(piTimes):
protoself.transport.write(b"3.14")
@@ -2571,6 +2570,8 @@
"""
Make a testing suitable L{HTTPFactory} which doesn't rely on a running
reactor.
+
+ @return: A L{HTTPFactory}.
"""
factory = HTTPFactory()
factory._logDateTime = "sometime"
@@ -2585,7 +2586,6 @@
and an "Upgrade" header that lists a protocol we support will be
upgraded to that protocol.
"""
-
class PiUpgrader(object):
def upgrade(self, verb, path, headers):
@@ -2623,6 +2623,52 @@
self.assertTrue(trans.disconnecting)
+ def test_upgradeWithReplay(self):
+ """
+ A HTTP/1.1 request with a "Connection" header that contains "Upgrade"
+ and an "Upgrade" header that lists a protocol we support will be
+ upgraded to that protocol. If the upgrader says it wants a replay of
+ the request, it will be replayed.
+ """
+ val = [
+ b"GET / HTTP/1.1\r\n"
+ b"Connection: keep-alive, Upgrade\r\n",
+ b"Upgrade: replay\r\n\r\n",
+ ]
+
+ class Echo(Protocol):
+ """
+ A protocol that echos back to the transport.
+ """
+ def dataReceived(protoself, data):
+ """
+ Echo out the data.
+ """
+ protoself.transport.write(data)
+
+ echoFactory = Factory()
+ echoFactory.protocol = Echo
+ echoFactory.startFactory()
+
+ class ReplayUpgrader(object):
+
+ def upgrade(self, verb, path, headers):
+ echo = echoFactory.buildProtocol(None)
+ return echo, True, {}
+
+ factory = self._makeFactory()
+ factory._addUpgrader(b"replay", ReplayUpgrader())
+ protocol = factory.buildProtocol(None)
+
+ trans = StringTransport()
+ protocol.makeConnection(trans)
+
+ for x in iterbytes(b"".join(val)):
+ protocol.dataReceived(x)
+
+ self.assertEqual(trans.value(), b"".join(val))
+
+
def test_upgradeNegotiatedHTTP11(self):
"""
A ALPN-negotiated HTTP/1.1 protocol needs to be read and checked for
@@ -2716,8 +2762,8 @@
def test_mangledStatusLine(self):
"""
- A non-HTTP first-line (or a mangled one) will return with a
- "bad request" error.
+ A non-HTTP first-line (or a mangled one) will return with a "bad
+ request" error.
"""
factory = self._makeFactory()
factory._addUpgrader(b"unused", None)
@@ -2737,9 +2783,10 @@
self.assertEqual(trans.value(), expectedValue)
- def test_regularRequest(self):
+ def test_regularRequestHTTP11(self):
"""
- A regular HTTP/1.1 request (that does not want to upgrade) will be passed right through.
+ A regular HTTP/1.1 request (that does not want to upgrade) will be
+ passed right through.
"""
factory = self._makeFactory()
factory._addUpgrader(b"unused", None)
@@ -2749,11 +2796,93 @@
protocol.makeConnection(trans)
val = [
- b"GET/ HTTP/1.1\r\n\r\n",
+ b"GET / HTTP/1.1\r\n"
+ b"Expect: 100-continue\r\n\r\n",
]
for x in iterbytes(b"".join(val)):
protocol.dataReceived(x)
- expectedValue = b"HTTP/1.1 400 Bad Request\r\n\r\n"
+ expectedValue = b"HTTP/1.1 100 Continue\r\n\r\n"
+ self.assertEqual(trans.value(), expectedValue)
+
+
+ def test_regularRequestHTTP10(self):
+ """
+ A regular HTTP/1.0 request (that does not want to upgrade) will be
+ passed right through.
+ """
+ factory = self._makeFactory()
+ factory._addUpgrader(b"unused", None)
+ protocol = factory.buildProtocol(None)
+
+ trans = StringTransport()
+ protocol.makeConnection(trans)
+
+ val = [
+ b"GET / HTTP/1.0\r\n\r\n",
+ ]
+
+ for x in iterbytes(b"".join(val)):
+ protocol.dataReceived(x)
+
+ expectedValue = b""
+ self.assertEqual(trans.value(), expectedValue)
+
+
+ def test_noAvailableUpgrader(self):
+ """
+ An upgrade request that cannot be served with an upgrade (because we
+ don't have it) will continue on as normal without upgrading, per the
+ RFC.
+ """
+ factory = self._makeFactory()
+ factory._addUpgrader(b"someotherprotocol", None)
+ protocol = factory.buildProtocol(None)
+
+ trans = StringTransport()
+ protocol.makeConnection(trans)
+
+ val = [
+ b"GET / HTTP/1.1\r\n"
+ b"Connection: Upgrade\r\n",
+ b"Upgrade: beepboopprotocol\r\n",
+ b"Expect: 100-continue\r\n\r\n",
+ ]
+
+ for x in iterbytes(b"".join(val)):
+ protocol.dataReceived(x)
+
+ expectedValue = b"HTTP/1.1 100 Continue\r\n\r\n"
+ self.assertEqual(trans.value(), expectedValue)
+
+
+ def test_cannotUpgrade(self):
+ """
+ An upgrade request that cannot be served with an upgrade (because the
+ upgrader fails safely) will continue on as normal without upgrading,
+ per the RFC.
+ """
+ class FailingUpgrade(object):
+ def upgrade(self, *args, **kwargs):
+ raise CannotUpgrade()
+
+ factory = self._makeFactory()
+ factory._addUpgrader(b"failing", FailingUpgrade())
+ protocol = factory.buildProtocol(None)
+
+ trans = StringTransport()
+ protocol.makeConnection(trans)
+
+ val = [
+ b"GET / HTTP/1.1\r\n"
+ b"Connection: Upgrade\r\n",
+ b"Upgrade: failing\r\n",
+ b"Expect: 100-continue\r\n\r\n",
+ ]
+
+ for x in iterbytes(b"".join(val)):
+ protocol.dataReceived(x)
+
+ expectedValue = b"HTTP/1.1 100 Continue\r\n\r\n"
self.assertEqual(trans.value(), expectedValue)
Modified: branches/proper-upgrade-8301-2/twisted/web/test/test_web.py
==============================================================================
--- branches/proper-upgrade-8301-2/twisted/web/test/test_web.py (original)
+++ branches/proper-upgrade-8301-2/twisted/web/test/test_web.py Mon Apr 25 08:09:57 2016
@@ -298,7 +298,7 @@
self.channel = self.site.buildProtocol(None)
self.transport = http.StringTransport()
self.transport.close = lambda *a, **kw: None
- self.transport.disconnecting = 0
+ self.transport.disconnecting = lambda *a, **kw: 0
self.transport.getPeer = lambda *a, **kw: "peer"
self.transport.getHost = lambda *a, **kw: "host"
self.channel.makeConnection(self.transport)
@@ -319,7 +319,7 @@
validator = b"If-Modified-Since: " + modifiedSince
else:
validator = b"If-Not-Match: " + etag
- for line in [b"GET / HTTP/1.1", validator, b"\r\n"]:
+ for line in [b"GET / HTTP/1.1", validator, b""]:
self.channel.dataReceived(line + b'\r\n')
result = self.transport.getvalue()
self.assertEqual(httpCode(result), http.OK)