blob: 8db9e4e0712790d4fbdc0ba57b2baddbc9193e14 [file] [log] [blame]
#!/usr/bin/env python
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed
# with this work for additional information regarding copyright
# ownership. The ASF licenses this file to you under the Apache
# License, Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of the
# License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
from twisted.internet import error, protocol, reactor, tcp
from twisted.web import http
print '''1..1 finalChunkEncodingDisconnect
# The proxy forwards the final chunk even if the origin disconnects
# immediately afterward'''
def callback():
print 'not ok 1 - No final chunk yet'
reactor.stop()
reactor.callLater(2, callback)
class factory(http.HTTPFactory):
class protocol(http.HTTPChannel):
class requestFactory(http.Request):
def requestReceived(ctx, method, target, version):
ctx.client = None
ctx.clientproto = version
ctx.write('finalChunkedEncodingDisconnect')
# If the proxy reads the final chunk before it sends the
# response headers, it may send a Content-Length header vs. a
# chunked response
def callback():
try:
ctx.finish()
except RuntimeError:
print 'not ok 1 - Did the proxy crash? (The origin connection closed.)'
reactor.stop()
else:
ctx.transport.loseConnection()
reactor.callLater(1, callback)
origin = tcp.Port(0, factory())
origin.startListening()
print '# Listening on {0}:{1}'.format(*origin.socket.getsockname())
class factory(protocol.ClientFactory):
def clientConnectionFailed(ctx, connector, reason):
print 'Bail out!'
reason.printTraceback()
reactor.stop()
class protocol(http.HTTPClient):
def connectionLost(ctx, reason):
try:
reactor.stop()
except error.ReactorNotRunning:
pass
else:
print 'not ok 1 - Did the proxy crash? (The client connection closed.)'
def connectionMade(ctx):
ctx.transport.write('GET {0}:{1} HTTP/1.1\r\n\r\n'.format(*origin.socket.getsockname()))
def handleHeader(ctx, k, v):
if k.lower() == 'content-length':
print 'not ok 1 - Got a Content-Length header vs. a chunked response'
# No hope of a final chunk now
reactor.stop()
# Avoid calling undefined handleResponse() at the end of the
# message (if the proxy sent a Content-Length header vs. a chunked
# response). (Override connectionLost() when the proxy crashes or
# we stop the reactor.)
#
# Data that was already received will get processed (the end of
# the headers), then shutdown events will fire (connections will
# get closed), and then finally the reactor will grind to a halt.
def handleResponseEnd(ctx):
pass
def handleResponsePart(ctx, data):
if data.endswith('0\r\n\r\n'):
print 'ok 1 - Got the final chunk'
reactor.stop()
tcp.Connector('localhost', 8080, factory(), 30, None, reactor).connect()
reactor.run()