~certify-web-dev/twisted/certify-production

« back to all changes in this revision

Viewing changes to twisted/web/test/test_newclient.py

  • Committer: Marc Tardif
  • Date: 2010-05-20 19:56:06 UTC
  • Revision ID: marc.tardif@canonical.com-20100520195606-xdrf0ztlxhvwmmzb
Added twisted-web.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2009 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
"""
 
5
Tests for L{twisted.web._newclient}.
 
6
"""
 
7
 
 
8
__metaclass__ = type
 
9
 
 
10
from zope.interface import implements
 
11
from zope.interface.verify import verifyObject
 
12
 
 
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
 
29
 
 
30
 
 
31
 
 
32
class ArbitraryException(Exception):
 
33
    """
 
34
    A unique, arbitrary exception type which L{twisted.web._newclient} knows
 
35
    nothing about.
 
36
    """
 
37
 
 
38
 
 
39
class AnotherArbitraryException(Exception):
 
40
    """
 
41
    Similar to L{ArbitraryException} but with a different identity.
 
42
    """
 
43
 
 
44
 
 
45
# A re-usable Headers instance for tests which don't really care what headers
 
46
# they're sending.
 
47
_boringHeaders = Headers({'host': ['example.com']})
 
48
 
 
49
 
 
50
def assertWrapperExceptionTypes(self, deferred, mainType, reasonTypes):
 
51
    """
 
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}.
 
55
 
 
56
    This is a helper for testing failures of exceptions which subclass
 
57
    L{_newclient._WrapperException}.
 
58
 
 
59
    @param self: A L{TestCase} instance which will be used to make the
 
60
        assertions.
 
61
 
 
62
    @param deferred: The L{Deferred} which is expected to fail with
 
63
        C{mainType}.
 
64
 
 
65
    @param mainType: A L{_newclient._WrapperException} subclass which will be
 
66
        trapped on C{deferred}.
 
67
 
 
68
    @param reasonTypes: A sequence of exception types which will be trapped on
 
69
        the resulting L{mainType} exception instance's C{reasons} sequence.
 
70
 
 
71
    @return: A L{Deferred} which fires with the C{mainType} instance
 
72
        C{deferred} fails with, or which fails somehow.
 
73
    """
 
74
    def cbFailed(err):
 
75
        for reason, type in zip(err.reasons, reasonTypes):
 
76
            reason.trap(type)
 
77
        self.assertEqual(len(err.reasons), len(reasonTypes))
 
78
        return err
 
79
    d = self.assertFailure(deferred, mainType)
 
80
    d.addCallback(cbFailed)
 
81
    return d
 
82
 
 
83
 
 
84
 
 
85
def assertResponseFailed(self, deferred, reasonTypes):
 
86
    """
 
87
    A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType}
 
88
    of L{ResponseFailed}.
 
89
    """
 
90
    return assertWrapperExceptionTypes(self, deferred, ResponseFailed, reasonTypes)
 
91
 
 
92
 
 
93
 
 
94
def assertRequestGenerationFailed(self, deferred, reasonTypes):
 
95
    """
 
96
    A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType}
 
97
    of L{RequestGenerationFailed}.
 
98
    """
 
99
    return assertWrapperExceptionTypes(self, deferred, RequestGenerationFailed, reasonTypes)
 
100
 
 
101
 
 
102
 
 
103
def assertRequestTransmissionFailed(self, deferred, reasonTypes):
 
104
    """
 
105
    A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType}
 
106
    of L{RequestTransmissionFailed}.
 
107
    """
 
108
    return assertWrapperExceptionTypes(self, deferred, RequestTransmissionFailed, reasonTypes)
 
109
 
 
110
 
 
111
 
 
112
def justTransportResponse(transport):
 
113
    """
 
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
 
117
    them.
 
118
    """
 
119
    return Response(('HTTP', 1, 1), 200, 'OK', _boringHeaders, transport)
 
120
 
 
121
 
 
122
class MakeStatefulDispatcherTests(TestCase):
 
123
    """
 
124
    Tests for L{makeStatefulDispatcher}.
 
125
    """
 
126
    def test_functionCalledByState(self):
 
127
        """
 
128
        A method defined with L{makeStatefulDispatcher} invokes a second
 
129
        method based on the current state of the object.
 
130
        """
 
131
        class Foo:
 
132
            _state = 'A'
 
133
 
 
134
            def bar(self):
 
135
                pass
 
136
            bar = makeStatefulDispatcher('quux', bar)
 
137
 
 
138
            def _quux_A(self):
 
139
                return 'a'
 
140
 
 
141
            def _quux_B(self):
 
142
                return 'b'
 
143
 
 
144
        stateful = Foo()
 
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)
 
150
 
 
151
 
 
152
 
 
153
class HTTPParserTests(TestCase):
 
154
    """
 
155
    Tests for L{HTTPParser} which is responsible for the bulk of the task of
 
156
    parsing HTTP bytes.
 
157
    """
 
158
    def test_statusCallback(self):
 
159
        """
 
160
        L{HTTPParser} calls its C{statusReceived} method when it receives a
 
161
        status line.
 
162
        """
 
163
        status = []
 
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)
 
171
 
 
172
 
 
173
    def _headerTestSetup(self):
 
174
        header = {}
 
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
 
180
 
 
181
 
 
182
    def test_headerCallback(self):
 
183
        """
 
184
        L{HTTPParser} calls its C{headerReceived} method when it receives a
 
185
        header.
 
186
        """
 
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)
 
194
 
 
195
 
 
196
    def test_continuedHeaderCallback(self):
 
197
        """
 
198
        If a header is split over multiple lines, L{HTTPParser} calls
 
199
        C{headerReceived} with the entire value once it is received.
 
200
        """
 
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)
 
208
 
 
209
 
 
210
    def test_fieldContentWhitespace(self):
 
211
        """
 
212
        Leading and trailing linear whitespace is stripped from the header
 
213
        value passed to the C{headerReceived} callback.
 
214
        """
 
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',
 
221
                                  'X-Bar': 'bar'})
 
222
 
 
223
 
 
224
    def test_allHeadersCallback(self):
 
225
        """
 
226
        After the last header is received, L{HTTPParser} calls
 
227
        C{allHeadersReceived}.
 
228
        """
 
229
        called = []
 
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)
 
238
 
 
239
 
 
240
    def test_noHeaderCallback(self):
 
241
        """
 
242
        If there are no headers in the message, L{HTTPParser} does not call
 
243
        C{headerReceived}.
 
244
        """
 
245
        header, protocol = self._headerTestSetup()
 
246
        protocol.dataReceived('\r\n')
 
247
        self.assertEqual(header, {})
 
248
        self.assertEqual(protocol.state, BODY)
 
249
 
 
250
 
 
251
    def test_headersSavedOnResponse(self):
 
252
        """
 
253
        All headers received by L{HTTPParser} are added to
 
254
        L{HTTPParser.headers}.
 
255
        """
 
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')
 
262
        self.assertEqual(
 
263
            list(protocol.headers.getAllRawHeaders()),
 
264
            [('X-Foo', ['bar', 'baz'])])
 
265
 
 
266
 
 
267
    def test_connectionControlHeaders(self):
 
268
        """
 
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.
 
272
        """
 
273
        protocol = HTTPParser()
 
274
        connHeaderNames = [
 
275
            'content-length', 'connection', 'keep-alive', 'te', 'trailers',
 
276
            'transfer-encoding', 'upgrade', 'proxy-connection']
 
277
 
 
278
        for header in connHeaderNames:
 
279
            self.assertTrue(
 
280
                protocol.isConnectionControlHeader(header),
 
281
                "Expecting %r to be a connection control header, but "
 
282
                "wasn't" % (header,))
 
283
        self.assertFalse(
 
284
            protocol.isConnectionControlHeader("date"),
 
285
            "Expecting the arbitrarily selected 'date' header to not be "
 
286
            "a connection control header, but was.")
 
287
 
 
288
 
 
289
    def test_switchToBodyMode(self):
 
290
        """
 
291
        L{HTTPParser.switchToBodyMode} raises L{RuntimeError} if called more
 
292
        than once.
 
293
        """
 
294
        protocol = HTTPParser()
 
295
        protocol.makeConnection(StringTransport())
 
296
        protocol.switchToBodyMode(object())
 
297
        self.assertRaises(RuntimeError, protocol.switchToBodyMode, object())
 
298
 
 
299
 
 
300
 
 
301
class HTTPClientParserTests(TestCase):
 
302
    """
 
303
    Tests for L{HTTPClientParser} which is responsible for parsing HTTP
 
304
    response messages.
 
305
    """
 
306
    def test_parseVersion(self):
 
307
        """
 
308
        L{HTTPClientParser.parseVersion} parses a status line into its three
 
309
        components.
 
310
        """
 
311
        protocol = HTTPClientParser(None, None)
 
312
        self.assertEqual(
 
313
            protocol.parseVersion('CANDY/7.2'),
 
314
            ('CANDY', 7, 2))
 
315
 
 
316
 
 
317
    def test_parseBadVersion(self):
 
318
        """
 
319
        L{HTTPClientParser.parseVersion} raises L{ValueError} when passed an
 
320
        unparsable version.
 
321
        """
 
322
        protocol = HTTPClientParser(None, None)
 
323
        e = BadResponseVersion
 
324
        f = protocol.parseVersion
 
325
 
 
326
        def checkParsing(s):
 
327
            exc = self.assertRaises(e, f, s)
 
328
            self.assertEqual(exc.data, s)
 
329
 
 
330
        checkParsing('foo')
 
331
        checkParsing('foo/bar/baz')
 
332
 
 
333
        checkParsing('foo/')
 
334
        checkParsing('foo/..')
 
335
 
 
336
        checkParsing('foo/a.b')
 
337
        checkParsing('foo/-1.-1')
 
338
 
 
339
 
 
340
    def test_responseStatusParsing(self):
 
341
        """
 
342
        L{HTTPClientParser.statusReceived} parses the version, code, and phrase
 
343
        from the status line and stores them on the response object.
 
344
        """
 
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')
 
352
 
 
353
 
 
354
    def test_badResponseStatus(self):
 
355
        """
 
356
        L{HTTPClientParser.statusReceived} raises L{ParseError} if it is called
 
357
        with a status line which cannot be parsed.
 
358
        """
 
359
        protocol = HTTPClientParser(None, None)
 
360
 
 
361
        def checkParsing(s):
 
362
            exc = self.assertRaises(ParseError, protocol.statusReceived, s)
 
363
            self.assertEqual(exc.data, s)
 
364
 
 
365
        # If there are fewer than three whitespace-delimited parts to the
 
366
        # status line, it is not valid and cannot be parsed.
 
367
        checkParsing('foo')
 
368
        checkParsing('HTTP/1.1 200')
 
369
 
 
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')
 
373
 
 
374
 
 
375
    def _noBodyTest(self, request, response):
 
376
        """
 
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.
 
380
 
 
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.
 
384
 
 
385
        @return: A C{dict} of headers from the response.
 
386
        """
 
387
        header = {}
 
388
        finished = []
 
389
        protocol = HTTPClientParser(request, finished.append)
 
390
        protocol.headerReceived = header.__setitem__
 
391
        body = []
 
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)
 
401
        return header
 
402
 
 
403
 
 
404
    def test_headResponse(self):
 
405
        """
 
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
 
408
        the header callback.
 
409
        """
 
410
        request = Request('HEAD', '/', _boringHeaders, None)
 
411
        status = (
 
412
            'HTTP/1.1 200 OK\r\n'
 
413
            'Content-Length: 10\r\n'
 
414
            '\r\n')
 
415
        header = self._noBodyTest(request, status)
 
416
        self.assertEqual(header, {'Content-Length': '10'})
 
417
 
 
418
 
 
419
    def test_noContentResponse(self):
 
420
        """
 
421
        If the response code is I{NO CONTENT} (204), no body is expected and
 
422
        the body callback is not invoked.
 
423
        """
 
424
        request = Request('GET', '/', _boringHeaders, None)
 
425
        status = (
 
426
            'HTTP/1.1 204 NO CONTENT\r\n'
 
427
            '\r\n')
 
428
        self._noBodyTest(request, status)
 
429
 
 
430
 
 
431
    def test_notModifiedResponse(self):
 
432
        """
 
433
        If the response code is I{NOT MODIFIED} (304), no body is expected and
 
434
        the body callback is not invoked.
 
435
        """
 
436
        request = Request('GET', '/', _boringHeaders, None)
 
437
        status = (
 
438
            'HTTP/1.1 304 NOT MODIFIED\r\n'
 
439
            '\r\n')
 
440
        self._noBodyTest(request, status)
 
441
 
 
442
 
 
443
    def test_responseHeaders(self):
 
444
        """
 
445
        The response headers are added to the response object's C{headers}
 
446
        L{Headers} instance.
 
447
        """
 
448
        protocol = HTTPClientParser(
 
449
            Request('GET', '/', _boringHeaders, None),
 
450
            lambda rest: 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')
 
455
        self.assertEqual(
 
456
            protocol.connHeaders,
 
457
            Headers({}))
 
458
        self.assertEqual(
 
459
            protocol.response.headers,
 
460
            Headers({'x-foo': ['bar']}))
 
461
        self.assertIdentical(protocol.response.length, UNKNOWN_LENGTH)
 
462
 
 
463
 
 
464
    def test_connectionHeaders(self):
 
465
        """
 
466
        The connection control headers are added to the parser's C{connHeaders}
 
467
        L{Headers} instance.
 
468
        """
 
469
        protocol = HTTPClientParser(
 
470
            Request('GET', '/', _boringHeaders, None),
 
471
            lambda rest: 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')
 
477
        self.assertEqual(
 
478
            protocol.response.headers,
 
479
            Headers({}))
 
480
        self.assertEqual(
 
481
            protocol.connHeaders,
 
482
            Headers({'content-length': ['123'],
 
483
                     'connection': ['close']}))
 
484
        self.assertEqual(protocol.response.length, 123)
 
485
 
 
486
 
 
487
    def test_headResponseContentLengthEntityHeader(self):
 
488
        """
 
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.
 
491
        """
 
492
        protocol = HTTPClientParser(
 
493
            Request('HEAD', '/', _boringHeaders, None),
 
494
            lambda rest: 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')
 
499
        self.assertEqual(
 
500
            protocol.response.headers,
 
501
            Headers({'content-length': ['123']}))
 
502
        self.assertEqual(
 
503
            protocol.connHeaders,
 
504
            Headers({}))
 
505
        self.assertEqual(protocol.response.length, 0)
 
506
 
 
507
 
 
508
    def test_contentLength(self):
 
509
        """
 
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}.
 
513
        """
 
514
        finished = []
 
515
        protocol = HTTPClientParser(
 
516
            Request('GET', '/', _boringHeaders, None),
 
517
            finished.append)
 
518
        transport = StringTransport()
 
519
        protocol.makeConnection(transport)
 
520
        protocol.dataReceived('HTTP/1.1 200 OK\r\n')
 
521
        body = []
 
522
        protocol.response._bodyDataReceived = body.append
 
523
        protocol.dataReceived('Content-Length: 10\r\n')
 
524
        protocol.dataReceived('\r\n')
 
525
 
 
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')
 
529
 
 
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, [''])
 
538
 
 
539
 
 
540
    def test_zeroContentLength(self):
 
541
        """
 
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}.
 
545
        """
 
546
        finished = []
 
547
        protocol = HTTPClientParser(
 
548
            Request('GET', '/', _boringHeaders, None),
 
549
            finished.append)
 
550
 
 
551
        protocol.makeConnection(StringTransport())
 
552
        protocol.dataReceived('HTTP/1.1 200 OK\r\n')
 
553
 
 
554
        body = []
 
555
        protocol.response._bodyDataReceived = body.append
 
556
 
 
557
        protocol.dataReceived('Content-Length: 0\r\n')
 
558
        protocol.dataReceived('\r\n')
 
559
 
 
560
        self.assertEqual(protocol.state, DONE)
 
561
        self.assertEqual(body, [])
 
562
        self.assertTrue(finished, [''])
 
563
        self.assertEqual(protocol.response.length, 0)
 
564
 
 
565
 
 
566
 
 
567
    def test_multipleContentLengthHeaders(self):
 
568
        """
 
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.
 
572
        """
 
573
        protocol = HTTPClientParser(
 
574
            Request('GET', '/', _boringHeaders, None),
 
575
            None)
 
576
 
 
577
        protocol.makeConnection(StringTransport())
 
578
        self.assertRaises(
 
579
            ValueError,
 
580
            protocol.dataReceived,
 
581
            'HTTP/1.1 200 OK\r\n'
 
582
            'Content-Length: 1\r\n'
 
583
            'Content-Length: 2\r\n'
 
584
            '\r\n')
 
585
 
 
586
 
 
587
    def test_extraBytesPassedBack(self):
 
588
        """
 
589
        If extra bytes are received past the end of a response, they are passed
 
590
        to the finish callback.
 
591
        """
 
592
        finished = []
 
593
        protocol = HTTPClientParser(
 
594
            Request('GET', '/', _boringHeaders, None),
 
595
            finished.append)
 
596
 
 
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!'])
 
603
 
 
604
 
 
605
    def test_extraBytesPassedBackHEAD(self):
 
606
        """
 
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.
 
609
        """
 
610
        finished = []
 
611
        protocol = HTTPClientParser(
 
612
            Request('HEAD', '/', _boringHeaders, None),
 
613
            finished.append)
 
614
 
 
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!'])
 
621
 
 
622
 
 
623
    def test_chunkedResponseBody(self):
 
624
        """
 
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}.
 
628
        """
 
629
        finished = []
 
630
        protocol = HTTPClientParser(
 
631
            Request('GET', '/', _boringHeaders, None),
 
632
            finished.append)
 
633
        protocol.makeConnection(StringTransport())
 
634
        protocol.dataReceived('HTTP/1.1 200 OK\r\n')
 
635
 
 
636
        body = []
 
637
        protocol.response._bodyDataReceived = body.append
 
638
 
 
639
        protocol.dataReceived('Transfer-Encoding: chunked\r\n')
 
640
        protocol.dataReceived('\r\n')
 
641
 
 
642
        # No data delivered yet
 
643
        self.assertEqual(body, [])
 
644
 
 
645
        # Cannot predict the length of a chunked encoded response body.
 
646
        self.assertIdentical(protocol.response.length, UNKNOWN_LENGTH)
 
647
 
 
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'])
 
653
 
 
654
        # The response's _bodyDataFinished method should be called when the last
 
655
        # chunk is received.  Extra data should be passed to the finished
 
656
        # callback.
 
657
        protocol.dataReceived('0\r\n\r\nextra')
 
658
        self.assertEqual(finished, ['extra'])
 
659
 
 
660
 
 
661
    def test_unknownContentLength(self):
 
662
        """
 
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.
 
666
        """
 
667
        finished = []
 
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')
 
673
 
 
674
        body = []
 
675
        protocol.response._bodyDataReceived = body.append
 
676
 
 
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, [''])
 
683
 
 
684
 
 
685
    def test_contentLengthAndTransferEncoding(self):
 
686
        """
 
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
 
689
        ignored
 
690
        """
 
691
        finished = []
 
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')
 
697
 
 
698
        body = []
 
699
        protocol.response._bodyDataReceived = body.append
 
700
 
 
701
        protocol.dataReceived(
 
702
            'Content-Length: 102\r\n'
 
703
            'Transfer-Encoding: chunked\r\n'
 
704
            '\r\n'
 
705
            '3\r\n'
 
706
            'abc\r\n'
 
707
            '0\r\n'
 
708
            '\r\n')
 
709
 
 
710
        self.assertEqual(body, ['abc'])
 
711
        self.assertEqual(finished, [''])
 
712
 
 
713
 
 
714
    def test_connectionLostBeforeBody(self):
 
715
        """
 
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}.
 
719
        """
 
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()))
 
726
 
 
727
        return assertResponseFailed(
 
728
            self, responseDeferred, [ArbitraryException])
 
729
 
 
730
 
 
731
    def test_connectionLostWithError(self):
 
732
        """
 
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.
 
736
        """
 
737
        transport = StringTransport()
 
738
        protocol = HTTPClientParser(Request('GET', '/', _boringHeaders, None), None)
 
739
        protocol.makeConnection(transport)
 
740
 
 
741
        response = []
 
742
        protocol._responseDeferred.addCallback(response.append)
 
743
        protocol.dataReceived(
 
744
            'HTTP/1.1 200 OK\r\n'
 
745
            'Content-Length: 1\r\n'
 
746
            '\r\n')
 
747
        response = response[0]
 
748
 
 
749
        # Arrange for an exception
 
750
        def fakeBodyDataFinished(err=None):
 
751
            raise ArbitraryException()
 
752
        response._bodyDataFinished = fakeBodyDataFinished
 
753
 
 
754
        protocol.connectionLost(None)
 
755
 
 
756
        self.assertEqual(len(self.flushLoggedErrors(ArbitraryException)), 1)
 
757
 
 
758
 
 
759
 
 
760
class SlowRequest:
 
761
    """
 
762
    L{SlowRequest} is a fake implementation of L{Request} which is easily
 
763
    controlled externally (for example, by code in a test method).
 
764
 
 
765
    @ivar stopped: A flag indicating whether C{stopWriting} has been called.
 
766
 
 
767
    @ivar finished: After C{writeTo} is called, a L{Deferred} which was
 
768
        returned by that method.  L{SlowRequest} will never fire this
 
769
        L{Deferred}.
 
770
    """
 
771
    method = 'GET'
 
772
    stopped = False
 
773
 
 
774
    def writeTo(self, transport):
 
775
        self.finished = Deferred()
 
776
        return self.finished
 
777
 
 
778
 
 
779
    def stopWriting(self):
 
780
        self.stopped = True
 
781
 
 
782
 
 
783
 
 
784
class SimpleRequest:
 
785
    """
 
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.
 
790
    """
 
791
    def writeTo(self, transport):
 
792
        transport.write('SOME BYTES')
 
793
        return succeed(None)
 
794
 
 
795
 
 
796
 
 
797
class HTTP11ClientProtocolTests(TestCase):
 
798
    """
 
799
    Tests for the HTTP 1.1 client protocol implementation,
 
800
    L{HTTP11ClientProtocol}.
 
801
    """
 
802
    def setUp(self):
 
803
        """
 
804
        Create an L{HTTP11ClientProtocol} connected to a fake transport.
 
805
        """
 
806
        self.transport = StringTransport()
 
807
        self.protocol = HTTP11ClientProtocol()
 
808
        self.protocol.makeConnection(self.transport)
 
809
 
 
810
 
 
811
    def test_request(self):
 
812
        """
 
813
        L{HTTP11ClientProtocol.request} accepts a L{Request} and calls its
 
814
        C{writeTo} method with its own transport.
 
815
        """
 
816
        self.protocol.request(SimpleRequest())
 
817
        self.assertEqual(self.transport.value(), 'SOME BYTES')
 
818
 
 
819
 
 
820
    def test_secondRequest(self):
 
821
        """
 
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.
 
825
        """
 
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)
 
832
        return d
 
833
 
 
834
 
 
835
    def test_requestAfterConnectionLost(self):
 
836
        """
 
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.
 
840
        """
 
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)
 
848
        return d
 
849
 
 
850
 
 
851
    def test_failedWriteTo(self):
 
852
        """
 
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.
 
857
        """
 
858
        class BrokenRequest:
 
859
            def writeTo(self, transport):
 
860
                return fail(ArbitraryException())
 
861
 
 
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)
 
871
        return d
 
872
 
 
873
 
 
874
    def test_synchronousWriteToError(self):
 
875
        """
 
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.
 
879
        """
 
880
        class BrokenRequest:
 
881
            def writeTo(self, transport):
 
882
                raise ArbitraryException()
 
883
 
 
884
        d = self.protocol.request(BrokenRequest())
 
885
        return assertRequestGenerationFailed(self, d, [ArbitraryException])
 
886
 
 
887
 
 
888
    def test_connectionLostDuringRequestGeneration(self, mode=None):
 
889
        """
 
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.
 
894
        """
 
895
        request = SlowRequest()
 
896
        d = self.protocol.request(request)
 
897
        d = assertRequestTransmissionFailed(self, d, [ArbitraryException])
 
898
 
 
899
        # The connection hasn't been lost yet.  The request should still be
 
900
        # allowed to do its thing.
 
901
        self.assertFalse(request.stopped)
 
902
 
 
903
        self.protocol.connectionLost(Failure(ArbitraryException()))
 
904
 
 
905
        # Now the connection has been lost.  The request should have been told
 
906
        # to stop writing itself.
 
907
        self.assertTrue(request.stopped)
 
908
 
 
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)
 
915
        else:
 
916
            # Don't fire the writeTo Deferred at all.
 
917
            pass
 
918
        return d
 
919
 
 
920
 
 
921
    def test_connectionLostBeforeGenerationFinished(self):
 
922
        """
 
923
        If the request passed to L{HTTP11ClientProtocol} finishes generation
 
924
        successfully after the L{HTTP11ClientProtocol}'s connection has been
 
925
        lost, nothing happens.
 
926
        """
 
927
        return self.test_connectionLostDuringRequestGeneration('callback')
 
928
 
 
929
 
 
930
    def test_connectionLostBeforeGenerationFailed(self):
 
931
        """
 
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.
 
935
        """
 
936
        return self.test_connectionLostDuringRequestGeneration('errback')
 
937
 
 
938
 
 
939
    def test_receiveSimplestResponse(self):
 
940
        """
 
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.
 
944
        """
 
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"
 
954
            "\r\n")
 
955
        return d
 
956
 
 
957
 
 
958
    def test_receiveResponseHeaders(self):
 
959
        """
 
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.
 
963
        """
 
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"
 
971
            "X-Foo: bar\r\n"
 
972
            "X-Foo: baz\r\n"
 
973
            "\r\n")
 
974
        return d
 
975
 
 
976
 
 
977
    def test_receiveResponseBeforeRequestGenerationDone(self):
 
978
        """
 
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.
 
982
        """
 
983
        request = SlowRequest()
 
984
        d = self.protocol.request(request)
 
985
        self.protocol.dataReceived(
 
986
            "HTTP/1.1 200 OK\r\n"
 
987
            "X-Foo: bar\r\n"
 
988
            "Content-Length: 6\r\n"
 
989
            "\r\n"
 
990
            "foobar")
 
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")
 
1004
 
 
1005
            # Also nothing bad should happen if the request does finally
 
1006
            # finish, even though it is completely irrelevant.
 
1007
            request.finished.callback(None)
 
1008
 
 
1009
        d.addCallback(cbAllResponse)
 
1010
        return d
 
1011
 
 
1012
 
 
1013
    def test_receiveResponseBody(self):
 
1014
        """
 
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.
 
1018
        """
 
1019
        protocol = AccumulatingProtocol()
 
1020
        whenFinished = protocol.closedDeferred = Deferred()
 
1021
        requestDeferred = self.protocol.request(Request('GET', '/', _boringHeaders, None))
 
1022
 
 
1023
        self.protocol.dataReceived(
 
1024
            "HTTP/1.1 200 OK\r\n"
 
1025
            "Content-Length: 6\r\n"
 
1026
            "\r")
 
1027
 
 
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.
 
1032
        result = []
 
1033
        requestDeferred.addCallback(result.append)
 
1034
 
 
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]
 
1040
 
 
1041
        response.deliverBody(protocol)
 
1042
 
 
1043
        self.protocol.dataReceived("foo")
 
1044
        self.protocol.dataReceived("bar")
 
1045
 
 
1046
        def cbAllResponse(ignored):
 
1047
            self.assertEqual(protocol.data, "foobar")
 
1048
            protocol.closedReason.trap(ResponseDone)
 
1049
        whenFinished.addCallback(cbAllResponse)
 
1050
        return whenFinished
 
1051
 
 
1052
 
 
1053
    def test_responseBodyFinishedWhenConnectionLostWhenContentLengthIsUnknown(
 
1054
        self):
 
1055
        """
 
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}
 
1059
        exception.
 
1060
        """
 
1061
        requestDeferred = self.protocol.request(Request('GET', '/', _boringHeaders, None))
 
1062
        self.protocol.dataReceived(
 
1063
            "HTTP/1.1 200 OK\r\n"
 
1064
            "\r\n")
 
1065
 
 
1066
        result = []
 
1067
        requestDeferred.addCallback(result.append)
 
1068
        response = result[0]
 
1069
 
 
1070
        protocol = AccumulatingProtocol()
 
1071
        response.deliverBody(protocol)
 
1072
 
 
1073
        self.protocol.dataReceived("foo")
 
1074
        self.protocol.dataReceived("bar")
 
1075
 
 
1076
        self.assertEqual(protocol.data, "foobar")
 
1077
        self.protocol.connectionLost(
 
1078
            Failure(ConnectionDone("low-level transport disconnected")))
 
1079
 
 
1080
        protocol.closedReason.trap(PotentialDataLoss)
 
1081
 
 
1082
 
 
1083
    def test_chunkedResponseBodyUnfinishedWhenConnectionLost(self):
 
1084
        """
 
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.
 
1089
        """
 
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"
 
1094
            "\r\n")
 
1095
 
 
1096
        result = []
 
1097
        requestDeferred.addCallback(result.append)
 
1098
        response = result[0]
 
1099
 
 
1100
        protocol = AccumulatingProtocol()
 
1101
        response.deliverBody(protocol)
 
1102
 
 
1103
        self.protocol.dataReceived("3\r\nfoo\r\n")
 
1104
        self.protocol.dataReceived("3\r\nbar\r\n")
 
1105
 
 
1106
        self.assertEqual(protocol.data, "foobar")
 
1107
 
 
1108
        self.protocol.connectionLost(Failure(ArbitraryException()))
 
1109
 
 
1110
        return assertResponseFailed(
 
1111
            self, fail(protocol.closedReason), [ArbitraryException, _DataLoss])
 
1112
 
 
1113
 
 
1114
    def test_parserDataReceivedException(self):
 
1115
        """
 
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.
 
1120
        """
 
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])
 
1124
        def cbFailed(exc):
 
1125
            self.assertTrue(self.transport.disconnecting)
 
1126
            self.assertEqual(
 
1127
                exc.reasons[0].value.data, 'unparseable garbage goes here')
 
1128
 
 
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
 
1132
            # exception.
 
1133
            self.protocol.connectionLost(Failure(ConnectionDone("it is done")))
 
1134
 
 
1135
        d.addCallback(cbFailed)
 
1136
        return d
 
1137
 
 
1138
 
 
1139
    def test_proxyStopped(self):
 
1140
        """
 
1141
        When the HTTP response parser is disconnected, the
 
1142
        L{TransportProxyProducer} which was connected to it as a transport is
 
1143
        stopped.
 
1144
        """
 
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])
 
1151
 
 
1152
 
 
1153
 
 
1154
class StringProducer:
 
1155
    """
 
1156
    L{StringProducer} is a dummy body producer.
 
1157
 
 
1158
    @ivar stopped: A flag which indicates whether or not C{stopProducing} has
 
1159
        been called.
 
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
 
1164
        L{Deferred}.
 
1165
    """
 
1166
    implements(IBodyProducer)
 
1167
 
 
1168
    stopped = False
 
1169
 
 
1170
    def __init__(self, length):
 
1171
        self.length = length
 
1172
 
 
1173
 
 
1174
    def startProducing(self, consumer):
 
1175
        self.consumer = consumer
 
1176
        self.finished = Deferred()
 
1177
        return self.finished
 
1178
 
 
1179
 
 
1180
    def stopProducing(self):
 
1181
        self.stopped = True
 
1182
 
 
1183
 
 
1184
 
 
1185
class RequestTests(TestCase):
 
1186
    """
 
1187
    Tests for L{Request}.
 
1188
    """
 
1189
    def setUp(self):
 
1190
        self.transport = StringTransport()
 
1191
 
 
1192
 
 
1193
    def test_sendSimplestRequest(self):
 
1194
        """
 
1195
        L{Request.writeTo} formats the request data and writes it to the given
 
1196
        transport.
 
1197
        """
 
1198
        Request('GET', '/', _boringHeaders, None).writeTo(self.transport)
 
1199
        self.assertEqual(
 
1200
            self.transport.value(),
 
1201
            "GET / HTTP/1.1\r\n"
 
1202
            "Connection: close\r\n"
 
1203
            "Host: example.com\r\n"
 
1204
            "\r\n")
 
1205
 
 
1206
 
 
1207
    def test_sendRequestHeaders(self):
 
1208
        """
 
1209
        L{Request.writeTo} formats header data and writes it to the given
 
1210
        transport.
 
1211
        """
 
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:]
 
1218
        lines.sort()
 
1219
        self.assertEqual(
 
1220
            lines,
 
1221
            ["Connection: close",
 
1222
             "Host: example.com",
 
1223
             "X-Foo: bar",
 
1224
             "X-Foo: baz"])
 
1225
 
 
1226
 
 
1227
    def test_sendChunkedRequestBody(self):
 
1228
        """
 
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.
 
1232
        """
 
1233
        producer = StringProducer(UNKNOWN_LENGTH)
 
1234
        request = Request('POST', '/bar', _boringHeaders, producer)
 
1235
        request.writeTo(self.transport)
 
1236
 
 
1237
        self.assertNotIdentical(producer.consumer, None)
 
1238
        self.assertIdentical(self.transport.producer, producer)
 
1239
        self.assertTrue(self.transport.streaming)
 
1240
 
 
1241
        self.assertEqual(
 
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"
 
1247
            "\r\n")
 
1248
        self.transport.clear()
 
1249
 
 
1250
        producer.consumer.write('x' * 3)
 
1251
        producer.consumer.write('y' * 15)
 
1252
        producer.finished.callback(None)
 
1253
        self.assertIdentical(self.transport.producer, None)
 
1254
        self.assertEqual(
 
1255
            self.transport.value(),
 
1256
            "3\r\n"
 
1257
            "xxx\r\n"
 
1258
            "f\r\n"
 
1259
            "yyyyyyyyyyyyyyy\r\n"
 
1260
            "0\r\n"
 
1261
            "\r\n")
 
1262
 
 
1263
 
 
1264
    def test_sendChunkedRequestBodyWithError(self):
 
1265
        """
 
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
 
1271
        transport.
 
1272
        """
 
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)
 
1283
        return d
 
1284
 
 
1285
 
 
1286
    def test_sendRequestBodyWithLength(self):
 
1287
        """
 
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.
 
1291
        """
 
1292
        producer = StringProducer(3)
 
1293
        request = Request('POST', '/bar', _boringHeaders, producer)
 
1294
        request.writeTo(self.transport)
 
1295
 
 
1296
        self.assertNotIdentical(producer.consumer, None)
 
1297
        self.assertIdentical(self.transport.producer, producer)
 
1298
        self.assertTrue(self.transport.streaming)
 
1299
 
 
1300
        self.assertEqual(
 
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"
 
1306
            "\r\n")
 
1307
        self.transport.clear()
 
1308
 
 
1309
        producer.consumer.write('abc')
 
1310
        producer.finished.callback(None)
 
1311
        self.assertIdentical(self.transport.producer, None)
 
1312
        self.assertEqual(self.transport.value(), "abc")
 
1313
 
 
1314
 
 
1315
    def test_sendRequestBodyWithTooFewBytes(self):
 
1316
        """
 
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.
 
1321
        """
 
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)
 
1329
 
 
1330
 
 
1331
    def _sendRequestBodyWithTooManyBytesTest(self, finisher):
 
1332
        """
 
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}.
 
1338
 
 
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.
 
1342
        """
 
1343
        producer = StringProducer(3)
 
1344
        request = Request('POST', '/bar', _boringHeaders, producer)
 
1345
        writeDeferred = request.writeTo(self.transport)
 
1346
 
 
1347
        producer.consumer.write('ab')
 
1348
 
 
1349
        # The producer hasn't misbehaved yet, so it shouldn't have been
 
1350
        # stopped.
 
1351
        self.assertFalse(producer.stopped)
 
1352
 
 
1353
        producer.consumer.write('cd')
 
1354
 
 
1355
        # Now the producer *has* misbehaved, so we should have tried to
 
1356
        # make it stop.
 
1357
        self.assertTrue(producer.stopped)
 
1358
 
 
1359
        # The transport should have had the producer unregistered from it as
 
1360
        # well.
 
1361
        self.assertIdentical(self.transport.producer, None)
 
1362
 
 
1363
        def cbFailed(exc):
 
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.
 
1369
            self.assertEqual(
 
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"
 
1375
                "\r\n"
 
1376
                "ab")
 
1377
            self.transport.clear()
 
1378
 
 
1379
            # Subsequent writes should be ignored, as should firing the
 
1380
            # Deferred returned from startProducing.
 
1381
            self.assertRaises(ExcessWrite, producer.consumer.write, 'ef')
 
1382
 
 
1383
            # Likewise, if the Deferred returned from startProducing fires,
 
1384
            # this should more or less be ignored (aside from possibly logging
 
1385
            # an error).
 
1386
            finisher(producer)
 
1387
 
 
1388
            # There should have been nothing further written to the transport.
 
1389
            self.assertEqual(self.transport.value(), "")
 
1390
 
 
1391
        d = self.assertFailure(writeDeferred, WrongBodyLength)
 
1392
        d.addCallback(cbFailed)
 
1393
        return d
 
1394
 
 
1395
 
 
1396
    def test_sendRequestBodyWithTooManyBytes(self):
 
1397
        """
 
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.
 
1402
        """
 
1403
        def finisher(producer):
 
1404
            producer.finished.callback(None)
 
1405
        return self._sendRequestBodyWithTooManyBytesTest(finisher)
 
1406
 
 
1407
 
 
1408
    def test_sendRequestBodyErrorWithTooManyBytes(self):
 
1409
        """
 
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.
 
1414
        """
 
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)
 
1420
 
 
1421
 
 
1422
    def test_sendRequestBodyErrorWithConsumerError(self):
 
1423
        """
 
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}.
 
1429
 
 
1430
        This is a whitebox test.
 
1431
        """
 
1432
        producer = StringProducer(3)
 
1433
        request = Request('POST', '/bar', _boringHeaders, producer)
 
1434
        writeDeferred = request.writeTo(self.transport)
 
1435
 
 
1436
        finishedConsuming = producer.consumer._finished
 
1437
 
 
1438
        producer.consumer.write('abc')
 
1439
        producer.finished.callback(None)
 
1440
 
 
1441
        finishedConsuming.errback(ArbitraryException())
 
1442
        self.assertEqual(len(self.flushLoggedErrors(ArbitraryException)), 1)
 
1443
 
 
1444
 
 
1445
    def _sendRequestBodyFinishedEarlyThenTooManyBytes(self, finisher):
 
1446
        """
 
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.
 
1451
        """
 
1452
        producer = StringProducer(3)
 
1453
        request = Request('POST', '/bar', _boringHeaders, producer)
 
1454
        writeDeferred = request.writeTo(self.transport)
 
1455
 
 
1456
        producer.consumer.write('ab')
 
1457
        finisher(producer)
 
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
 
1463
 
 
1464
 
 
1465
    def test_sendRequestBodyFinishedEarlyThenTooManyBytes(self):
 
1466
        """
 
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}.
 
1471
        """
 
1472
        def finisher(producer):
 
1473
            producer.finished.callback(None)
 
1474
        return self.assertFailure(
 
1475
            self._sendRequestBodyFinishedEarlyThenTooManyBytes(finisher),
 
1476
            WrongBodyLength)
 
1477
 
 
1478
 
 
1479
    def test_sendRequestBodyErroredEarlyThenTooManyBytes(self):
 
1480
        """
 
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.
 
1485
        """
 
1486
        def finisher(producer):
 
1487
            producer.finished.errback(ArbitraryException())
 
1488
        return self.assertFailure(
 
1489
            self._sendRequestBodyFinishedEarlyThenTooManyBytes(finisher),
 
1490
            ArbitraryException)
 
1491
 
 
1492
 
 
1493
    def test_sendChunkedRequestBodyFinishedThenWriteMore(self, _with=None):
 
1494
        """
 
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.
 
1499
        """
 
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()
 
1505
 
 
1506
        self.assertRaises(ExcessWrite, producer.consumer.write, 'foo')
 
1507
        self.assertEqual(self.transport.value(), "")
 
1508
        return writeDeferred
 
1509
 
 
1510
 
 
1511
    def test_sendChunkedRequestBodyFinishedWithErrorThenWriteMore(self):
 
1512
        """
 
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.
 
1517
        """
 
1518
        d = self.test_sendChunkedRequestBodyFinishedThenWriteMore(
 
1519
            Failure(ArbitraryException()))
 
1520
        return self.assertFailure(d, ArbitraryException)
 
1521
 
 
1522
 
 
1523
    def test_sendRequestBodyWithError(self):
 
1524
        """
 
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
 
1528
        L{Failure}.
 
1529
        """
 
1530
        producer = StringProducer(5)
 
1531
        request = Request('POST', '/bar', _boringHeaders, producer)
 
1532
        writeDeferred = request.writeTo(self.transport)
 
1533
 
 
1534
        # Sanity check - the producer should be registered with the underlying
 
1535
        # transport.
 
1536
        self.assertIdentical(self.transport.producer, producer)
 
1537
        self.assertTrue(self.transport.streaming)
 
1538
 
 
1539
        producer.consumer.write('ab')
 
1540
        self.assertEqual(
 
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"
 
1546
            "\r\n"
 
1547
            "ab")
 
1548
 
 
1549
        self.assertFalse(self.transport.disconnecting)
 
1550
        producer.finished.errback(Failure(ArbitraryException()))
 
1551
 
 
1552
        # Disconnection is handled by a higher level.  Request should leave the
 
1553
        # transport alone in this case.
 
1554
        self.assertFalse(self.transport.disconnecting)
 
1555
 
 
1556
        # Oh.  Except it should unregister the producer that it registered.
 
1557
        self.assertIdentical(self.transport.producer, None)
 
1558
 
 
1559
        return self.assertFailure(writeDeferred, ArbitraryException)
 
1560
 
 
1561
    def test_hostHeaderRequired(self):
 
1562
        """
 
1563
        L{Request.writeTo} raises L{BadHeaders} if there is not exactly one
 
1564
        I{Host} header and writes nothing to the given transport.
 
1565
        """
 
1566
        request = Request('GET', '/', Headers({}), None)
 
1567
        self.assertRaises(BadHeaders, request.writeTo, self.transport)
 
1568
        self.assertEqual(self.transport.value(), '')
 
1569
 
 
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(), '')
 
1573
 
 
1574
 
 
1575
    def test_stopWriting(self):
 
1576
        """
 
1577
        L{Request.stopWriting} calls its body producer's C{stopProducing}
 
1578
        method.
 
1579
        """
 
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)
 
1586
 
 
1587
 
 
1588
    def test_brokenStopProducing(self):
 
1589
        """
 
1590
        If the body producer's C{stopProducing} method raises an exception,
 
1591
        L{Request.stopWriting} logs it and does not re-raise it.
 
1592
        """
 
1593
        producer = StringProducer(3)
 
1594
        def brokenStopProducing():
 
1595
            raise ArbitraryException("stopProducing is busted")
 
1596
        producer.stopProducing = brokenStopProducing
 
1597
 
 
1598
        request = Request('GET', '/', _boringHeaders, producer)
 
1599
        d = request.writeTo(self.transport)
 
1600
        request.stopWriting()
 
1601
        self.assertEqual(
 
1602
            len(self.flushLoggedErrors(ArbitraryException)), 1)
 
1603
 
 
1604
 
 
1605
 
 
1606
class LengthEnforcingConsumerTests(TestCase):
 
1607
    """
 
1608
    Tests for L{LengthEnforcingConsumer}.
 
1609
    """
 
1610
    def setUp(self):
 
1611
        self.result = Deferred()
 
1612
        self.producer = StringProducer(10)
 
1613
        self.transport = StringTransport()
 
1614
        self.enforcer = LengthEnforcingConsumer(
 
1615
            self.producer, self.transport, self.result)
 
1616
 
 
1617
 
 
1618
    def test_write(self):
 
1619
        """
 
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.
 
1623
        """
 
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')
 
1629
 
 
1630
 
 
1631
    def test_finishedEarly(self):
 
1632
        """
 
1633
        L{LengthEnforcingConsumer._noMoreWritesExpected} raises
 
1634
        L{WrongBodyLength} if it is called before the indicated number of bytes
 
1635
        have been written.
 
1636
        """
 
1637
        self.enforcer.write('x' * 9)
 
1638
        self.assertRaises(WrongBodyLength, self.enforcer._noMoreWritesExpected)
 
1639
 
 
1640
 
 
1641
    def test_writeTooMany(self, _unregisterAfter=False):
 
1642
        """
 
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.
 
1648
        """
 
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)
 
1656
 
 
1657
 
 
1658
    def test_writeAfterNoMoreExpected(self):
 
1659
        """
 
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}.
 
1663
        """
 
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)
 
1669
 
 
1670
 
 
1671
    def test_finishedLate(self):
 
1672
        """
 
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}.
 
1676
        """
 
1677
        return self.test_writeTooMany(True)
 
1678
 
 
1679
 
 
1680
    def test_finished(self):
 
1681
        """
 
1682
        If L{LengthEnforcingConsumer._noMoreWritesExpected} is called after
 
1683
        the correct number of bytes have been written it returns C{None}.
 
1684
        """
 
1685
        self.enforcer.write('x' * 10)
 
1686
        self.assertIdentical(self.enforcer._noMoreWritesExpected(), None)
 
1687
 
 
1688
 
 
1689
    def test_stopProducingRaises(self):
 
1690
        """
 
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
 
1695
        L{Deferred}.
 
1696
        """
 
1697
        def brokenStopProducing():
 
1698
            StringProducer.stopProducing(self.producer)
 
1699
            raise ArbitraryException("stopProducing is busted")
 
1700
        self.producer.stopProducing = brokenStopProducing
 
1701
 
 
1702
        def cbFinished(ignored):
 
1703
            self.assertEqual(
 
1704
                len(self.flushLoggedErrors(ArbitraryException)), 1)
 
1705
        d = self.test_writeTooMany()
 
1706
        d.addCallback(cbFinished)
 
1707
        return d
 
1708
 
 
1709
 
 
1710
 
 
1711
class RequestBodyConsumerTests(TestCase):
 
1712
    """
 
1713
    Tests for L{ChunkedEncoder} which sits between an L{ITransport} and a
 
1714
    request/response body producer and chunked encodes everything written to
 
1715
    it.
 
1716
    """
 
1717
    def test_interface(self):
 
1718
        """
 
1719
        L{ChunkedEncoder} instances provide L{IConsumer}.
 
1720
        """
 
1721
        self.assertTrue(
 
1722
            verifyObject(IConsumer, ChunkedEncoder(StringTransport())))
 
1723
 
 
1724
 
 
1725
    def test_write(self):
 
1726
        """
 
1727
        L{ChunkedEncoder.write} writes to the transport the chunked encoded
 
1728
        form of the bytes passed to it.
 
1729
        """
 
1730
        transport = StringTransport()
 
1731
        encoder = ChunkedEncoder(transport)
 
1732
        encoder.write('foo')
 
1733
        self.assertEqual(transport.value(), '3\r\nfoo\r\n')
 
1734
        transport.clear()
 
1735
        encoder.write('x' * 16)
 
1736
        self.assertEqual(transport.value(), '10\r\n' + 'x' * 16 + '\r\n')
 
1737
 
 
1738
 
 
1739
    def test_producerRegistration(self):
 
1740
        """
 
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.
 
1745
        """
 
1746
        transport = StringTransport()
 
1747
        producer = object()
 
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')
 
1755
 
 
1756
 
 
1757
 
 
1758
class TransportProxyProducerTests(TestCase):
 
1759
    """
 
1760
    Tests for L{TransportProxyProducer} which proxies the L{IPushProducer}
 
1761
    interface of a transport.
 
1762
    """
 
1763
    def test_interface(self):
 
1764
        """
 
1765
        L{TransportProxyProducer} instances provide L{IPushProducer}.
 
1766
        """
 
1767
        self.assertTrue(
 
1768
            verifyObject(IPushProducer, TransportProxyProducer(None)))
 
1769
 
 
1770
 
 
1771
    def test_stopProxyingUnreferencesProducer(self):
 
1772
        """
 
1773
        L{TransportProxyProducer._stopProxying} drops the reference to the
 
1774
        wrapped L{IPushProducer} provider.
 
1775
        """
 
1776
        transport = StringTransport()
 
1777
        proxy = TransportProxyProducer(transport)
 
1778
        self.assertIdentical(proxy._producer, transport)
 
1779
        proxy._stopProxying()
 
1780
        self.assertIdentical(proxy._producer, None)
 
1781
 
 
1782
 
 
1783
    def test_resumeProducing(self):
 
1784
        """
 
1785
        L{TransportProxyProducer.resumeProducing} calls the wrapped
 
1786
        transport's C{resumeProducing} method unless told to stop proxying.
 
1787
        """
 
1788
        transport = StringTransport()
 
1789
        transport.pauseProducing()
 
1790
 
 
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')
 
1797
 
 
1798
        transport.pauseProducing()
 
1799
        proxy._stopProxying()
 
1800
 
 
1801
        # The proxy should no longer do anything to the transport.
 
1802
        proxy.resumeProducing()
 
1803
        self.assertEqual(transport.producerState, 'paused')
 
1804
 
 
1805
 
 
1806
    def test_pauseProducing(self):
 
1807
        """
 
1808
        L{TransportProxyProducer.pauseProducing} calls the wrapped transport's
 
1809
        C{pauseProducing} method unless told to stop proxying.
 
1810
        """
 
1811
        transport = StringTransport()
 
1812
 
 
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')
 
1819
 
 
1820
        transport.resumeProducing()
 
1821
        proxy._stopProxying()
 
1822
 
 
1823
        # The proxy should no longer do anything to the transport.
 
1824
        proxy.pauseProducing()
 
1825
        self.assertEqual(transport.producerState, 'producing')
 
1826
 
 
1827
 
 
1828
    def test_stopProducing(self):
 
1829
        """
 
1830
        L{TransportProxyProducer.stopProducing} calls the wrapped transport's
 
1831
        C{stopProducing} method unless told to stop proxying.
 
1832
        """
 
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')
 
1840
 
 
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')
 
1847
 
 
1848
 
 
1849
 
 
1850
class ResponseTests(TestCase):
 
1851
    """
 
1852
    Tests for L{Response}.
 
1853
    """
 
1854
    def test_makeConnection(self):
 
1855
        """
 
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.
 
1859
        """
 
1860
        producers = []
 
1861
        transport = StringTransport()
 
1862
        class SomeProtocol(Protocol):
 
1863
            def makeConnection(self, producer):
 
1864
                producers.append(producer)
 
1865
 
 
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')
 
1874
 
 
1875
 
 
1876
    def test_dataReceived(self):
 
1877
        """
 
1878
        The L{IProtocol} provider passed to L{Response.deliverBody} has its
 
1879
        C{dataReceived} method called with bytes received as part of the
 
1880
        response body.
 
1881
        """
 
1882
        bytes = []
 
1883
        class ListConsumer(Protocol):
 
1884
            def dataReceived(self, data):
 
1885
                bytes.append(data)
 
1886
 
 
1887
 
 
1888
        consumer = ListConsumer()
 
1889
        response = justTransportResponse(StringTransport())
 
1890
        response.deliverBody(consumer)
 
1891
 
 
1892
        response._bodyDataReceived('foo')
 
1893
        self.assertEqual(bytes, ['foo'])
 
1894
 
 
1895
 
 
1896
    def test_connectionLost(self):
 
1897
        """
 
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
 
1901
        called.
 
1902
        """
 
1903
        lost = []
 
1904
        class ListConsumer(Protocol):
 
1905
            def connectionLost(self, reason):
 
1906
                lost.append(reason)
 
1907
 
 
1908
        consumer = ListConsumer()
 
1909
        response = justTransportResponse(StringTransport())
 
1910
        response.deliverBody(consumer)
 
1911
 
 
1912
        response._bodyDataFinished()
 
1913
        lost[0].trap(ResponseDone)
 
1914
        self.assertEqual(len(lost), 1)
 
1915
 
 
1916
        # The protocol reference should be dropped, too, to facilitate GC or
 
1917
        # whatever.
 
1918
        self.assertIdentical(response._bodyProtocol, None)
 
1919
 
 
1920
 
 
1921
    def test_bufferEarlyData(self):
 
1922
        """
 
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.
 
1926
        """
 
1927
        bytes = []
 
1928
        class ListConsumer(Protocol):
 
1929
            def dataReceived(self, data):
 
1930
                bytes.append(data)
 
1931
 
 
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)
 
1942
 
 
1943
 
 
1944
    def test_multipleStartProducingFails(self):
 
1945
        """
 
1946
        L{Response.deliverBody} raises L{RuntimeError} if called more than
 
1947
        once.
 
1948
        """
 
1949
        response = justTransportResponse(StringTransport())
 
1950
        response.deliverBody(Protocol())
 
1951
        self.assertRaises(RuntimeError, response.deliverBody, Protocol())
 
1952
 
 
1953
 
 
1954
    def test_startProducingAfterFinishedFails(self):
 
1955
        """
 
1956
        L{Response.deliverBody} raises L{RuntimeError} if called after
 
1957
        L{Response._bodyDataFinished}.
 
1958
        """
 
1959
        response = justTransportResponse(StringTransport())
 
1960
        response.deliverBody(Protocol())
 
1961
        response._bodyDataFinished()
 
1962
        self.assertRaises(RuntimeError, response.deliverBody, Protocol())
 
1963
 
 
1964
 
 
1965
    def test_bodyDataReceivedAfterFinishedFails(self):
 
1966
        """
 
1967
        L{Response._bodyDataReceived} raises L{RuntimeError} if called after
 
1968
        L{Response._bodyDataFinished} but before L{Response.deliverBody}.
 
1969
        """
 
1970
        response = justTransportResponse(StringTransport())
 
1971
        response._bodyDataFinished()
 
1972
        self.assertRaises(RuntimeError, response._bodyDataReceived, 'foo')
 
1973
 
 
1974
 
 
1975
    def test_bodyDataReceivedAfterDeliveryFails(self):
 
1976
        """
 
1977
        L{Response._bodyDataReceived} raises L{RuntimeError} if called after
 
1978
        L{Response._bodyDataFinished} and after L{Response.deliverBody}.
 
1979
        """
 
1980
        response = justTransportResponse(StringTransport())
 
1981
        response._bodyDataFinished()
 
1982
        response.deliverBody(Protocol())
 
1983
        self.assertRaises(RuntimeError, response._bodyDataReceived, 'foo')
 
1984
 
 
1985
 
 
1986
    def test_bodyDataFinishedAfterFinishedFails(self):
 
1987
        """
 
1988
        L{Response._bodyDataFinished} raises L{RuntimeError} if called more
 
1989
        than once.
 
1990
        """
 
1991
        response = justTransportResponse(StringTransport())
 
1992
        response._bodyDataFinished()
 
1993
        self.assertRaises(RuntimeError, response._bodyDataFinished)
 
1994
 
 
1995
 
 
1996
    def test_bodyDataFinishedAfterDeliveryFails(self):
 
1997
        """
 
1998
        L{Response._bodyDataFinished} raises L{RuntimeError} if called after
 
1999
        the body has been delivered.
 
2000
        """
 
2001
        response = justTransportResponse(StringTransport())
 
2002
        response._bodyDataFinished()
 
2003
        response.deliverBody(Protocol())
 
2004
        self.assertRaises(RuntimeError, response._bodyDataFinished)
 
2005
 
 
2006
 
 
2007
    def test_transportResumed(self):
 
2008
        """
 
2009
        L{Response.deliverBody} resumes the HTTP connection's transport
 
2010
        before passing it to the transport's C{makeConnection} method.
 
2011
        """
 
2012
        transportState = []
 
2013
        class ListConsumer(Protocol):
 
2014
            def makeConnection(self, transport):
 
2015
                transportState.append(transport.producerState)
 
2016
 
 
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'])
 
2024
 
 
2025
 
 
2026
    def test_bodyDataFinishedBeforeStartProducing(self):
 
2027
        """
 
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
 
2031
        disconnected.
 
2032
        """
 
2033
        transport = StringTransport()
 
2034
        response = justTransportResponse(transport)
 
2035
        response._bodyDataReceived('foo')
 
2036
        response._bodyDataReceived('bar')
 
2037
        response._bodyDataFinished()
 
2038
 
 
2039
        protocol = AccumulatingProtocol()
 
2040
        response.deliverBody(protocol)
 
2041
        self.assertEqual(protocol.data, 'foobar')
 
2042
        protocol.closedReason.trap(ResponseDone)
 
2043
 
 
2044
 
 
2045
    def test_finishedWithErrorWhenConnected(self):
 
2046
        """
 
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.
 
2051
        """
 
2052
        transport = StringTransport()
 
2053
        response = justTransportResponse(transport)
 
2054
 
 
2055
        protocol = AccumulatingProtocol()
 
2056
        response.deliverBody(protocol)
 
2057
 
 
2058
        # Sanity check - this test is for the connected state
 
2059
        self.assertEqual(response._state, 'CONNECTED')
 
2060
        response._bodyDataFinished(Failure(ArbitraryException()))
 
2061
 
 
2062
        protocol.closedReason.trap(ArbitraryException)
 
2063
 
 
2064
 
 
2065
    def test_finishedWithErrorWhenInitial(self):
 
2066
        """
 
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}
 
2070
        method.
 
2071
        """
 
2072
        transport = StringTransport()
 
2073
        response = justTransportResponse(transport)
 
2074
 
 
2075
        # Sanity check - this test is for the initial state
 
2076
        self.assertEqual(response._state, 'INITIAL')
 
2077
        response._bodyDataFinished(Failure(ArbitraryException()))
 
2078
 
 
2079
        protocol = AccumulatingProtocol()
 
2080
        response.deliverBody(protocol)
 
2081
 
 
2082
        protocol.closedReason.trap(ArbitraryException)