r47053 - apply patch from lukasa, refs #8191
hawkowl-TA+aISz0psMTMxyoc4vAAJOcrHinNvQL0E9HWUfgJXw@public.gmane.org Tue, 22 Mar 2016 08:34:40 -0600 (MDT)
| Newsgroups | gmane.comp.python.twisted.commits |
|---|---|
| Message-ID | <[email protected]> |
Author: hawkowl
Date: Tue Mar 22 08:34:35 2016
New Revision: 47053
Added:
branches/hide-request-transport-8191-3/twisted/web/topfiles/8191.misc
Modified:
branches/hide-request-transport-8191-3/twisted/web/http.py
branches/hide-request-transport-8191-3/twisted/web/server.py
branches/hide-request-transport-8191-3/twisted/web/test/requesthelper.py
branches/hide-request-transport-8191-3/twisted/web/test/test_http.py
branches/hide-request-transport-8191-3/twisted/web/test/test_proxy.py
branches/hide-request-transport-8191-3/twisted/web/test/test_web.py
branches/hide-request-transport-8191-3/twisted/web/wsgi.py
Log:
apply patch from lukasa, refs #8191
Modified: branches/hide-request-transport-8191-3/twisted/web/http.py
==============================================================================
--- branches/hide-request-transport-8191-3/twisted/web/http.py (original)
+++ branches/hide-request-transport-8191-3/twisted/web/http.py Tue Mar 22 08:34:35 2016
@@ -91,7 +91,8 @@
# twisted imports
from twisted.python.compat import (
_PY3, unicode, intToBytes, networkString, nativeString)
-from twisted.python.deprecate import deprecated
+from twisted.python.constants import NamedConstant, Names
+from twisted.python.deprecate import deprecated, deprecatedProperty
from twisted.python import log
from twisted.python.versions import Version
from twisted.python.components import proxyForInterface
@@ -568,6 +569,16 @@
which this request was received is closed and which is C{True} after
that.
@type _disconnected: C{bool}
+
+ @ivar _queuedHeaders: A C{tuple} of items that would normally be passed to
+ L{HTTPChannel.writeHeaders}. Used when the response is queued to store
+ the eventual headers.
+ @type _queuedHeaders: A C{tuple} of HTTP version (C{bytes}), status code
+ (C{int}), reason phrase (C{bytes}), and headers (C{list} of C{tuple}s
+ of C{(bytes, bytes)}.
+
+ @ivar _send100: Whether to send a 100-Continue response when unqueued.
+ @type _send100: C{bool}
"""
producer = None
finished = 0
@@ -586,6 +597,8 @@
content = None
_forceSSL = 0
_disconnected = False
+ _queuedHeaders = None
+ _send100 = False
def __init__(self, channel, queued):
"""
@@ -594,7 +607,7 @@
the transport?
"""
self.notifications = []
- self.channel = channel
+ self._channel = channel
self.queued = queued
self.requestHeaders = Headers()
self.received_cookies = {}
@@ -602,9 +615,29 @@
self.cookies = [] # outgoing cookies
if queued:
- self.transport = StringTransport()
+ self._transport = StringTransport()
else:
- self.transport = self.channel.transport
+ self._transport = self._channel
+
+
+ @deprecatedProperty(Version('Twisted', 16, 1, 0))
+ def transport(self):
+ return self._transport
+
+
+ @transport.setter
+ def transport(self, value):
+ self._transport = value
+
+
+ @deprecatedProperty(Version('Twisted', 16, 1, 0))
+ def channel(self):
+ return self._channel
+
+
+ @channel.setter
+ def channel(self, value):
+ self._channel = value
def _cleanup(self):
@@ -614,8 +647,8 @@
if self.producer:
log.err(RuntimeError("Producer was not unregistered for %s" % self.uri))
self.unregisterProducer()
- self.channel.requestDone(self)
- del self.channel
+ self._channel.requestDone(self)
+ del self._channel
try:
self.content.close()
except OSError:
@@ -642,14 +675,19 @@
self.queued = 0
# set transport to real one and send any buffer data
- data = self.transport.getvalue()
- self.transport = self.channel.transport
+ data = self._transport.getvalue()
+ self._transport = self._channel
+ if self._send100:
+ self.channel._send100Continue()
+ if self._queuedHeaders:
+ self._transport.writeHeaders(*self._queuedHeaders)
+ self._queuedHeaders = None
if data:
- self.transport.write(data)
+ self._transport.write(data)
# if we have producer, register it with transport
if (self.producer is not None) and not self.finished:
- self.transport.registerProducer(self.producer, self.streamingProducer)
+ self._transport.registerProducer(self.producer, self.streamingProducer)
# if we're finished, clean up
if self.finished:
@@ -733,8 +771,8 @@
# cache the client and server information, we'll need this later to be
# serialized and sent with the request so CGIs will work remotely
- self.client = self.channel.transport.getPeer()
- self.host = self.channel.transport.getHost()
+ self.client = self._channel.getPeer()
+ self.host = self._channel.getHost()
# Argument processing
args = self.args
@@ -761,7 +799,7 @@
self.args.update(cgiArgs)
except:
# It was a bad request.
- _respondToBadRequestAndDisconnect(self.channel.transport)
+ self._channel._respondToBadRequestAndDisconnect()
return
self.content.seek(0, 0)
@@ -811,14 +849,14 @@
if streaming:
producer.pauseProducing()
else:
- self.transport.registerProducer(producer, streaming)
+ self._channel.registerProducer(producer, streaming)
def unregisterProducer(self):
"""
Unregister the producer.
"""
if not self.queued:
- self.transport.unregisterProducer()
+ self._channel.unregisterProducer()
self.producer = None
@@ -880,11 +918,11 @@
if self.chunked:
# write last chunk and closing CRLF
- self.transport.write(b"0\r\n\r\n")
+ self._transport.write(b"0\r\n\r\n")
# log request
- if hasattr(self.channel, "factory"):
- self.channel.factory.log(self)
+ if hasattr(self._channel, "factory"):
+ self._channel.factory.log(self)
self.finished = 1
if not self.queued:
@@ -905,11 +943,10 @@
if not self.startedWriting:
self.startedWriting = 1
version = self.clientproto
- l = []
- l.append(
- version + b" " +
- intToBytes(self.code) + b" " +
- self.code_message + b"\r\n")
+ code = intToBytes(self.code)
+ reason = self.code_message
+
+ headers = []
# if we don't have a content length, we send data in
# chunked mode, so that we can support pipelining in
@@ -917,7 +954,7 @@
if ((version == b"HTTP/1.1") and
(self.responseHeaders.getRawHeaders(b'content-length') is None) and
self.method != b"HEAD" and self.code not in NO_BODY_CODES):
- l.append(b'Transfer-Encoding: chunked\r\n')
+ headers.append((b'Transfer-Encoding', 'chunked'))
self.chunked = 1
if self.lastModified is not None:
@@ -941,14 +978,15 @@
category=DeprecationWarning, stacklevel=2)
# Backward compatible cast for non-bytes values
value = networkString('%s' % (value,))
- l.extend([name, b": ", value, b"\r\n"])
+ headers.append((name, value))
for cookie in self.cookies:
- l.append(b'Set-Cookie: ' + cookie + b'\r\n')
+ headers.append((b'Set-Cookie', cookie))
- l.append(b"\r\n")
-
- self.transport.writeSequence(l)
+ if self.queued:
+ self._queuedHeaders = (version, code, reason, headers)
+ else:
+ self._channel.writeHeaders(version, code, reason, headers)
# if this is a "HEAD" request, we shouldn't return any data
if self.method == b"HEAD":
@@ -963,9 +1001,9 @@
self.sentLength = self.sentLength + len(data)
if data:
if self.chunked:
- self.transport.writeSequence(toChunk(data))
+ self._transport.writeSequence(toChunk(data))
else:
- self.transport.write(data)
+ self._transport.write(data)
def addCookie(self, k, v, expires=None, domain=None, path=None,
max_age=None, comment=None, secure=None, httpOnly=False):
@@ -1264,7 +1302,9 @@
"""
if self._forceSSL:
return True
- transport = getattr(getattr(self, 'channel', None), 'transport', None)
+ transport = getattr(
+ getattr(self, '_channel', None), 'transport', None
+ )
if interfaces.ISSLTransport(transport, None) is not None:
return True
return False
@@ -1339,13 +1379,31 @@
Clean up anything which can't be useful anymore.
"""
self._disconnected = True
- self.channel = None
+ self._channel = None
if self.content is not None:
self.content.close()
for d in self.notifications:
d.errback(reason)
self.notifications = []
+
+ def loseConnection(self):
+ """
+ Pass the loseConnection through to the underlying channel.
+ """
+ self._channel.loseConnection()
+
+
+ def _send100Continue(self):
+ """
+ Sends a "100 Continue" status code, where 100 Continue is supported.
+ """
+ if not self.queued:
+ self._channel._send100Continue()
+ else:
+ self._send100 = True
+
+
Request.getClient = deprecated(
Version("Twisted", 15, 0, 0),
"Twisted Names to resolve hostnames")(Request.getClient)
@@ -1585,6 +1643,24 @@
+class _ChannelSendState(Names):
+ """
+ Defines a collection of states that indicate what portion of a HTTP
+ response has already been sent on L{HTTPChannel}. Used to enforce that
+ callers of methods on the L{HTTPChannel} are calling them at the
+ appropriate times and to prevent callers from sending invalid HTTP
+ responses.
+
+ The state of the channel send state goes from IDLE (the previous response
+ is complete), optionally to SENT_100_CONTINUE, and then to SENT_HEADERS.
+ When the response is complete, the state is reset to IDLE.
+ """
+ IDLE = NamedConstant()
+ SENT_100_CONTINUE = NamedConstant()
+ SENT_HEADERS = NamedConstant()
+
+
+
class HTTPChannel(basic.LineReceiver, policies.TimeoutMixin):
"""
A receiver for HTTP requests.
@@ -1627,6 +1703,7 @@
# the request queue
self.requests = []
self._transferDecoder = None
+ self._sendState = _ChannelSendState.IDLE
def connectionMade(self):
@@ -1642,7 +1719,7 @@
self._receivedHeaderSize += len(line)
if (self._receivedHeaderSize > self.totalHeadersSize):
- _respondToBadRequestAndDisconnect(self.transport)
+ self._respondToBadRequestAndDisconnect()
return
if self.__first_line:
@@ -1666,13 +1743,13 @@
parts = line.split()
if len(parts) != 3:
- _respondToBadRequestAndDisconnect(self.transport)
+ self._respondToBadRequestAndDisconnect()
return
command, request, version = parts
try:
command.decode("ascii")
except UnicodeDecodeError:
- _respondToBadRequestAndDisconnect(self.transport)
+ self._respondToBadRequestAndDisconnect()
return
self._command = command
@@ -1721,7 +1798,7 @@
try:
self.length = int(data)
except ValueError:
- _respondToBadRequestAndDisconnect(self.transport)
+ self._respondToBadRequestAndDisconnect()
self.length = None
return
self._transferDecoder = _IdentityTransferDecoder(
@@ -1741,7 +1818,7 @@
self._receivedHeaderCount += 1
if self._receivedHeaderCount > self.maxHeaders:
- _respondToBadRequestAndDisconnect(self.transport)
+ self._respondToBadRequestAndDisconnect()
return
@@ -1772,7 +1849,7 @@
try:
self._transferDecoder.dataReceived(data)
except _MalformedChunkedDataError:
- _respondToBadRequestAndDisconnect(self.transport)
+ self._respondToBadRequestAndDisconnect()
def allHeadersReceived(self):
@@ -1785,7 +1862,7 @@
expectContinue = req.requestHeaders.getRawHeaders(b'expect')
if (expectContinue and expectContinue[0].lower() == b'100-continue' and
self._version == b'HTTP/1.1'):
- req.transport.write(b"HTTP/1.1 100 Continue\r\n\r\n")
+ req._send100Continue()
def checkPersistence(self, request, version):
@@ -1840,6 +1917,8 @@
del self.requests[0]
if self.persistent:
+ self._sendState = _ChannelSendState.IDLE
+
# notify next request it can start writing
if self.requests:
self.requests[0].noLongerQueued()
@@ -1859,20 +1938,126 @@
request.connectionLost(reason)
+ def writeHeaders(self, version, code, reason, headers):
+ """
+ Called by C{Request} objects to write a complete set of HTTP headers to
+ a transport.
-def _respondToBadRequestAndDisconnect(transport):
- """
- This is a quick and dirty way of responding to bad requests.
+ @param version: The HTTP version in use.
+ @type version: C{bytes}
- As described by HTTP standard we should be patient and accept the
- whole request from the client before sending a polite bad request
- response, even in the case when clients send tons of data.
+ @param code: The HTTP status code to write.
+ @type code: C{bytes}
- @param transport: Transport handling connection to the client.
- @type transport: L{interfaces.ITransport}
- """
- transport.write(b"HTTP/1.1 400 Bad Request\r\n\r\n")
- transport.loseConnection()
+ @param reason: The HTTP reason phrase to write.
+ @type reason: C{bytes}
+
+ @param headers: The headers to write to the transport.
+ @type headers: L{twisted.web.http_headers.Headers}
+ """
+ assert self._sendState in (
+ _ChannelSendState.IDLE, _ChannelSendState.SENT_100_CONTINUE
+ )
+ response_line = version + b" " + code + b" " + reason + b"\r\n"
+ headerSequence = [response_line]
+ headerSequence.extend(
+ name + b': ' + value + b"\r\n" for name, value in headers
+ )
+ headerSequence.append("\r\n")
+ self.transport.writeSequence(headerSequence)
+ self._sendState = _ChannelSendState.SENT_HEADERS
+
+
+ def registerProducer(self, producer, streaming):
+ """
+ @see L{IConsumer.registerProducer}
+ """
+ return self.transport.registerProducer(producer, streaming)
+
+
+ def unregisterProducer(self):
+ """
+ @see L{IConsumer.unregisterProducer}
+ """
+ return self.transport.unregisterProducer()
+
+
+ def write(self, data):
+ """
+ Called by C{Request} objects to write response data.
+
+ @param data: The data chunk to write to the stream.
+ @type data: C{bytes}
+ """
+ assert self._sendState == _ChannelSendState.SENT_HEADERS
+ self.transport.write(data)
+
+
+ def writeSequence(self, iovec):
+ """
+ Write a list of strings to the HTTP response.
+
+ @param iovec: A list of byte strings to write to the stream.
+ @type data: C{list} of C{bytes}
+ """
+ assert self._sendState == _ChannelSendState.SENT_HEADERS
+ self.transport.writeSequence(iovec)
+
+
+ def getPeer(self):
+ """
+ Get the remote address of this connection.
+
+ @return: An L{IAddress} provider.
+ """
+ return self.transport.getPeer()
+
+
+ def getHost(self):
+ """
+ Get the local address of this connection.
+
+ @return: An L{IAddress} provider.
+ """
+ return self.transport.getHost()
+
+
+ def loseConnection(self):
+ """
+ Closes the connection. Will write any data that is pending to be sent
+ on the network, but if this response has not yet been written to the
+ network will not write anything.
+ """
+ # TODO: Does this need to be smarter, particularly about queued
+ # responses?
+ return self.transport.loseConnection()
+
+
+ def _send100Continue(self):
+ """
+ Sends a 100 Continue response, used to signal to clients that further
+ processing will be performed.
+ """
+ assert self._sendState == _ChannelSendState.IDLE
+ self.transport.write(b"HTTP/1.1 100 Continue\r\n\r\n")
+ self._sendState = _ChannelSendState.SENT_100_CONTINUE
+
+
+ def _respondToBadRequestAndDisconnect(self):
+ """
+ This is a quick and dirty way of responding to bad requests.
+
+ As described by HTTP standard we should be patient and accept the
+ whole request from the client before sending a polite bad request
+ response, even in the case when clients send tons of data.
+ """
+ # FIXME: There is nothing in this method to ensure that the response it
+ # sends is not intermingled with some other response body being written
+ # at the same time. Clearly this isn't the end of the world: the method
+ # has been arund a little while. Still, this should probably be
+ # refactored.
+ self.transport.write(b"HTTP/1.1 400 Bad Request\r\n\r\n")
+ self.transport.loseConnection()
Modified: branches/hide-request-transport-8191-3/twisted/web/server.py
==============================================================================
--- branches/hide-request-transport-8191-3/twisted/web/server.py (original)
+++ branches/hide-request-transport-8191-3/twisted/web/server.py Tue Mar 22 08:34:35 2016
@@ -110,10 +110,10 @@
def getStateToCopyFor(self, issuer):
x = self.__dict__.copy()
- del x['transport']
+ del x['_transport']
# XXX refactor this attribute out; it's from protocol
# del x['server']
- del x['channel']
+ del x['_channel']
del x['content']
del x['site']
self.content.seek(0, 0)
@@ -164,7 +164,7 @@
"""
# get site from channel
- self.site = self.channel.site
+ self.site = self._channel.site
# set various default headers
self.setHeader(b'server', version)
Modified: branches/hide-request-transport-8191-3/twisted/web/test/requesthelper.py
==============================================================================
--- branches/hide-request-transport-8191-3/twisted/web/test/requesthelper.py (original)
+++ branches/hide-request-transport-8191-3/twisted/web/test/requesthelper.py Tue Mar 22 08:34:35 2016
@@ -53,6 +53,9 @@
def registerProducer(self, producer, streaming):
self.producers.append((producer, streaming))
+ def unregisterProducer(self):
+ pass
+
def loseConnection(self):
self.disconnected = True
@@ -71,6 +74,53 @@
pass
+ def writeHeaders(self, version, code, reason, headers):
+ response_line = version + b" " + code + b" " + reason + b"\r\n"
+ headerSequence = [response_line]
+ headerSequence.extend(
+ name + b': ' + value + b"\r\n" for name, value in headers
+ )
+ headerSequence.append("\r\n")
+ self.transport.writeSequence(headerSequence)
+
+
+ def getPeer(self):
+ return self.transport.getPeer()
+
+
+ def getHost(self):
+ return self.transport.getHost()
+
+
+ def registerProducer(self, producer, streaming):
+ self.transport.registerProducer(producer, streaming)
+
+
+ def unregisterProducer(self):
+ self.transport.unregisterProducer()
+
+
+ def write(self, data):
+ self.transport.write(data)
+
+
+ def writeSequence(self, iovec):
+ self.transport.writeSequence(iovec)
+
+
+ def loseConnection(self):
+ self.transport.loseConnection()
+
+
+ def endRequest(self):
+ pass
+
+
+ @property
+ def producers(self):
+ return self.transport.producers
+
+
class DummyRequest(object):
"""
Modified: branches/hide-request-transport-8191-3/twisted/web/test/test_http.py
==============================================================================
--- branches/hide-request-transport-8191-3/twisted/web/test/test_http.py (original)
+++ branches/hide-request-transport-8191-3/twisted/web/test/test_http.py Tue Mar 22 08:34:35 2016
@@ -59,6 +59,7 @@
self.finish()
+
class LoopbackHTTPClient(http.HTTPClient):
def connectionMade(self):
@@ -323,6 +324,104 @@
+class ResponseWriteOrderingTests(unittest.TestCase):
+ requests = (
+ b"GET / HTTP/1.1\r\n"
+ b"Accept: text/html\r\n"
+ b"\r\n"
+ b"GET / HTTP/1.1\r\n"
+ b"\r\n")
+
+
+ def setUp(self):
+ self.transport = StringTransport()
+ self.channel = http.HTTPChannel()
+ self.channel.requestFactory = http.Request
+ self.channel.makeConnection(self.transport)
+ self.channel.dataReceived(self.requests)
+
+
+ def test_cannotWriteBeforeHeaders(self):
+ """
+ The HTTPChannel forbids writes before headers are sent.
+ """
+ self.assertRaises(
+ AssertionError,
+ self.channel.write,
+ b"some response data",
+ )
+
+
+ def test_cannot100ContinueAfterHeaders(self):
+ """
+ The HTTPChannel forbids sending 100 Continue after headers were sent.
+ """
+ self.channel.writeHeaders(b"HTTP/1.1", b"200", b"OK", [])
+ self.assertRaises(
+ AssertionError,
+ self.channel._send100Continue,
+ )
+
+
+ def test_cannotSendHeadersTwice(self):
+ """
+ The HTTPChannel forbids sending a header block twice.
+ """
+ self.channel.writeHeaders(b"HTTP/1.1", b"200", b"OK", [])
+ self.assertRaises(
+ AssertionError,
+ self.channel.writeHeaders,
+ b"HTTP/1.1",
+ b"200",
+ b"OK",
+ [],
+ )
+
+
+ def test_completingRequestAllows100ContinueAfterHeaders(self):
+ """
+ The HTTPChannel allows a 100 Continue once a request is complete.
+ """
+ self.channel.writeHeaders(b"HTTP/1.1", b"200", b"OK", [])
+ self.channel.requestDone(self.channel.requests[0])
+ self.channel._send100Continue()
+
+ self.assertEqual(
+ self.transport.value(),
+ b"HTTP/1.1 200 OK\r\n\r\nHTTP/1.1 100 Continue\r\n\r\n",
+ )
+
+
+ def test_completingRequestAllowsNewHeaders(self):
+ """
+ The HTTPChannel allows sending a new header block after headers are
+ complete.
+ """
+ self.channel.writeHeaders(b"HTTP/1.1", b"200", b"OK", [])
+ self.channel.requestDone(self.channel.requests[0])
+ self.channel.writeHeaders(b"HTTP/1.1", b"204", b"No Content", [])
+
+ self.assertEqual(
+ self.transport.value(),
+ b"HTTP/1.1 200 OK\r\n\r\nHTTP/1.1 204 No Content\r\n\r\n",
+ )
+
+
+ def test_canWriteAfterHeaders(self):
+ """
+ The HTTPChannel allows writing data after headers.
+ """
+ headers = [(b'Content-Length', b'5')]
+ self.channel.writeHeaders(b"HTTP/1.1", b"200", b"OK", headers)
+ self.channel.write(b'hello')
+
+ self.assertEqual(
+ self.transport.value(),
+ b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello",
+ )
+
+
+
class HTTPLoopbackTests(unittest.TestCase):
expectedHeaders = {b'request': b'/foo/bar',
@@ -1234,7 +1333,7 @@
content.append(self.content.read())
method.append(self.method)
path.append(self.path)
- decoder.append(self.channel._transferDecoder)
+ decoder.append(self._channel._transferDecoder)
testcase.didRequest = True
self.finish()
@@ -1714,10 +1813,12 @@
For an HTTP 1.0 request, L{http.Request.write} sends an HTTP 1.0
Response-Line and whatever response headers are set.
"""
- req = http.Request(DummyChannel(), False)
+ channel = DummyChannel()
trans = StringTransport()
+ channel.transport = trans
+ req = http.Request(channel, False)
- req.transport = trans
+ req._transport = trans
req.setResponseCode(200)
req.clientproto = b"HTTP/1.0"
@@ -1736,10 +1837,12 @@
L{http.Request.write} casts non-bytes header value to bytes
transparently.
"""
- req = http.Request(DummyChannel(), False)
+ channel = DummyChannel()
trans = StringTransport()
+ channel.transport = trans
+ req = http.Request(channel, False)
- req.transport = trans
+ req._transport = trans
req.setResponseCode(200)
req.clientproto = b"HTTP/1.0"
@@ -1768,10 +1871,12 @@
Response-Line, whatever response headers are set, and uses chunked
encoding for the response body.
"""
- req = http.Request(DummyChannel(), False)
+ channel = DummyChannel()
trans = StringTransport()
+ channel.transport = trans
+ req = http.Request(channel, False)
- req.transport = trans
+ req._transport = trans
req.setResponseCode(200)
req.clientproto = b"HTTP/1.1"
@@ -1793,10 +1898,12 @@
L{http.Request.write} sends an HTTP Response-Line, whatever response
headers are set, and a last-modified header with that time.
"""
- req = http.Request(DummyChannel(), False)
+ channel = DummyChannel()
trans = StringTransport()
+ channel.transport = trans
+ req = http.Request(channel, False)
- req.transport = trans
+ req._transport = trans
req.setResponseCode(200)
req.clientproto = b"HTTP/1.0"
@@ -1951,7 +2058,7 @@
# Then something goes wrong and content should get closed.
req.connectionLost(Failure(ConnectionLost("Finished")))
self.assertTrue(content.closed)
- self.assertIdentical(req.channel, None)
+ self.assertIdentical(req._channel, None)
def test_registerProducerTwiceFails(self):
@@ -2004,7 +2111,7 @@
# This is a roundabout assertion: http.StringTransport doesn't
# implement registerProducer, so Request.registerProducer can't have
# tried to call registerProducer on the transport.
- self.assertIsInstance(req.transport, http.StringTransport)
+ self.assertIsInstance(req._transport, http.StringTransport)
def test_registerProducerWhenQueuedDoesntRegisterPullProducer(self):
@@ -2023,7 +2130,7 @@
# This is a roundabout assertion: http.StringTransport doesn't
# implement registerProducer, so Request.registerProducer can't have
# tried to call registerProducer on the transport.
- self.assertIsInstance(req.transport, http.StringTransport)
+ self.assertIsInstance(req._transport, http.StringTransport)
def test_registerProducerWhenNotQueuedRegistersPushProducer(self):
@@ -2035,7 +2142,7 @@
req = http.Request(DummyChannel(), False)
producer = DummyProducer()
req.registerProducer(producer, True)
- self.assertEqual([(producer, True)], req.transport.producers)
+ self.assertEqual([(producer, True)], req._transport.producers)
def test_registerProducerWhenNotQueuedRegistersPullProducer(self):
@@ -2047,7 +2154,7 @@
req = http.Request(DummyChannel(), False)
producer = DummyProducer()
req.registerProducer(producer, False)
- self.assertEqual([(producer, False)], req.transport.producers)
+ self.assertEqual([(producer, False)], req._transport.producers)
def test_connectionLostNotification(self):
@@ -2059,7 +2166,7 @@
request = http.Request(d, True)
finished = request.notifyFinish()
request.connectionLost(Failure(ConnectionLost("Connection done")))
- self.assertIdentical(request.channel, None)
+ self.assertIdentical(request._channel, None)
return self.assertFailure(finished, ConnectionLost)
@@ -2155,10 +2262,10 @@
producer from the request and the request's transport.
"""
req = http.Request(DummyChannel(), False)
- req.transport = StringTransport()
+ req._transport = StringTransport()
req.registerProducer(DummyProducer(), False)
req.unregisterProducer()
- self.assertEqual((None, None), (req.producer, req.transport.producer))
+ self.assertEqual((None, None), (req.producer, req._transport.producer))
def test_unregisterNonQueuedStreamingProducer(self):
@@ -2167,10 +2274,10 @@
producer from the request and the request's transport.
"""
req = http.Request(DummyChannel(), False)
- req.transport = StringTransport()
+ req._transport = StringTransport()
req.registerProducer(DummyProducer(), True)
req.unregisterProducer()
- self.assertEqual((None, None), (req.producer, req.transport.producer))
+ self.assertEqual((None, None), (req.producer, req._transport.producer))
def test_unregisterQueuedNonStreamingProducer(self):
Modified: branches/hide-request-transport-8191-3/twisted/web/test/test_proxy.py
==============================================================================
--- branches/hide-request-transport-8191-3/twisted/web/test/test_proxy.py (original)
+++ branches/hide-request-transport-8191-3/twisted/web/test/test_proxy.py Tue Mar 22 08:34:35 2016
@@ -123,6 +123,14 @@
self.lostReason = reason
+ def getPeer(self):
+ return self.transport.getPeer()
+
+
+ def getHost(self):
+ return self.transport.getHost()
+
+
class ProxyClientTests(TestCase):
"""
Modified: branches/hide-request-transport-8191-3/twisted/web/test/test_web.py
==============================================================================
--- branches/hide-request-transport-8191-3/twisted/web/test/test_web.py (original)
+++ branches/hide-request-transport-8191-3/twisted/web/test/test_web.py Tue Mar 22 08:34:35 2016
@@ -554,8 +554,8 @@
fail = failure.Failure(Exception("Oh no!"))
request.processingFailed(fail)
- self.assertNotIn(b"Oh no!", request.transport.getvalue())
- self.assertIn(b"Processing Failed", request.transport.getvalue())
+ self.assertNotIn(b"Oh no!", request._transport.getvalue())
+ self.assertIn(b"Processing Failed", request._transport.getvalue())
# Since we didn't "handle" the exception, flush it to prevent a test
# failure
@@ -574,7 +574,7 @@
fail = failure.Failure(Exception("Oh no!"))
request.processingFailed(fail)
- self.assertIn(b"Oh no!", request.transport.getvalue())
+ self.assertIn(b"Oh no!", request._transport.getvalue())
# Since we didn't "handle" the exception, flush it to prevent a test
# failure
@@ -594,7 +594,7 @@
fail = failure.Failure(Exception(u"\u2603"))
request.processingFailed(fail)
- self.assertIn(b"☃", request.transport.getvalue())
+ self.assertIn(b"☃", request._transport.getvalue())
# Since we didn't "handle" the exception, flush it to prevent a test
# failure
@@ -823,11 +823,11 @@
def testGoodMethods(self):
req = self._getReq()
req.requestReceived(b'GET', b'/newrender', b'HTTP/1.0')
- self.assertEqual(req.transport.getvalue().splitlines()[-1], b'hi hi')
+ self.assertEqual(req._transport.getvalue().splitlines()[-1], b'hi hi')
req = self._getReq()
req.requestReceived(b'HEH', b'/newrender', b'HTTP/1.0')
- self.assertEqual(req.transport.getvalue().splitlines()[-1], b'ho ho')
+ self.assertEqual(req._transport.getvalue().splitlines()[-1], b'ho ho')
def testBadMethods(self):
req = self._getReq()
@@ -855,7 +855,7 @@
req = self._getReq()
req.requestReceived(b'HEAD', b'/newrender', b'HTTP/1.0')
self.assertEqual(req.code, 200)
- self.assertEqual(-1, req.transport.getvalue().find(b'hi hi'))
+ self.assertEqual(-1, req._transport.getvalue().find(b'hi hi'))
def test_unsupportedHead(self):
@@ -866,7 +866,7 @@
resource = HeadlessResource()
req = self._getReq(resource)
req.requestReceived(b"HEAD", b"/newrender", b"HTTP/1.0")
- headers, body = req.transport.getvalue().split(b'\r\n\r\n')
+ body = req._transport.getvalue()
self.assertEqual(req.code, 200)
self.assertEqual(body, b'')
@@ -887,7 +887,7 @@
request.requestReceived(b"GET", b"/newrender", b"HTTP/1.0")
- headers, body = request.transport.getvalue().split(b'\r\n\r\n')
+ body = request._transport.getvalue()
self.assertEqual(request.code, 500)
expected = [
'',
@@ -988,7 +988,7 @@
req.requestReceived(b'POST', b'/gettableresource?'
b'value=<script>bad', b'HTTP/1.0')
self.assertEqual(req.code, 405)
- renderedPage = req.transport.getvalue()
+ renderedPage = req._transport.getvalue()
self.assertNotIn(b"<script>bad", renderedPage)
self.assertIn(b'<script>bad', renderedPage)
@@ -1003,7 +1003,7 @@
req = self._getReq()
req.requestReceived(b'<style>bad', b'/gettableresource', b'HTTP/1.0')
self.assertEqual(req.code, 501)
- renderedPage = req.transport.getvalue()
+ renderedPage = req._transport.getvalue()
self.assertNotIn(b"<style>bad", renderedPage)
self.assertIn(b'<style>bad', renderedPage)
Modified: branches/hide-request-transport-8191-3/twisted/web/wsgi.py
==============================================================================
--- branches/hide-request-transport-8191-3/twisted/web/wsgi.py (original)
+++ branches/hide-request-transport-8191-3/twisted/web/wsgi.py Tue Mar 22 08:34:35 2016
@@ -506,7 +506,7 @@
def wsgiError(started, type, value, traceback):
err(Failure(value, type, traceback), "WSGI application error")
if started:
- self.request.transport.loseConnection()
+ self.request.loseConnection()
else:
self.request.setResponseCode(INTERNAL_SERVER_ERROR)
self.request.finish()