Fixed python_path problem.
[smonitor.git] / lib / cherrypy / test / test_http.py
blobeb72b5bfbb24a80518eb8f3e2e45d818af2801c7
1 """Tests for managing HTTP issues (malformed requests, etc)."""
3 import mimetypes
5 import cherrypy
6 from cherrypy._cpcompat import HTTPConnection, HTTPSConnection, ntob
9 def encode_multipart_formdata(files):
10 """Return (content_type, body) ready for httplib.HTTP instance.
12 files: a sequence of (name, filename, value) tuples for multipart uploads.
13 """
14 BOUNDARY = '________ThIs_Is_tHe_bouNdaRY_$'
15 L = []
16 for key, filename, value in files:
17 L.append('--' + BOUNDARY)
18 L.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
19 (key, filename))
20 ct = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
21 L.append('Content-Type: %s' % ct)
22 L.append('')
23 L.append(value)
24 L.append('--' + BOUNDARY + '--')
25 L.append('')
26 body = '\r\n'.join(L)
27 content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
28 return content_type, body
33 from cherrypy.test import helper
35 class HTTPTests(helper.CPWebCase):
37 def setup_server():
38 class Root:
39 def index(self, *args, **kwargs):
40 return "Hello world!"
41 index.exposed = True
43 def no_body(self, *args, **kwargs):
44 return "Hello world!"
45 no_body.exposed = True
46 no_body._cp_config = {'request.process_request_body': False}
48 def post_multipart(self, file):
49 """Return a summary ("a * 65536\nb * 65536") of the uploaded file."""
50 contents = file.file.read()
51 summary = []
52 curchar = ""
53 count = 0
54 for c in contents:
55 if c == curchar:
56 count += 1
57 else:
58 if count:
59 summary.append("%s * %d" % (curchar, count))
60 count = 1
61 curchar = c
62 if count:
63 summary.append("%s * %d" % (curchar, count))
64 return ", ".join(summary)
65 post_multipart.exposed = True
67 cherrypy.tree.mount(Root())
68 cherrypy.config.update({'server.max_request_body_size': 30000000})
69 setup_server = staticmethod(setup_server)
71 def test_no_content_length(self):
72 # "The presence of a message-body in a request is signaled by the
73 # inclusion of a Content-Length or Transfer-Encoding header field in
74 # the request's message-headers."
76 # Send a message with neither header and no body. Even though
77 # the request is of method POST, this should be OK because we set
78 # request.process_request_body to False for our handler.
79 if self.scheme == "https":
80 c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
81 else:
82 c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
83 c.request("POST", "/no_body")
84 response = c.getresponse()
85 self.body = response.fp.read()
86 self.status = str(response.status)
87 self.assertStatus(200)
88 self.assertBody(ntob('Hello world!'))
90 # Now send a message that has no Content-Length, but does send a body.
91 # Verify that CP times out the socket and responds
92 # with 411 Length Required.
93 if self.scheme == "https":
94 c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
95 else:
96 c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
97 c.request("POST", "/")
98 response = c.getresponse()
99 self.body = response.fp.read()
100 self.status = str(response.status)
101 self.assertStatus(411)
103 def test_post_multipart(self):
104 alphabet = "abcdefghijklmnopqrstuvwxyz"
105 # generate file contents for a large post
106 contents = "".join([c * 65536 for c in alphabet])
108 # encode as multipart form data
109 files=[('file', 'file.txt', contents)]
110 content_type, body = encode_multipart_formdata(files)
111 body = body.encode('Latin-1')
113 # post file
114 if self.scheme == 'https':
115 c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
116 else:
117 c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
118 c.putrequest('POST', '/post_multipart')
119 c.putheader('Content-Type', content_type)
120 c.putheader('Content-Length', str(len(body)))
121 c.endheaders()
122 c.send(body)
124 response = c.getresponse()
125 self.body = response.fp.read()
126 self.status = str(response.status)
127 self.assertStatus(200)
128 self.assertBody(", ".join(["%s * 65536" % c for c in alphabet]))
130 def test_malformed_request_line(self):
131 if getattr(cherrypy.server, "using_apache", False):
132 return self.skip("skipped due to known Apache differences...")
134 # Test missing version in Request-Line
135 if self.scheme == 'https':
136 c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
137 else:
138 c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
139 c._output(ntob('GET /'))
140 c._send_output()
141 if hasattr(c, 'strict'):
142 response = c.response_class(c.sock, strict=c.strict, method='GET')
143 else:
144 # Python 3.2 removed the 'strict' feature, saying:
145 # "http.client now always assumes HTTP/1.x compliant servers."
146 response = c.response_class(c.sock, method='GET')
147 response.begin()
148 self.assertEqual(response.status, 400)
149 self.assertEqual(response.fp.read(22), ntob("Malformed Request-Line"))
150 c.close()
152 def test_malformed_header(self):
153 if self.scheme == 'https':
154 c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
155 else:
156 c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
157 c.putrequest('GET', '/')
158 c.putheader('Content-Type', 'text/plain')
159 # See http://www.cherrypy.org/ticket/941
160 c._output(ntob('Re, 1.2.3.4#015#012'))
161 c.endheaders()
163 response = c.getresponse()
164 self.status = str(response.status)
165 self.assertStatus(400)
166 self.body = response.fp.read(20)
167 self.assertBody("Illegal header line.")