1
# Copyright (c) 2009 Twisted Matrix Laboratories.
2
# See LICENSE for details.
5
Tests for L{twisted.web._newclient}.
10
from zope.interface import implements
11
from zope.interface.verify import verifyObject
13
from twisted.python.failure import Failure
14
from twisted.internet.interfaces import IConsumer, IPushProducer
15
from twisted.internet.error import ConnectionDone
16
from twisted.internet.defer import Deferred, succeed, fail
17
from twisted.internet.protocol import Protocol
18
from twisted.trial.unittest import TestCase
19
from twisted.test.proto_helpers import StringTransport, AccumulatingProtocol
20
from twisted.web._newclient import UNKNOWN_LENGTH, STATUS, HEADER, BODY, DONE
21
from twisted.web._newclient import Request, Response, HTTPParser, HTTPClientParser
22
from twisted.web._newclient import BadResponseVersion, ParseError, HTTP11ClientProtocol
23
from twisted.web._newclient import ChunkedEncoder, RequestGenerationFailed, RequestTransmissionFailed, ResponseFailed, WrongBodyLength, RequestNotSent
24
from twisted.web._newclient import BadHeaders, ResponseDone, PotentialDataLoss, ExcessWrite
25
from twisted.web._newclient import TransportProxyProducer, LengthEnforcingConsumer, makeStatefulDispatcher
26
from twisted.web.http_headers import Headers
27
from twisted.web.http import _DataLoss
28
from twisted.web.iweb import IBodyProducer
32
class ArbitraryException(Exception):
34
A unique, arbitrary exception type which L{twisted.web._newclient} knows
39
class AnotherArbitraryException(Exception):
41
Similar to L{ArbitraryException} but with a different identity.
45
# A re-usable Headers instance for tests which don't really care what headers
47
_boringHeaders = Headers({'host': ['example.com']})
50
def assertWrapperExceptionTypes(self, deferred, mainType, reasonTypes):
52
Assert that the given L{Deferred} fails with the exception given by
53
C{mainType} and that the exceptions wrapped by the instance of C{mainType}
54
it fails with match the list of exception types given by C{reasonTypes}.
56
This is a helper for testing failures of exceptions which subclass
57
L{_newclient._WrapperException}.
59
@param self: A L{TestCase} instance which will be used to make the
62
@param deferred: The L{Deferred} which is expected to fail with
65
@param mainType: A L{_newclient._WrapperException} subclass which will be
66
trapped on C{deferred}.
68
@param reasonTypes: A sequence of exception types which will be trapped on
69
the resulting L{mainType} exception instance's C{reasons} sequence.
71
@return: A L{Deferred} which fires with the C{mainType} instance
72
C{deferred} fails with, or which fails somehow.
75
for reason, type in zip(err.reasons, reasonTypes):
77
self.assertEqual(len(err.reasons), len(reasonTypes))
79
d = self.assertFailure(deferred, mainType)
80
d.addCallback(cbFailed)
85
def assertResponseFailed(self, deferred, reasonTypes):
87
A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType}
90
return assertWrapperExceptionTypes(self, deferred, ResponseFailed, reasonTypes)
94
def assertRequestGenerationFailed(self, deferred, reasonTypes):
96
A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType}
97
of L{RequestGenerationFailed}.
99
return assertWrapperExceptionTypes(self, deferred, RequestGenerationFailed, reasonTypes)
103
def assertRequestTransmissionFailed(self, deferred, reasonTypes):
105
A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType}
106
of L{RequestTransmissionFailed}.
108
return assertWrapperExceptionTypes(self, deferred, RequestTransmissionFailed, reasonTypes)
112
def justTransportResponse(transport):
114
Helper function for creating a Response which uses the given transport.
115
All of the other parameters to L{Response.__init__} are filled with
116
arbitrary values. Only use this method if you don't care about any of
119
return Response(('HTTP', 1, 1), 200, 'OK', _boringHeaders, transport)
122
class MakeStatefulDispatcherTests(TestCase):
124
Tests for L{makeStatefulDispatcher}.
126
def test_functionCalledByState(self):
128
A method defined with L{makeStatefulDispatcher} invokes a second
129
method based on the current state of the object.
136
bar = makeStatefulDispatcher('quux', bar)
145
self.assertEqual(stateful.bar(), 'a')
146
stateful._state = 'B'
147
self.assertEqual(stateful.bar(), 'b')
148
stateful._state = 'C'
149
self.assertRaises(RuntimeError, stateful.bar)
153
class HTTPParserTests(TestCase):
155
Tests for L{HTTPParser} which is responsible for the bulk of the task of
158
def test_statusCallback(self):
160
L{HTTPParser} calls its C{statusReceived} method when it receives a
164
protocol = HTTPParser()
165
protocol.statusReceived = status.append
166
protocol.makeConnection(StringTransport())
167
self.assertEqual(protocol.state, STATUS)
168
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
169
self.assertEqual(status, ['HTTP/1.1 200 OK'])
170
self.assertEqual(protocol.state, HEADER)
173
def _headerTestSetup(self):
175
protocol = HTTPParser()
176
protocol.headerReceived = header.__setitem__
177
protocol.makeConnection(StringTransport())
178
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
179
return header, protocol
182
def test_headerCallback(self):
184
L{HTTPParser} calls its C{headerReceived} method when it receives a
187
header, protocol = self._headerTestSetup()
188
protocol.dataReceived('X-Foo:bar\r\n')
189
# Cannot tell it's not a continue header until the next line arrives
190
# and is not a continuation
191
protocol.dataReceived('\r\n')
192
self.assertEqual(header, {'X-Foo': 'bar'})
193
self.assertEqual(protocol.state, BODY)
196
def test_continuedHeaderCallback(self):
198
If a header is split over multiple lines, L{HTTPParser} calls
199
C{headerReceived} with the entire value once it is received.
201
header, protocol = self._headerTestSetup()
202
protocol.dataReceived('X-Foo: bar\r\n')
203
protocol.dataReceived(' baz\r\n')
204
protocol.dataReceived('\tquux\r\n')
205
protocol.dataReceived('\r\n')
206
self.assertEqual(header, {'X-Foo': 'bar baz\tquux'})
207
self.assertEqual(protocol.state, BODY)
210
def test_fieldContentWhitespace(self):
212
Leading and trailing linear whitespace is stripped from the header
213
value passed to the C{headerReceived} callback.
215
header, protocol = self._headerTestSetup()
216
value = ' \t \r\n bar \t\r\n \t\r\n'
217
protocol.dataReceived('X-Bar:' + value)
218
protocol.dataReceived('X-Foo:' + value)
219
protocol.dataReceived('\r\n')
220
self.assertEqual(header, {'X-Foo': 'bar',
224
def test_allHeadersCallback(self):
226
After the last header is received, L{HTTPParser} calls
227
C{allHeadersReceived}.
230
header, protocol = self._headerTestSetup()
231
def allHeadersReceived():
232
called.append(protocol.state)
233
protocol.state = STATUS
234
protocol.allHeadersReceived = allHeadersReceived
235
protocol.dataReceived('\r\n')
236
self.assertEqual(called, [HEADER])
237
self.assertEqual(protocol.state, STATUS)
240
def test_noHeaderCallback(self):
242
If there are no headers in the message, L{HTTPParser} does not call
245
header, protocol = self._headerTestSetup()
246
protocol.dataReceived('\r\n')
247
self.assertEqual(header, {})
248
self.assertEqual(protocol.state, BODY)
251
def test_headersSavedOnResponse(self):
253
All headers received by L{HTTPParser} are added to
254
L{HTTPParser.headers}.
256
protocol = HTTPParser()
257
protocol.makeConnection(StringTransport())
258
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
259
protocol.dataReceived('X-Foo: bar\r\n')
260
protocol.dataReceived('X-Foo: baz\r\n')
261
protocol.dataReceived('\r\n')
263
list(protocol.headers.getAllRawHeaders()),
264
[('X-Foo', ['bar', 'baz'])])
267
def test_connectionControlHeaders(self):
269
L{HTTPParser.isConnectionControlHeader} returns C{True} for headers
270
which are always connection control headers (similar to "hop-by-hop"
271
headers from RFC 2616 section 13.5.1) and C{False} for other headers.
273
protocol = HTTPParser()
275
'content-length', 'connection', 'keep-alive', 'te', 'trailers',
276
'transfer-encoding', 'upgrade', 'proxy-connection']
278
for header in connHeaderNames:
280
protocol.isConnectionControlHeader(header),
281
"Expecting %r to be a connection control header, but "
282
"wasn't" % (header,))
284
protocol.isConnectionControlHeader("date"),
285
"Expecting the arbitrarily selected 'date' header to not be "
286
"a connection control header, but was.")
289
def test_switchToBodyMode(self):
291
L{HTTPParser.switchToBodyMode} raises L{RuntimeError} if called more
294
protocol = HTTPParser()
295
protocol.makeConnection(StringTransport())
296
protocol.switchToBodyMode(object())
297
self.assertRaises(RuntimeError, protocol.switchToBodyMode, object())
301
class HTTPClientParserTests(TestCase):
303
Tests for L{HTTPClientParser} which is responsible for parsing HTTP
306
def test_parseVersion(self):
308
L{HTTPClientParser.parseVersion} parses a status line into its three
311
protocol = HTTPClientParser(None, None)
313
protocol.parseVersion('CANDY/7.2'),
317
def test_parseBadVersion(self):
319
L{HTTPClientParser.parseVersion} raises L{ValueError} when passed an
322
protocol = HTTPClientParser(None, None)
323
e = BadResponseVersion
324
f = protocol.parseVersion
327
exc = self.assertRaises(e, f, s)
328
self.assertEqual(exc.data, s)
331
checkParsing('foo/bar/baz')
334
checkParsing('foo/..')
336
checkParsing('foo/a.b')
337
checkParsing('foo/-1.-1')
340
def test_responseStatusParsing(self):
342
L{HTTPClientParser.statusReceived} parses the version, code, and phrase
343
from the status line and stores them on the response object.
345
request = Request('GET', '/', _boringHeaders, None)
346
protocol = HTTPClientParser(request, None)
347
protocol.makeConnection(StringTransport())
348
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
349
self.assertEqual(protocol.response.version, ('HTTP', 1, 1))
350
self.assertEqual(protocol.response.code, 200)
351
self.assertEqual(protocol.response.phrase, 'OK')
354
def test_badResponseStatus(self):
356
L{HTTPClientParser.statusReceived} raises L{ParseError} if it is called
357
with a status line which cannot be parsed.
359
protocol = HTTPClientParser(None, None)
362
exc = self.assertRaises(ParseError, protocol.statusReceived, s)
363
self.assertEqual(exc.data, s)
365
# If there are fewer than three whitespace-delimited parts to the
366
# status line, it is not valid and cannot be parsed.
368
checkParsing('HTTP/1.1 200')
370
# If the response code is not an integer, the status line is not valid
371
# and cannot be parsed.
372
checkParsing('HTTP/1.1 bar OK')
375
def _noBodyTest(self, request, response):
377
Assert that L{HTTPClientParser} parses the given C{response} to
378
C{request}, resulting in a response with no body and no extra bytes and
379
leaving the transport in the producing state.
381
@param request: A L{Request} instance which might have caused a server
382
to return the given response.
383
@param response: A string giving the response to be parsed.
385
@return: A C{dict} of headers from the response.
389
protocol = HTTPClientParser(request, finished.append)
390
protocol.headerReceived = header.__setitem__
392
protocol._bodyDataReceived = body.append
393
transport = StringTransport()
394
protocol.makeConnection(transport)
395
protocol.dataReceived(response)
396
self.assertEqual(transport.producerState, 'producing')
397
self.assertEqual(protocol.state, DONE)
398
self.assertEqual(body, [])
399
self.assertEqual(finished, [''])
400
self.assertEqual(protocol.response.length, 0)
404
def test_headResponse(self):
406
If the response is to a HEAD request, no body is expected, the body
407
callback is not invoked, and the I{Content-Length} header is passed to
410
request = Request('HEAD', '/', _boringHeaders, None)
412
'HTTP/1.1 200 OK\r\n'
413
'Content-Length: 10\r\n'
415
header = self._noBodyTest(request, status)
416
self.assertEqual(header, {'Content-Length': '10'})
419
def test_noContentResponse(self):
421
If the response code is I{NO CONTENT} (204), no body is expected and
422
the body callback is not invoked.
424
request = Request('GET', '/', _boringHeaders, None)
426
'HTTP/1.1 204 NO CONTENT\r\n'
428
self._noBodyTest(request, status)
431
def test_notModifiedResponse(self):
433
If the response code is I{NOT MODIFIED} (304), no body is expected and
434
the body callback is not invoked.
436
request = Request('GET', '/', _boringHeaders, None)
438
'HTTP/1.1 304 NOT MODIFIED\r\n'
440
self._noBodyTest(request, status)
443
def test_responseHeaders(self):
445
The response headers are added to the response object's C{headers}
448
protocol = HTTPClientParser(
449
Request('GET', '/', _boringHeaders, None),
451
protocol.makeConnection(StringTransport())
452
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
453
protocol.dataReceived('X-Foo: bar\r\n')
454
protocol.dataReceived('\r\n')
456
protocol.connHeaders,
459
protocol.response.headers,
460
Headers({'x-foo': ['bar']}))
461
self.assertIdentical(protocol.response.length, UNKNOWN_LENGTH)
464
def test_connectionHeaders(self):
466
The connection control headers are added to the parser's C{connHeaders}
469
protocol = HTTPClientParser(
470
Request('GET', '/', _boringHeaders, None),
472
protocol.makeConnection(StringTransport())
473
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
474
protocol.dataReceived('Content-Length: 123\r\n')
475
protocol.dataReceived('Connection: close\r\n')
476
protocol.dataReceived('\r\n')
478
protocol.response.headers,
481
protocol.connHeaders,
482
Headers({'content-length': ['123'],
483
'connection': ['close']}))
484
self.assertEqual(protocol.response.length, 123)
487
def test_headResponseContentLengthEntityHeader(self):
489
If a HEAD request is made, the I{Content-Length} header in the response
490
is added to the response headers, not the connection control headers.
492
protocol = HTTPClientParser(
493
Request('HEAD', '/', _boringHeaders, None),
495
protocol.makeConnection(StringTransport())
496
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
497
protocol.dataReceived('Content-Length: 123\r\n')
498
protocol.dataReceived('\r\n')
500
protocol.response.headers,
501
Headers({'content-length': ['123']}))
503
protocol.connHeaders,
505
self.assertEqual(protocol.response.length, 0)
508
def test_contentLength(self):
510
If a response includes a body with a length given by the
511
I{Content-Length} header, the bytes which make up the body are passed
512
to the C{_bodyDataReceived} callback on the L{HTTPParser}.
515
protocol = HTTPClientParser(
516
Request('GET', '/', _boringHeaders, None),
518
transport = StringTransport()
519
protocol.makeConnection(transport)
520
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
522
protocol.response._bodyDataReceived = body.append
523
protocol.dataReceived('Content-Length: 10\r\n')
524
protocol.dataReceived('\r\n')
526
# Incidentally, the transport should be paused now. It is the response
527
# object's responsibility to resume this when it is ready for bytes.
528
self.assertEqual(transport.producerState, 'paused')
530
self.assertEqual(protocol.state, BODY)
531
protocol.dataReceived('x' * 6)
532
self.assertEqual(body, ['x' * 6])
533
self.assertEqual(protocol.state, BODY)
534
protocol.dataReceived('y' * 4)
535
self.assertEqual(body, ['x' * 6, 'y' * 4])
536
self.assertEqual(protocol.state, DONE)
537
self.assertTrue(finished, [''])
540
def test_zeroContentLength(self):
542
If a response includes a I{Content-Length} header indicating zero bytes
543
in the response, L{Response.length} is set accordingly and no data is
544
delivered to L{Response._bodyDataReceived}.
547
protocol = HTTPClientParser(
548
Request('GET', '/', _boringHeaders, None),
551
protocol.makeConnection(StringTransport())
552
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
555
protocol.response._bodyDataReceived = body.append
557
protocol.dataReceived('Content-Length: 0\r\n')
558
protocol.dataReceived('\r\n')
560
self.assertEqual(protocol.state, DONE)
561
self.assertEqual(body, [])
562
self.assertTrue(finished, [''])
563
self.assertEqual(protocol.response.length, 0)
567
def test_multipleContentLengthHeaders(self):
569
If a response includes multiple I{Content-Length} headers,
570
L{HTTPClientParser.dataReceived} raises L{ValueError} to indicate that
571
the response is invalid and the transport is now unusable.
573
protocol = HTTPClientParser(
574
Request('GET', '/', _boringHeaders, None),
577
protocol.makeConnection(StringTransport())
580
protocol.dataReceived,
581
'HTTP/1.1 200 OK\r\n'
582
'Content-Length: 1\r\n'
583
'Content-Length: 2\r\n'
587
def test_extraBytesPassedBack(self):
589
If extra bytes are received past the end of a response, they are passed
590
to the finish callback.
593
protocol = HTTPClientParser(
594
Request('GET', '/', _boringHeaders, None),
597
protocol.makeConnection(StringTransport())
598
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
599
protocol.dataReceived('Content-Length: 0\r\n')
600
protocol.dataReceived('\r\nHere is another thing!')
601
self.assertEqual(protocol.state, DONE)
602
self.assertEqual(finished, ['Here is another thing!'])
605
def test_extraBytesPassedBackHEAD(self):
607
If extra bytes are received past the end of the headers of a response
608
to a HEAD request, they are passed to the finish callback.
611
protocol = HTTPClientParser(
612
Request('HEAD', '/', _boringHeaders, None),
615
protocol.makeConnection(StringTransport())
616
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
617
protocol.dataReceived('Content-Length: 12\r\n')
618
protocol.dataReceived('\r\nHere is another thing!')
619
self.assertEqual(protocol.state, DONE)
620
self.assertEqual(finished, ['Here is another thing!'])
623
def test_chunkedResponseBody(self):
625
If the response headers indicate the response body is encoded with the
626
I{chunked} transfer encoding, the body is decoded according to that
627
transfer encoding before being passed to L{Response._bodyDataReceived}.
630
protocol = HTTPClientParser(
631
Request('GET', '/', _boringHeaders, None),
633
protocol.makeConnection(StringTransport())
634
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
637
protocol.response._bodyDataReceived = body.append
639
protocol.dataReceived('Transfer-Encoding: chunked\r\n')
640
protocol.dataReceived('\r\n')
642
# No data delivered yet
643
self.assertEqual(body, [])
645
# Cannot predict the length of a chunked encoded response body.
646
self.assertIdentical(protocol.response.length, UNKNOWN_LENGTH)
648
# Deliver some chunks and make sure the data arrives
649
protocol.dataReceived('3\r\na')
650
self.assertEqual(body, ['a'])
651
protocol.dataReceived('bc\r\n')
652
self.assertEqual(body, ['a', 'bc'])
654
# The response's _bodyDataFinished method should be called when the last
655
# chunk is received. Extra data should be passed to the finished
657
protocol.dataReceived('0\r\n\r\nextra')
658
self.assertEqual(finished, ['extra'])
661
def test_unknownContentLength(self):
663
If a response does not include a I{Transfer-Encoding} or a
664
I{Content-Length}, the end of response body is indicated by the
665
connection being closed.
668
protocol = HTTPClientParser(
669
Request('GET', '/', _boringHeaders, None), finished.append)
670
transport = StringTransport()
671
protocol.makeConnection(transport)
672
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
675
protocol.response._bodyDataReceived = body.append
677
protocol.dataReceived('\r\n')
678
protocol.dataReceived('foo')
679
protocol.dataReceived('bar')
680
self.assertEqual(body, ['foo', 'bar'])
681
protocol.connectionLost(ConnectionDone("simulated end of connection"))
682
self.assertEqual(finished, [''])
685
def test_contentLengthAndTransferEncoding(self):
687
According to RFC 2616, section 4.4, point 3, if I{Content-Length} and
688
I{Transfer-Encoding: chunked} are present, I{Content-Length} MUST be
692
protocol = HTTPClientParser(
693
Request('GET', '/', _boringHeaders, None), finished.append)
694
transport = StringTransport()
695
protocol.makeConnection(transport)
696
protocol.dataReceived('HTTP/1.1 200 OK\r\n')
699
protocol.response._bodyDataReceived = body.append
701
protocol.dataReceived(
702
'Content-Length: 102\r\n'
703
'Transfer-Encoding: chunked\r\n'
710
self.assertEqual(body, ['abc'])
711
self.assertEqual(finished, [''])
714
def test_connectionLostBeforeBody(self):
716
If L{HTTPClientParser.connectionLost} is called before the headers are
717
finished, the C{_responseDeferred} is fired with the L{Failure} passed
718
to C{connectionLost}.
720
transport = StringTransport()
721
protocol = HTTPClientParser(Request('GET', '/', _boringHeaders, None), None)
722
protocol.makeConnection(transport)
723
# Grab this here because connectionLost gets rid of the attribute
724
responseDeferred = protocol._responseDeferred
725
protocol.connectionLost(Failure(ArbitraryException()))
727
return assertResponseFailed(
728
self, responseDeferred, [ArbitraryException])
731
def test_connectionLostWithError(self):
733
If one of the L{Response} methods called by
734
L{HTTPClientParser.connectionLost} raises an exception, the exception
735
is logged and not re-raised.
737
transport = StringTransport()
738
protocol = HTTPClientParser(Request('GET', '/', _boringHeaders, None), None)
739
protocol.makeConnection(transport)
742
protocol._responseDeferred.addCallback(response.append)
743
protocol.dataReceived(
744
'HTTP/1.1 200 OK\r\n'
745
'Content-Length: 1\r\n'
747
response = response[0]
749
# Arrange for an exception
750
def fakeBodyDataFinished(err=None):
751
raise ArbitraryException()
752
response._bodyDataFinished = fakeBodyDataFinished
754
protocol.connectionLost(None)
756
self.assertEqual(len(self.flushLoggedErrors(ArbitraryException)), 1)
762
L{SlowRequest} is a fake implementation of L{Request} which is easily
763
controlled externally (for example, by code in a test method).
765
@ivar stopped: A flag indicating whether C{stopWriting} has been called.
767
@ivar finished: After C{writeTo} is called, a L{Deferred} which was
768
returned by that method. L{SlowRequest} will never fire this
774
def writeTo(self, transport):
775
self.finished = Deferred()
779
def stopWriting(self):
786
L{SimpleRequest} is a fake implementation of L{Request} which writes a
787
short, fixed string to the transport passed to its C{writeTo} method and
788
returns a succeeded L{Deferred}. This vaguely emulates the behavior of a
789
L{Request} with no body producer.
791
def writeTo(self, transport):
792
transport.write('SOME BYTES')
797
class HTTP11ClientProtocolTests(TestCase):
799
Tests for the HTTP 1.1 client protocol implementation,
800
L{HTTP11ClientProtocol}.
804
Create an L{HTTP11ClientProtocol} connected to a fake transport.
806
self.transport = StringTransport()
807
self.protocol = HTTP11ClientProtocol()
808
self.protocol.makeConnection(self.transport)
811
def test_request(self):
813
L{HTTP11ClientProtocol.request} accepts a L{Request} and calls its
814
C{writeTo} method with its own transport.
816
self.protocol.request(SimpleRequest())
817
self.assertEqual(self.transport.value(), 'SOME BYTES')
820
def test_secondRequest(self):
822
The second time L{HTTP11ClientProtocol.request} is called, it returns a
823
L{Deferred} which immediately fires with a L{Failure} wrapping a
824
L{RequestNotSent} exception.
826
self.protocol.request(SlowRequest())
827
def cbNotSent(ignored):
828
self.assertEqual(self.transport.value(), '')
829
d = self.assertFailure(
830
self.protocol.request(SimpleRequest()), RequestNotSent)
831
d.addCallback(cbNotSent)
835
def test_requestAfterConnectionLost(self):
837
L{HTTP11ClientProtocol.request} returns a L{Deferred} which immediately
838
fires with a L{Failure} wrapping a L{RequestNotSent} if called after
839
the protocol has been disconnected.
841
self.protocol.connectionLost(
842
Failure(ConnectionDone("sad transport")))
843
def cbNotSent(ignored):
844
self.assertEqual(self.transport.value(), '')
845
d = self.assertFailure(
846
self.protocol.request(SimpleRequest()), RequestNotSent)
847
d.addCallback(cbNotSent)
851
def test_failedWriteTo(self):
853
If the L{Deferred} returned by L{Request.writeTo} fires with a
854
L{Failure}, L{HTTP11ClientProtocol.request} disconnects its transport
855
and returns a L{Deferred} which fires with a L{Failure} of
856
L{RequestGenerationFailed} wrapping the underlying failure.
859
def writeTo(self, transport):
860
return fail(ArbitraryException())
862
d = self.protocol.request(BrokenRequest())
863
def cbFailed(ignored):
864
self.assertTrue(self.transport.disconnecting)
865
# Simulate what would happen if the protocol had a real transport
866
# and make sure no exception is raised.
867
self.protocol.connectionLost(
868
Failure(ConnectionDone("you asked for it")))
869
d = assertRequestGenerationFailed(self, d, [ArbitraryException])
870
d.addCallback(cbFailed)
874
def test_synchronousWriteToError(self):
876
If L{Request.writeTo} raises an exception,
877
L{HTTP11ClientProtocol.request} returns a L{Deferred} which fires with
878
a L{Failure} of L{RequestGenerationFailed} wrapping that exception.
881
def writeTo(self, transport):
882
raise ArbitraryException()
884
d = self.protocol.request(BrokenRequest())
885
return assertRequestGenerationFailed(self, d, [ArbitraryException])
888
def test_connectionLostDuringRequestGeneration(self, mode=None):
890
If L{HTTP11ClientProtocol}'s transport is disconnected before the
891
L{Deferred} returned by L{Request.writeTo} fires, the L{Deferred}
892
returned by L{HTTP11ClientProtocol.request} fires with a L{Failure} of
893
L{RequestTransmissionFailed} wrapping the underlying failure.
895
request = SlowRequest()
896
d = self.protocol.request(request)
897
d = assertRequestTransmissionFailed(self, d, [ArbitraryException])
899
# The connection hasn't been lost yet. The request should still be
900
# allowed to do its thing.
901
self.assertFalse(request.stopped)
903
self.protocol.connectionLost(Failure(ArbitraryException()))
905
# Now the connection has been lost. The request should have been told
906
# to stop writing itself.
907
self.assertTrue(request.stopped)
909
if mode == 'callback':
910
request.finished.callback(None)
911
elif mode == 'errback':
912
request.finished.errback(Failure(AnotherArbitraryException()))
913
errors = self.flushLoggedErrors(AnotherArbitraryException)
914
self.assertEqual(len(errors), 1)
916
# Don't fire the writeTo Deferred at all.
921
def test_connectionLostBeforeGenerationFinished(self):
923
If the request passed to L{HTTP11ClientProtocol} finishes generation
924
successfully after the L{HTTP11ClientProtocol}'s connection has been
925
lost, nothing happens.
927
return self.test_connectionLostDuringRequestGeneration('callback')
930
def test_connectionLostBeforeGenerationFailed(self):
932
If the request passed to L{HTTP11ClientProtocol} finished generation
933
with an error after the L{HTTP11ClientProtocol}'s connection has been
934
lost, nothing happens.
936
return self.test_connectionLostDuringRequestGeneration('errback')
939
def test_receiveSimplestResponse(self):
941
When a response is delivered to L{HTTP11ClientProtocol}, the
942
L{Deferred} previously returned by the C{request} method is called back
943
with a L{Response} instance and the connection is closed.
945
d = self.protocol.request(Request('GET', '/', _boringHeaders, None))
946
def cbRequest(response):
947
self.assertEqual(response.code, 200)
948
self.assertEqual(response.headers, Headers())
949
self.assertTrue(self.transport.disconnecting)
950
d.addCallback(cbRequest)
951
self.protocol.dataReceived(
952
"HTTP/1.1 200 OK\r\n"
953
"Content-Length: 0\r\n"
958
def test_receiveResponseHeaders(self):
960
The headers included in a response delivered to L{HTTP11ClientProtocol}
961
are included on the L{Response} instance passed to the callback
962
returned by the C{request} method.
964
d = self.protocol.request(Request('GET', '/', _boringHeaders, None))
965
def cbRequest(response):
966
expected = Headers({'x-foo': ['bar', 'baz']})
967
self.assertEqual(response.headers, expected)
968
d.addCallback(cbRequest)
969
self.protocol.dataReceived(
970
"HTTP/1.1 200 OK\r\n"
977
def test_receiveResponseBeforeRequestGenerationDone(self):
979
If response bytes are delivered to L{HTTP11ClientProtocol} before the
980
L{Deferred} returned by L{Request.writeTo} fires, those response bytes
981
are parsed as part of the response.
983
request = SlowRequest()
984
d = self.protocol.request(request)
985
self.protocol.dataReceived(
986
"HTTP/1.1 200 OK\r\n"
988
"Content-Length: 6\r\n"
991
def cbResponse(response):
992
p = AccumulatingProtocol()
993
whenFinished = p.closedDeferred = Deferred()
994
response.deliverBody(p)
995
return whenFinished.addCallback(
996
lambda ign: (response, p.data))
997
d.addCallback(cbResponse)
998
def cbAllResponse((response, body)):
999
self.assertEqual(response.version, ('HTTP', 1, 1))
1000
self.assertEqual(response.code, 200)
1001
self.assertEqual(response.phrase, 'OK')
1002
self.assertEqual(response.headers, Headers({'x-foo': ['bar']}))
1003
self.assertEqual(body, "foobar")
1005
# Also nothing bad should happen if the request does finally
1006
# finish, even though it is completely irrelevant.
1007
request.finished.callback(None)
1009
d.addCallback(cbAllResponse)
1013
def test_receiveResponseBody(self):
1015
The C{deliverBody} method of the response object with which the
1016
L{Deferred} returned by L{HTTP11ClientProtocol.request} fires can be
1017
used to get the body of the response.
1019
protocol = AccumulatingProtocol()
1020
whenFinished = protocol.closedDeferred = Deferred()
1021
requestDeferred = self.protocol.request(Request('GET', '/', _boringHeaders, None))
1023
self.protocol.dataReceived(
1024
"HTTP/1.1 200 OK\r\n"
1025
"Content-Length: 6\r\n"
1028
# Here's what's going on: all the response headers have been delivered
1029
# by this point, so the request Deferred can fire with a Response
1030
# object. The body is yet to come, but that's okay, because the
1031
# Response object is how you *get* the body.
1033
requestDeferred.addCallback(result.append)
1035
self.assertEqual(result, [])
1036
# Deliver the very last byte of the response. It is exactly at this
1037
# point which the Deferred returned by request should fire.
1038
self.protocol.dataReceived("\n")
1039
response = result[0]
1041
response.deliverBody(protocol)
1043
self.protocol.dataReceived("foo")
1044
self.protocol.dataReceived("bar")
1046
def cbAllResponse(ignored):
1047
self.assertEqual(protocol.data, "foobar")
1048
protocol.closedReason.trap(ResponseDone)
1049
whenFinished.addCallback(cbAllResponse)
1053
def test_responseBodyFinishedWhenConnectionLostWhenContentLengthIsUnknown(
1056
If the length of the response body is unknown, the protocol passed to
1057
the response's C{deliverBody} method has its C{connectionLost}
1058
method called with a L{Failure} wrapping a L{PotentialDataLoss}
1061
requestDeferred = self.protocol.request(Request('GET', '/', _boringHeaders, None))
1062
self.protocol.dataReceived(
1063
"HTTP/1.1 200 OK\r\n"
1067
requestDeferred.addCallback(result.append)
1068
response = result[0]
1070
protocol = AccumulatingProtocol()
1071
response.deliverBody(protocol)
1073
self.protocol.dataReceived("foo")
1074
self.protocol.dataReceived("bar")
1076
self.assertEqual(protocol.data, "foobar")
1077
self.protocol.connectionLost(
1078
Failure(ConnectionDone("low-level transport disconnected")))
1080
protocol.closedReason.trap(PotentialDataLoss)
1083
def test_chunkedResponseBodyUnfinishedWhenConnectionLost(self):
1085
If the final chunk has not been received when the connection is lost
1086
(for any reason), the protocol passed to C{deliverBody} has its
1087
C{connectionLost} method called with a L{Failure} wrapping the
1088
exception for that reason.
1090
requestDeferred = self.protocol.request(Request('GET', '/', _boringHeaders, None))
1091
self.protocol.dataReceived(
1092
"HTTP/1.1 200 OK\r\n"
1093
"Transfer-Encoding: chunked\r\n"
1097
requestDeferred.addCallback(result.append)
1098
response = result[0]
1100
protocol = AccumulatingProtocol()
1101
response.deliverBody(protocol)
1103
self.protocol.dataReceived("3\r\nfoo\r\n")
1104
self.protocol.dataReceived("3\r\nbar\r\n")
1106
self.assertEqual(protocol.data, "foobar")
1108
self.protocol.connectionLost(Failure(ArbitraryException()))
1110
return assertResponseFailed(
1111
self, fail(protocol.closedReason), [ArbitraryException, _DataLoss])
1114
def test_parserDataReceivedException(self):
1116
If the parser L{HTTP11ClientProtocol} delivers bytes to in
1117
C{dataReceived} raises an exception, the exception is wrapped in a
1118
L{Failure} and passed to the parser's C{connectionLost} and then the
1119
L{HTTP11ClientProtocol}'s transport is disconnected.
1121
requestDeferred = self.protocol.request(Request('GET', '/', _boringHeaders, None))
1122
self.protocol.dataReceived('unparseable garbage goes here\r\n')
1123
d = assertResponseFailed(self, requestDeferred, [ParseError])
1125
self.assertTrue(self.transport.disconnecting)
1127
exc.reasons[0].value.data, 'unparseable garbage goes here')
1129
# Now do what StringTransport doesn't do but a real transport would
1130
# have, call connectionLost on the HTTP11ClientProtocol. Nothing
1131
# is asserted about this, but it's important for it to not raise an
1133
self.protocol.connectionLost(Failure(ConnectionDone("it is done")))
1135
d.addCallback(cbFailed)
1139
def test_proxyStopped(self):
1141
When the HTTP response parser is disconnected, the
1142
L{TransportProxyProducer} which was connected to it as a transport is
1145
requestDeferred = self.protocol.request(Request('GET', '/', _boringHeaders, None))
1146
transport = self.protocol._parser.transport
1147
self.assertIdentical(transport._producer, self.transport)
1148
self.protocol._disconnectParser(Failure(ConnectionDone("connection done")))
1149
self.assertIdentical(transport._producer, None)
1150
return assertResponseFailed(self, requestDeferred, [ConnectionDone])
1154
class StringProducer:
1156
L{StringProducer} is a dummy body producer.
1158
@ivar stopped: A flag which indicates whether or not C{stopProducing} has
1160
@ivar consumer: After C{startProducing} is called, the value of the
1161
C{consumer} argument to that method.
1162
@ivar finished: After C{startProducing} is called, a L{Deferred} which was
1163
returned by that method. L{StringProducer} will never fire this
1166
implements(IBodyProducer)
1170
def __init__(self, length):
1171
self.length = length
1174
def startProducing(self, consumer):
1175
self.consumer = consumer
1176
self.finished = Deferred()
1177
return self.finished
1180
def stopProducing(self):
1185
class RequestTests(TestCase):
1187
Tests for L{Request}.
1190
self.transport = StringTransport()
1193
def test_sendSimplestRequest(self):
1195
L{Request.writeTo} formats the request data and writes it to the given
1198
Request('GET', '/', _boringHeaders, None).writeTo(self.transport)
1200
self.transport.value(),
1201
"GET / HTTP/1.1\r\n"
1202
"Connection: close\r\n"
1203
"Host: example.com\r\n"
1207
def test_sendRequestHeaders(self):
1209
L{Request.writeTo} formats header data and writes it to the given
1212
headers = Headers({'x-foo': ['bar', 'baz'], 'host': ['example.com']})
1213
Request('GET', '/foo', headers, None).writeTo(self.transport)
1214
lines = self.transport.value().split('\r\n')
1215
self.assertEqual(lines[0], "GET /foo HTTP/1.1")
1216
self.assertEqual(lines[-2:], ["", ""])
1217
del lines[0], lines[-2:]
1221
["Connection: close",
1222
"Host: example.com",
1227
def test_sendChunkedRequestBody(self):
1229
L{Request.writeTo} uses chunked encoding to write data from the request
1230
body producer to the given transport. It registers the request body
1231
producer with the transport.
1233
producer = StringProducer(UNKNOWN_LENGTH)
1234
request = Request('POST', '/bar', _boringHeaders, producer)
1235
request.writeTo(self.transport)
1237
self.assertNotIdentical(producer.consumer, None)
1238
self.assertIdentical(self.transport.producer, producer)
1239
self.assertTrue(self.transport.streaming)
1242
self.transport.value(),
1243
"POST /bar HTTP/1.1\r\n"
1244
"Connection: close\r\n"
1245
"Transfer-Encoding: chunked\r\n"
1246
"Host: example.com\r\n"
1248
self.transport.clear()
1250
producer.consumer.write('x' * 3)
1251
producer.consumer.write('y' * 15)
1252
producer.finished.callback(None)
1253
self.assertIdentical(self.transport.producer, None)
1255
self.transport.value(),
1259
"yyyyyyyyyyyyyyy\r\n"
1264
def test_sendChunkedRequestBodyWithError(self):
1266
If L{Request} is created with a C{bodyProducer} without a known length
1267
and the L{Deferred} returned from its C{startProducing} method fires
1268
with a L{Failure}, the L{Deferred} returned by L{Request.writeTo} fires
1269
with that L{Failure} and the body producer is unregistered from the
1270
transport. The final zero-length chunk is not written to the
1273
producer = StringProducer(UNKNOWN_LENGTH)
1274
request = Request('POST', '/bar', _boringHeaders, producer)
1275
writeDeferred = request.writeTo(self.transport)
1276
self.transport.clear()
1277
producer.finished.errback(ArbitraryException())
1278
def cbFailed(ignored):
1279
self.assertEqual(self.transport.value(), "")
1280
self.assertIdentical(self.transport.producer, None)
1281
d = self.assertFailure(writeDeferred, ArbitraryException)
1282
d.addCallback(cbFailed)
1286
def test_sendRequestBodyWithLength(self):
1288
If L{Request} is created with a C{bodyProducer} with a known length,
1289
that length is sent as the value for the I{Content-Length} header and
1290
chunked encoding is not used.
1292
producer = StringProducer(3)
1293
request = Request('POST', '/bar', _boringHeaders, producer)
1294
request.writeTo(self.transport)
1296
self.assertNotIdentical(producer.consumer, None)
1297
self.assertIdentical(self.transport.producer, producer)
1298
self.assertTrue(self.transport.streaming)
1301
self.transport.value(),
1302
"POST /bar HTTP/1.1\r\n"
1303
"Connection: close\r\n"
1304
"Content-Length: 3\r\n"
1305
"Host: example.com\r\n"
1307
self.transport.clear()
1309
producer.consumer.write('abc')
1310
producer.finished.callback(None)
1311
self.assertIdentical(self.transport.producer, None)
1312
self.assertEqual(self.transport.value(), "abc")
1315
def test_sendRequestBodyWithTooFewBytes(self):
1317
If L{Request} is created with a C{bodyProducer} with a known length and
1318
the producer does not produce that many bytes, the L{Deferred} returned
1319
by L{Request.writeTo} fires with a L{Failure} wrapping a
1320
L{WrongBodyLength} exception.
1322
producer = StringProducer(3)
1323
request = Request('POST', '/bar', _boringHeaders, producer)
1324
writeDeferred = request.writeTo(self.transport)
1325
producer.consumer.write('ab')
1326
producer.finished.callback(None)
1327
self.assertIdentical(self.transport.producer, None)
1328
return self.assertFailure(writeDeferred, WrongBodyLength)
1331
def _sendRequestBodyWithTooManyBytesTest(self, finisher):
1333
Verify that when too many bytes have been written by a body producer
1334
and then the body producer's C{startProducing} L{Deferred} fires that
1335
the producer is unregistered from the transport and that the
1336
L{Deferred} returned from L{Request.writeTo} is fired with a L{Failure}
1337
wrapping a L{WrongBodyLength}.
1339
@param finisher: A callable which will be invoked with the body
1340
producer after too many bytes have been written to the transport.
1341
It should fire the startProducing Deferred somehow.
1343
producer = StringProducer(3)
1344
request = Request('POST', '/bar', _boringHeaders, producer)
1345
writeDeferred = request.writeTo(self.transport)
1347
producer.consumer.write('ab')
1349
# The producer hasn't misbehaved yet, so it shouldn't have been
1351
self.assertFalse(producer.stopped)
1353
producer.consumer.write('cd')
1355
# Now the producer *has* misbehaved, so we should have tried to
1357
self.assertTrue(producer.stopped)
1359
# The transport should have had the producer unregistered from it as
1361
self.assertIdentical(self.transport.producer, None)
1364
# The "cd" should not have been written to the transport because
1365
# the request can now locally be recognized to be invalid. If we
1366
# had written the extra bytes, the server could have decided to
1367
# start processing the request, which would be bad since we're
1368
# going to indicate failure locally.
1370
self.transport.value(),
1371
"POST /bar HTTP/1.1\r\n"
1372
"Connection: close\r\n"
1373
"Content-Length: 3\r\n"
1374
"Host: example.com\r\n"
1377
self.transport.clear()
1379
# Subsequent writes should be ignored, as should firing the
1380
# Deferred returned from startProducing.
1381
self.assertRaises(ExcessWrite, producer.consumer.write, 'ef')
1383
# Likewise, if the Deferred returned from startProducing fires,
1384
# this should more or less be ignored (aside from possibly logging
1388
# There should have been nothing further written to the transport.
1389
self.assertEqual(self.transport.value(), "")
1391
d = self.assertFailure(writeDeferred, WrongBodyLength)
1392
d.addCallback(cbFailed)
1396
def test_sendRequestBodyWithTooManyBytes(self):
1398
If L{Request} is created with a C{bodyProducer} with a known length and
1399
the producer tries to produce more than than many bytes, the
1400
L{Deferred} returned by L{Request.writeTo} fires with a L{Failure}
1401
wrapping a L{WrongBodyLength} exception.
1403
def finisher(producer):
1404
producer.finished.callback(None)
1405
return self._sendRequestBodyWithTooManyBytesTest(finisher)
1408
def test_sendRequestBodyErrorWithTooManyBytes(self):
1410
If L{Request} is created with a C{bodyProducer} with a known length and
1411
the producer tries to produce more than than many bytes, the
1412
L{Deferred} returned by L{Request.writeTo} fires with a L{Failure}
1413
wrapping a L{WrongBodyLength} exception.
1415
def finisher(producer):
1416
producer.finished.errback(ArbitraryException())
1417
errors = self.flushLoggedErrors(ArbitraryException)
1418
self.assertEqual(len(errors), 1)
1419
return self._sendRequestBodyWithTooManyBytesTest(finisher)
1422
def test_sendRequestBodyErrorWithConsumerError(self):
1424
Though there should be no way for the internal C{finishedConsuming}
1425
L{Deferred} in L{Request._writeToContentLength} to fire a L{Failure}
1426
after the C{finishedProducing} L{Deferred} has fired, in case this does
1427
happen, the error should be logged with a message about how there's
1428
probably a bug in L{Request}.
1430
This is a whitebox test.
1432
producer = StringProducer(3)
1433
request = Request('POST', '/bar', _boringHeaders, producer)
1434
writeDeferred = request.writeTo(self.transport)
1436
finishedConsuming = producer.consumer._finished
1438
producer.consumer.write('abc')
1439
producer.finished.callback(None)
1441
finishedConsuming.errback(ArbitraryException())
1442
self.assertEqual(len(self.flushLoggedErrors(ArbitraryException)), 1)
1445
def _sendRequestBodyFinishedEarlyThenTooManyBytes(self, finisher):
1447
Verify that if the body producer fires its Deferred and then keeps
1448
writing to the consumer that the extra writes are ignored and the
1449
L{Deferred} returned by L{Request.writeTo} fires with a L{Failure}
1450
wrapping the most appropriate exception type.
1452
producer = StringProducer(3)
1453
request = Request('POST', '/bar', _boringHeaders, producer)
1454
writeDeferred = request.writeTo(self.transport)
1456
producer.consumer.write('ab')
1458
self.assertIdentical(self.transport.producer, None)
1459
self.transport.clear()
1460
self.assertRaises(ExcessWrite, producer.consumer.write, 'cd')
1461
self.assertEqual(self.transport.value(), "")
1462
return writeDeferred
1465
def test_sendRequestBodyFinishedEarlyThenTooManyBytes(self):
1467
If the request body producer indicates it is done by firing the
1468
L{Deferred} returned from its C{startProducing} method but then goes on
1469
to write too many bytes, the L{Deferred} returned by {Request.writeTo}
1470
fires with a L{Failure} wrapping L{WrongBodyLength}.
1472
def finisher(producer):
1473
producer.finished.callback(None)
1474
return self.assertFailure(
1475
self._sendRequestBodyFinishedEarlyThenTooManyBytes(finisher),
1479
def test_sendRequestBodyErroredEarlyThenTooManyBytes(self):
1481
If the request body producer indicates an error by firing the
1482
L{Deferred} returned from its C{startProducing} method but then goes on
1483
to write too many bytes, the L{Deferred} returned by {Request.writeTo}
1484
fires with that L{Failure} and L{WrongBodyLength} is logged.
1486
def finisher(producer):
1487
producer.finished.errback(ArbitraryException())
1488
return self.assertFailure(
1489
self._sendRequestBodyFinishedEarlyThenTooManyBytes(finisher),
1493
def test_sendChunkedRequestBodyFinishedThenWriteMore(self, _with=None):
1495
If the request body producer with an unknown length tries to write
1496
after firing the L{Deferred} returned by its C{startProducing} method,
1497
the C{write} call raises an exception and does not write anything to
1498
the underlying transport.
1500
producer = StringProducer(UNKNOWN_LENGTH)
1501
request = Request('POST', '/bar', _boringHeaders, producer)
1502
writeDeferred = request.writeTo(self.transport)
1503
producer.finished.callback(_with)
1504
self.transport.clear()
1506
self.assertRaises(ExcessWrite, producer.consumer.write, 'foo')
1507
self.assertEqual(self.transport.value(), "")
1508
return writeDeferred
1511
def test_sendChunkedRequestBodyFinishedWithErrorThenWriteMore(self):
1513
If the request body producer with an unknown length tries to write
1514
after firing the L{Deferred} returned by its C{startProducing} method
1515
with a L{Failure}, the C{write} call raises an exception and does not
1516
write anything to the underlying transport.
1518
d = self.test_sendChunkedRequestBodyFinishedThenWriteMore(
1519
Failure(ArbitraryException()))
1520
return self.assertFailure(d, ArbitraryException)
1523
def test_sendRequestBodyWithError(self):
1525
If the L{Deferred} returned from the C{startProducing} method of the
1526
L{IBodyProducer} passed to L{Request} fires with a L{Failure}, the
1527
L{Deferred} returned from L{Request.writeTo} fails with that
1530
producer = StringProducer(5)
1531
request = Request('POST', '/bar', _boringHeaders, producer)
1532
writeDeferred = request.writeTo(self.transport)
1534
# Sanity check - the producer should be registered with the underlying
1536
self.assertIdentical(self.transport.producer, producer)
1537
self.assertTrue(self.transport.streaming)
1539
producer.consumer.write('ab')
1541
self.transport.value(),
1542
"POST /bar HTTP/1.1\r\n"
1543
"Connection: close\r\n"
1544
"Content-Length: 5\r\n"
1545
"Host: example.com\r\n"
1549
self.assertFalse(self.transport.disconnecting)
1550
producer.finished.errback(Failure(ArbitraryException()))
1552
# Disconnection is handled by a higher level. Request should leave the
1553
# transport alone in this case.
1554
self.assertFalse(self.transport.disconnecting)
1556
# Oh. Except it should unregister the producer that it registered.
1557
self.assertIdentical(self.transport.producer, None)
1559
return self.assertFailure(writeDeferred, ArbitraryException)
1561
def test_hostHeaderRequired(self):
1563
L{Request.writeTo} raises L{BadHeaders} if there is not exactly one
1564
I{Host} header and writes nothing to the given transport.
1566
request = Request('GET', '/', Headers({}), None)
1567
self.assertRaises(BadHeaders, request.writeTo, self.transport)
1568
self.assertEqual(self.transport.value(), '')
1570
request = Request('GET', '/', Headers({'Host': ['example.com', 'example.org']}), None)
1571
self.assertRaises(BadHeaders, request.writeTo, self.transport)
1572
self.assertEqual(self.transport.value(), '')
1575
def test_stopWriting(self):
1577
L{Request.stopWriting} calls its body producer's C{stopProducing}
1580
producer = StringProducer(3)
1581
request = Request('GET', '/', _boringHeaders, producer)
1582
d = request.writeTo(self.transport)
1583
self.assertFalse(producer.stopped)
1584
request.stopWriting()
1585
self.assertTrue(producer.stopped)
1588
def test_brokenStopProducing(self):
1590
If the body producer's C{stopProducing} method raises an exception,
1591
L{Request.stopWriting} logs it and does not re-raise it.
1593
producer = StringProducer(3)
1594
def brokenStopProducing():
1595
raise ArbitraryException("stopProducing is busted")
1596
producer.stopProducing = brokenStopProducing
1598
request = Request('GET', '/', _boringHeaders, producer)
1599
d = request.writeTo(self.transport)
1600
request.stopWriting()
1602
len(self.flushLoggedErrors(ArbitraryException)), 1)
1606
class LengthEnforcingConsumerTests(TestCase):
1608
Tests for L{LengthEnforcingConsumer}.
1611
self.result = Deferred()
1612
self.producer = StringProducer(10)
1613
self.transport = StringTransport()
1614
self.enforcer = LengthEnforcingConsumer(
1615
self.producer, self.transport, self.result)
1618
def test_write(self):
1620
L{LengthEnforcingConsumer.write} calls the wrapped consumer's C{write}
1621
method with the bytes it is passed as long as there are fewer of them
1622
than the C{length} attribute indicates remain to be received.
1624
self.enforcer.write('abc')
1625
self.assertEqual(self.transport.value(), 'abc')
1626
self.transport.clear()
1627
self.enforcer.write('def')
1628
self.assertEqual(self.transport.value(), 'def')
1631
def test_finishedEarly(self):
1633
L{LengthEnforcingConsumer._noMoreWritesExpected} raises
1634
L{WrongBodyLength} if it is called before the indicated number of bytes
1637
self.enforcer.write('x' * 9)
1638
self.assertRaises(WrongBodyLength, self.enforcer._noMoreWritesExpected)
1641
def test_writeTooMany(self, _unregisterAfter=False):
1643
If it is called with a total number of bytes exceeding the indicated
1644
limit passed to L{LengthEnforcingConsumer.__init__},
1645
L{LengthEnforcingConsumer.write} fires the L{Deferred} with a
1646
L{Failure} wrapping a L{WrongBodyLength} and also calls the
1647
C{stopProducing} method of the producer.
1649
self.enforcer.write('x' * 10)
1650
self.assertFalse(self.producer.stopped)
1651
self.enforcer.write('x')
1652
self.assertTrue(self.producer.stopped)
1653
if _unregisterAfter:
1654
self.enforcer._noMoreWritesExpected()
1655
return self.assertFailure(self.result, WrongBodyLength)
1658
def test_writeAfterNoMoreExpected(self):
1660
If L{LengthEnforcingConsumer.write} is called after
1661
L{LengthEnforcingConsumer._noMoreWritesExpected}, it calls the
1662
producer's C{stopProducing} method and raises L{ExcessWrite}.
1664
self.enforcer.write('x' * 10)
1665
self.enforcer._noMoreWritesExpected()
1666
self.assertFalse(self.producer.stopped)
1667
self.assertRaises(ExcessWrite, self.enforcer.write, 'x')
1668
self.assertTrue(self.producer.stopped)
1671
def test_finishedLate(self):
1673
L{LengthEnforcingConsumer._noMoreWritesExpected} does nothing (in
1674
particular, it does not raise any exception) if called after too many
1675
bytes have been passed to C{write}.
1677
return self.test_writeTooMany(True)
1680
def test_finished(self):
1682
If L{LengthEnforcingConsumer._noMoreWritesExpected} is called after
1683
the correct number of bytes have been written it returns C{None}.
1685
self.enforcer.write('x' * 10)
1686
self.assertIdentical(self.enforcer._noMoreWritesExpected(), None)
1689
def test_stopProducingRaises(self):
1691
If L{LengthEnforcingConsumer.write} calls the producer's
1692
C{stopProducing} because too many bytes were written and the
1693
C{stopProducing} method raises an exception, the exception is logged
1694
and the L{LengthEnforcingConsumer} still errbacks the finished
1697
def brokenStopProducing():
1698
StringProducer.stopProducing(self.producer)
1699
raise ArbitraryException("stopProducing is busted")
1700
self.producer.stopProducing = brokenStopProducing
1702
def cbFinished(ignored):
1704
len(self.flushLoggedErrors(ArbitraryException)), 1)
1705
d = self.test_writeTooMany()
1706
d.addCallback(cbFinished)
1711
class RequestBodyConsumerTests(TestCase):
1713
Tests for L{ChunkedEncoder} which sits between an L{ITransport} and a
1714
request/response body producer and chunked encodes everything written to
1717
def test_interface(self):
1719
L{ChunkedEncoder} instances provide L{IConsumer}.
1722
verifyObject(IConsumer, ChunkedEncoder(StringTransport())))
1725
def test_write(self):
1727
L{ChunkedEncoder.write} writes to the transport the chunked encoded
1728
form of the bytes passed to it.
1730
transport = StringTransport()
1731
encoder = ChunkedEncoder(transport)
1732
encoder.write('foo')
1733
self.assertEqual(transport.value(), '3\r\nfoo\r\n')
1735
encoder.write('x' * 16)
1736
self.assertEqual(transport.value(), '10\r\n' + 'x' * 16 + '\r\n')
1739
def test_producerRegistration(self):
1741
L{ChunkedEncoder.registerProducer} registers the given streaming
1742
producer with its transport and L{ChunkedEncoder.unregisterProducer}
1743
writes a zero-length chunk to its transport and unregisters the
1744
transport's producer.
1746
transport = StringTransport()
1748
encoder = ChunkedEncoder(transport)
1749
encoder.registerProducer(producer, True)
1750
self.assertIdentical(transport.producer, producer)
1751
self.assertTrue(transport.streaming)
1752
encoder.unregisterProducer()
1753
self.assertIdentical(transport.producer, None)
1754
self.assertEqual(transport.value(), '0\r\n\r\n')
1758
class TransportProxyProducerTests(TestCase):
1760
Tests for L{TransportProxyProducer} which proxies the L{IPushProducer}
1761
interface of a transport.
1763
def test_interface(self):
1765
L{TransportProxyProducer} instances provide L{IPushProducer}.
1768
verifyObject(IPushProducer, TransportProxyProducer(None)))
1771
def test_stopProxyingUnreferencesProducer(self):
1773
L{TransportProxyProducer._stopProxying} drops the reference to the
1774
wrapped L{IPushProducer} provider.
1776
transport = StringTransport()
1777
proxy = TransportProxyProducer(transport)
1778
self.assertIdentical(proxy._producer, transport)
1779
proxy._stopProxying()
1780
self.assertIdentical(proxy._producer, None)
1783
def test_resumeProducing(self):
1785
L{TransportProxyProducer.resumeProducing} calls the wrapped
1786
transport's C{resumeProducing} method unless told to stop proxying.
1788
transport = StringTransport()
1789
transport.pauseProducing()
1791
proxy = TransportProxyProducer(transport)
1792
# The transport should still be paused.
1793
self.assertEqual(transport.producerState, 'paused')
1794
proxy.resumeProducing()
1795
# The transport should now be resumed.
1796
self.assertEqual(transport.producerState, 'producing')
1798
transport.pauseProducing()
1799
proxy._stopProxying()
1801
# The proxy should no longer do anything to the transport.
1802
proxy.resumeProducing()
1803
self.assertEqual(transport.producerState, 'paused')
1806
def test_pauseProducing(self):
1808
L{TransportProxyProducer.pauseProducing} calls the wrapped transport's
1809
C{pauseProducing} method unless told to stop proxying.
1811
transport = StringTransport()
1813
proxy = TransportProxyProducer(transport)
1814
# The transport should still be producing.
1815
self.assertEqual(transport.producerState, 'producing')
1816
proxy.pauseProducing()
1817
# The transport should now be paused.
1818
self.assertEqual(transport.producerState, 'paused')
1820
transport.resumeProducing()
1821
proxy._stopProxying()
1823
# The proxy should no longer do anything to the transport.
1824
proxy.pauseProducing()
1825
self.assertEqual(transport.producerState, 'producing')
1828
def test_stopProducing(self):
1830
L{TransportProxyProducer.stopProducing} calls the wrapped transport's
1831
C{stopProducing} method unless told to stop proxying.
1833
transport = StringTransport()
1834
proxy = TransportProxyProducer(transport)
1835
# The transport should still be producing.
1836
self.assertEqual(transport.producerState, 'producing')
1837
proxy.stopProducing()
1838
# The transport should now be stopped.
1839
self.assertEqual(transport.producerState, 'stopped')
1841
transport = StringTransport()
1842
proxy = TransportProxyProducer(transport)
1843
proxy._stopProxying()
1844
proxy.stopProducing()
1845
# The transport should not have been stopped.
1846
self.assertEqual(transport.producerState, 'producing')
1850
class ResponseTests(TestCase):
1852
Tests for L{Response}.
1854
def test_makeConnection(self):
1856
The L{IProtocol} provider passed to L{Response.deliverBody} has its
1857
C{makeConnection} method called with an L{IPushProducer} provider
1858
hooked up to the response as an argument.
1861
transport = StringTransport()
1862
class SomeProtocol(Protocol):
1863
def makeConnection(self, producer):
1864
producers.append(producer)
1866
consumer = SomeProtocol()
1867
response = justTransportResponse(transport)
1868
response.deliverBody(consumer)
1869
[theProducer] = producers
1870
theProducer.pauseProducing()
1871
self.assertEqual(transport.producerState, 'paused')
1872
theProducer.resumeProducing()
1873
self.assertEqual(transport.producerState, 'producing')
1876
def test_dataReceived(self):
1878
The L{IProtocol} provider passed to L{Response.deliverBody} has its
1879
C{dataReceived} method called with bytes received as part of the
1883
class ListConsumer(Protocol):
1884
def dataReceived(self, data):
1888
consumer = ListConsumer()
1889
response = justTransportResponse(StringTransport())
1890
response.deliverBody(consumer)
1892
response._bodyDataReceived('foo')
1893
self.assertEqual(bytes, ['foo'])
1896
def test_connectionLost(self):
1898
The L{IProtocol} provider passed to L{Response.deliverBody} has its
1899
C{connectionLost} method called with a L{Failure} wrapping
1900
L{ResponseDone} when the response's C{_bodyDataFinished} method is
1904
class ListConsumer(Protocol):
1905
def connectionLost(self, reason):
1908
consumer = ListConsumer()
1909
response = justTransportResponse(StringTransport())
1910
response.deliverBody(consumer)
1912
response._bodyDataFinished()
1913
lost[0].trap(ResponseDone)
1914
self.assertEqual(len(lost), 1)
1916
# The protocol reference should be dropped, too, to facilitate GC or
1918
self.assertIdentical(response._bodyProtocol, None)
1921
def test_bufferEarlyData(self):
1923
If data is delivered to the L{Response} before a protocol is registered
1924
with C{deliverBody}, that data is buffered until the protocol is
1925
registered and then is delivered.
1928
class ListConsumer(Protocol):
1929
def dataReceived(self, data):
1932
protocol = ListConsumer()
1933
response = justTransportResponse(StringTransport())
1934
response._bodyDataReceived('foo')
1935
response._bodyDataReceived('bar')
1936
response.deliverBody(protocol)
1937
response._bodyDataReceived('baz')
1938
self.assertEqual(bytes, ['foo', 'bar', 'baz'])
1939
# Make sure the implementation-detail-byte-buffer is cleared because
1940
# not clearing it wastes memory.
1941
self.assertIdentical(response._bodyBuffer, None)
1944
def test_multipleStartProducingFails(self):
1946
L{Response.deliverBody} raises L{RuntimeError} if called more than
1949
response = justTransportResponse(StringTransport())
1950
response.deliverBody(Protocol())
1951
self.assertRaises(RuntimeError, response.deliverBody, Protocol())
1954
def test_startProducingAfterFinishedFails(self):
1956
L{Response.deliverBody} raises L{RuntimeError} if called after
1957
L{Response._bodyDataFinished}.
1959
response = justTransportResponse(StringTransport())
1960
response.deliverBody(Protocol())
1961
response._bodyDataFinished()
1962
self.assertRaises(RuntimeError, response.deliverBody, Protocol())
1965
def test_bodyDataReceivedAfterFinishedFails(self):
1967
L{Response._bodyDataReceived} raises L{RuntimeError} if called after
1968
L{Response._bodyDataFinished} but before L{Response.deliverBody}.
1970
response = justTransportResponse(StringTransport())
1971
response._bodyDataFinished()
1972
self.assertRaises(RuntimeError, response._bodyDataReceived, 'foo')
1975
def test_bodyDataReceivedAfterDeliveryFails(self):
1977
L{Response._bodyDataReceived} raises L{RuntimeError} if called after
1978
L{Response._bodyDataFinished} and after L{Response.deliverBody}.
1980
response = justTransportResponse(StringTransport())
1981
response._bodyDataFinished()
1982
response.deliverBody(Protocol())
1983
self.assertRaises(RuntimeError, response._bodyDataReceived, 'foo')
1986
def test_bodyDataFinishedAfterFinishedFails(self):
1988
L{Response._bodyDataFinished} raises L{RuntimeError} if called more
1991
response = justTransportResponse(StringTransport())
1992
response._bodyDataFinished()
1993
self.assertRaises(RuntimeError, response._bodyDataFinished)
1996
def test_bodyDataFinishedAfterDeliveryFails(self):
1998
L{Response._bodyDataFinished} raises L{RuntimeError} if called after
1999
the body has been delivered.
2001
response = justTransportResponse(StringTransport())
2002
response._bodyDataFinished()
2003
response.deliverBody(Protocol())
2004
self.assertRaises(RuntimeError, response._bodyDataFinished)
2007
def test_transportResumed(self):
2009
L{Response.deliverBody} resumes the HTTP connection's transport
2010
before passing it to the transport's C{makeConnection} method.
2013
class ListConsumer(Protocol):
2014
def makeConnection(self, transport):
2015
transportState.append(transport.producerState)
2017
transport = StringTransport()
2018
transport.pauseProducing()
2019
protocol = ListConsumer()
2020
response = justTransportResponse(transport)
2021
self.assertEqual(transport.producerState, 'paused')
2022
response.deliverBody(protocol)
2023
self.assertEqual(transportState, ['producing'])
2026
def test_bodyDataFinishedBeforeStartProducing(self):
2028
If the entire body is delivered to the L{Response} before the
2029
response's C{deliverBody} method is called, the protocol passed to
2030
C{deliverBody} is immediately given the body data and then
2033
transport = StringTransport()
2034
response = justTransportResponse(transport)
2035
response._bodyDataReceived('foo')
2036
response._bodyDataReceived('bar')
2037
response._bodyDataFinished()
2039
protocol = AccumulatingProtocol()
2040
response.deliverBody(protocol)
2041
self.assertEqual(protocol.data, 'foobar')
2042
protocol.closedReason.trap(ResponseDone)
2045
def test_finishedWithErrorWhenConnected(self):
2047
The L{Failure} passed to L{Response._bodyDataFinished} when the response
2048
is in the I{connected} state is passed to the C{connectionLost} method
2049
of the L{IProtocol} provider passed to the L{Response}'s
2050
C{deliverBody} method.
2052
transport = StringTransport()
2053
response = justTransportResponse(transport)
2055
protocol = AccumulatingProtocol()
2056
response.deliverBody(protocol)
2058
# Sanity check - this test is for the connected state
2059
self.assertEqual(response._state, 'CONNECTED')
2060
response._bodyDataFinished(Failure(ArbitraryException()))
2062
protocol.closedReason.trap(ArbitraryException)
2065
def test_finishedWithErrorWhenInitial(self):
2067
The L{Failure} passed to L{Response._bodyDataFinished} when the response
2068
is in the I{initial} state is passed to the C{connectionLost} method of
2069
the L{IProtocol} provider passed to the L{Response}'s C{deliverBody}
2072
transport = StringTransport()
2073
response = justTransportResponse(transport)
2075
# Sanity check - this test is for the initial state
2076
self.assertEqual(response._state, 'INITIAL')
2077
response._bodyDataFinished(Failure(ArbitraryException()))
2079
protocol = AccumulatingProtocol()
2080
response.deliverBody(protocol)
2082
protocol.closedReason.trap(ArbitraryException)