"""Tests for managing HTTP issues (malformed requests, etc)."""
from cherrypy.test import test
test.prefer_parent_path()
import httplib
import cherrypy
import mimetypes
def encode_multipart_formdata(files):
"""Return (content_type, body) ready for httplib.HTTP instance.
files: a sequence of (name, filename, value) tuples for multipart uploads.
"""
BOUNDARY = '________ThIs_Is_tHe_bouNdaRY_$'
L = []
for key, filename, value in files:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
(key, filename))
ct = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
L.append('Content-Type: %s' % ct)
L.append('')
L.append(value)
L.append('--' + BOUNDARY + '--')
L.append('')
body = '\r\n'.join(L)
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
return content_type, body
def setup_server():
class Root:
def index(self, *args, **kwargs):
return "Hello world!"
index.exposed = True
def post_multipart(self, file):
"""Return a summary ("a * 65536\nb * 65536") of the uploaded file."""
contents = file.file.read()
summary = []
curchar = ""
count = 0
for c in contents:
if c == curchar:
count += 1
else:
if count:
summary.append("%s * %d" % (curchar, count))
count = 1
curchar = c
if count:
summary.append("%s * %d" % (curchar, count))
return ", ".join(summary)
post_multipart.exposed = True
cherrypy.tree.mount(Root())
cherrypy.config.update({'environment': 'test_suite',
'server.max_request_body_size': 30000000})
from cherrypy.test import helper
class HTTPTests(helper.CPWebCase):
def test_sockets(self):
# By not including a Content-Length header, cgi.FieldStorage
# will hang. Verify that CP times out the socket and responds
# with 411 Length Required.
if self.scheme == "https":
c = httplib.HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
else:
c = httplib.HTTPConnection('%s:%s' % (self.interface(), self.PORT))
c.request("POST", "/")
self.assertEqual(c.getresponse().status, 411)
def test_post_multipart(self):
alphabet = "abcdefghijklmnopqrstuvwxyz"
# generate file contents for a large post
contents = "".join([c * 65536 for c in alphabet])
# encode as multipart form data
files=[('file', 'file.txt', contents)]
content_type, body = encode_multipart_formdata(files)
# post file
if self.scheme == 'https':
c = httplib.HTTPS('%s:%s' % (self.interface(), self.PORT))
else:
c = httplib.HTTP('%s:%s' % (self.interface(), self.PORT))
c.putrequest('POST', '/post_multipart')
c.putheader('Content-Type', content_type)
c.putheader('Content-Length', str(len(body)))
c.endheaders()
c.send(body)
errcode, errmsg, headers = c.getreply()
self.assertEqual(errcode, 200)
response_body = c.file.read()
self.assertEquals(", ".join(["%s * 65536" % c for c in alphabet]),
response_body)
def test_malformed_request_line(self):
if getattr(cherrypy.server, "using_apache", False):
print "skipped due to known Apache differences...",
return
# Test missing version in Request-Line
if self.scheme == 'https':
c = httplib.HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
else:
c = httplib.HTTPConnection('%s:%s' % (self.interface(), self.PORT))
c._output('GET /')
c._send_output()
response = c.response_class(c.sock, strict=c.strict, method='GET')
response.begin()
self.assertEqual(response.status, 400)
self.assertEqual(response.fp.read(), "Malformed Request-Line")
c.close()
def test_http_over_https(self):
if self.scheme != 'https':
print "skipped (not running HTTPS)...",
return
# Try connecting without SSL.
conn = httplib.HTTPConnection('%s:%s' % (self.interface(), self.PORT))
conn.putrequest("GET", "/", skip_host=True)
conn.putheader("Host", self.HOST)
conn.endheaders()
response = conn.response_class(conn.sock, method="GET")
response.begin()
self.assertEqual(response.status, 400)
self.body = response.read()
self.assertBody("The client sent a plain HTTP request, but this "
"server only speaks HTTPS on this port.")
if __name__ == '__main__':
setup_server()
helper.testmain()
|