Index: Lib/BaseHTTPServer.py =================================================================== --- Lib/BaseHTTPServer.py (revision 62996) +++ Lib/BaseHTTPServer.py (working copy) @@ -288,8 +288,33 @@ elif (conntype.lower() == 'keep-alive' and self.protocol_version >= "HTTP/1.1"): self.close_connection = 0 + + # Examine the headers and look for an Expect directive + expect = self.headers.get('Expect', "") + if (expect.lower() == "100-continue" and + self.protocol_version >= "HTTP/1.1" and + self.request_version >= "HTTP/1.1"): + if not self.handle_expect_100(): + return False return True + def handle_expect_100(self): + """Decide what to do with an "Expect: 100-continue" header. + + If the client is expecting a 100 Continue response, we must + respond with either a 100 Continue or a final response before + waiting for the request body. The default is to always respond + with a 100 Continue. You can behave differently (for example, + reject unauthorized requests) by overriding this method. + + This method should either return True (possibly after sending + a 100 Continue response) or send an error response and return + False. + + """ + self.send_response_only(100) + return True + def handle_one_request(self): """Handle a single HTTP request. @@ -361,6 +386,12 @@ """ self.log_request(code) + self.send_response_only(code, message) + self.send_header('Server', self.version_string()) + self.send_header('Date', self.date_time_string()) + + def send_response_only(self, code, message=None): + """Send the response header only.""" if message is None: if code in self.responses: message = self.responses[code][0] @@ -370,8 +401,6 @@ self.wfile.write("%s %d %s\r\n" % (self.protocol_version, code, message)) # print (self.protocol_version, code, message) - self.send_header('Server', self.version_string()) - self.send_header('Date', self.date_time_string()) def send_header(self, keyword, value): """Send a MIME header.""" Index: Lib/test/test_BaseHTTPServer.py =================================================================== --- Lib/test/test_BaseHTTPServer.py (revision 0) +++ Lib/test/test_BaseHTTPServer.py (revision 0) @@ -0,0 +1,133 @@ +""" +This should test more functionality +""" + +import unittest +from BaseHTTPServer import BaseHTTPRequestHandler +from test import test_support +from StringIO import StringIO + + +class SocketlessRequestHandler(BaseHTTPRequestHandler): + def __init__(self): + self.get_called = False + self.protocol_version = "HTTP/1.1" + + def do_GET(self): + self.get_called = True + self.send_response(200) + self.send_header('Content-Type', 'text/html') + self.end_headers() + self.wfile.write('Data\r\n') + + def log_message(self, format, *args): + pass + +class RejectingSocketlessRequestHandler(SocketlessRequestHandler): + def handle_expect_100(self): + self.send_error(417) + return False + +class BaseHTTPRequestHandlerTestCase(unittest.TestCase): + """Test the functionaility of the BaseHTTPServer. + + Currently, only the support for the Expect 100-continue header + is tested. + """ + def setUp (self): + self.handler = SocketlessRequestHandler() + + def test_http_1_1(self): + input = StringIO('GET / HTTP/1.1\r\n\r\n') + output = StringIO() + self.handler.rfile = input + self.handler.wfile = output + self.handler.handle_one_request() + self.assertTrue(self.handler.get_called) + output.seek(0) + result = output.readlines() + self.assertEqual(result[0], 'HTTP/1.1 200 OK\r\n') + self.assertTrue(result[1].startswith('Server: ')) + self.assertTrue(result[2].startswith('Date: ')) + self.assertTrue(result[3].startswith('Content-Type: ')) + self.assertEqual(result[-1], 'Data\r\n') + + def test_http_1_0(self): + input = StringIO('GET / HTTP/1.0\r\n\r\n') + output = StringIO() + self.handler.rfile = input + self.handler.wfile = output + self.handler.handle_one_request() + self.assertTrue(self.handler.get_called) + output.seek(0) + result = output.readlines() + self.assertEqual(result[0], 'HTTP/1.1 200 OK\r\n') + self.assertTrue(result[1].startswith('Server: ')) + self.assertTrue(result[2].startswith('Date: ')) + self.assertTrue(result[3].startswith('Content-Type: ')) + self.assertEqual(result[-1], 'Data\r\n') + + def test_http_0_9(self): + input = StringIO('GET / HTTP/0.9\r\n\r\n') + output = StringIO() + self.handler.rfile = input + self.handler.wfile = output + self.handler.handle_one_request() + self.assertTrue(self.handler.get_called) + output.seek(0) + result = output.readlines() + self.assertEqual(len(result), 1) + self.assertEqual(result[0], 'Data\r\n') + + def test_with_continue_1_0(self): + input = StringIO('GET / HTTP/1.0\r\nExpect: 100-continue\r\n\r\n') + output = StringIO() + self.handler.rfile = input + self.handler.wfile = output + self.handler.handle_one_request() + self.assertTrue(self.handler.get_called) + output.seek(0) + result = output.readlines() + self.assertEqual(result[0], 'HTTP/1.1 200 OK\r\n') + self.assertTrue(result[1].startswith('Server: ')) + self.assertTrue(result[2].startswith('Date: ')) + self.assertTrue(result[3].startswith('Content-Type: ')) + self.assertEqual(result[-1], 'Data\r\n') + + def test_with_continue_1_1(self): + input = StringIO('GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n') + output = StringIO() + self.handler.rfile = input + self.handler.wfile = output + self.handler.handle_one_request() + self.assertTrue(self.handler.get_called) + output.seek(0) + result = output.readlines() + self.assertEqual(result[0], 'HTTP/1.1 100 Continue\r\n') + self.assertEqual(result[1], 'HTTP/1.1 200 OK\r\n') + self.assertTrue(result[2].startswith('Server: ')) + self.assertTrue(result[3].startswith('Date: ')) + self.assertTrue(result[4].startswith('Content-Type: ')) + self.assertEqual(result[-1], 'Data\r\n') + + def test_with_continue_rejected(self): + self.handler = RejectingSocketlessRequestHandler() + input = StringIO('GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n') + output = StringIO() + self.handler.rfile = input + self.handler.wfile = output + self.handler.handle_one_request() + self.assertFalse(self.handler.get_called) + output.seek(0) + result = output.readlines() + self.assertEqual(result[0], 'HTTP/1.1 417 Expectation Failed\r\n') + self.assertTrue(result[1].startswith('Server: ')) + self.assertTrue(result[2].startswith('Date: ')) + self.assertTrue(result[3].startswith('Content-Type: ')) + self.assertEqual(result[4], 'Connection: close\r\n') + +def test_main(): + test_support.run_unittest(BaseHTTPRequestHandlerTestCase) + +if __name__ == "__main__": + test_main()