Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
0f476d49
Commit
0f476d49
authored
Sep 30, 2010
by
Senthil Kumaran
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue1491 - BaseHTTPServer incorrectly implements response code 100
parent
748cacee
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
151 additions
and
3 deletions
+151
-3
Doc/library/http.server.rst
Doc/library/http.server.rst
+20
-0
Lib/http/server.py
Lib/http/server.py
+30
-3
Lib/test/test_httpservers.py
Lib/test/test_httpservers.py
+98
-0
Misc/NEWS
Misc/NEWS
+3
-0
No files found.
Doc/library/http.server.rst
View file @
0f476d49
...
...
@@ -155,6 +155,17 @@ of which this module provides three different variants:
This method will parse and dispatch the request to the appropriate
:meth:`do_\*` method. You should never need to override it.
.. method:: handle_expect_100()
When a HTTP/1.1 compliant server receives a ``Expect: 100-continue``
request header it responds back with a ``100 Continue`` followed by ``200
OK`` headers.
This method can be overridden to raise an error if the server does not
want the client to continue. For e.g. server can chose to send ``417
Expectation Failed`` as a response header and ``return False``.
.. versionadded:: 3.2
.. method:: send_error(code, message=None)
Sends and logs a complete error reply to the client. The numeric *code*
...
...
@@ -174,6 +185,15 @@ of which this module provides three different variants:
Writes a specific HTTP header to the output stream. *keyword* should
specify the header keyword, with *value* specifying its value.
.. method:: send_response_only(code, message=None)
Sends the reponse header only, used for the purposes when ``100
Continue`` response is sent by the server to the client. If the *message*
is not specified, the HTTP message corresponding the response *code* is
sent.
.. versionadded:: 3.2
.. method:: end_headers()
Sends a blank line, indicating the end of the HTTP headers in the
...
...
Lib/http/server.py
View file @
0f476d49
...
...
@@ -322,6 +322,30 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
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
):
...
...
@@ -400,6 +424,12 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
"""
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
]
...
...
@@ -408,9 +438,6 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
if
self
.
request_version
!=
'HTTP/0.9'
:
self
.
wfile
.
write
((
"%s %d %s
\
r
\
n
"
%
(
self
.
protocol_version
,
code
,
message
)).
encode
(
'ASCII'
,
'strict'
))
# 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."""
...
...
Lib/test/test_httpservers.py
View file @
0f476d49
...
...
@@ -10,11 +10,13 @@ from http import server
import
os
import
sys
import
re
import
base64
import
shutil
import
urllib.parse
import
http.client
import
tempfile
from
io
import
BytesIO
import
unittest
from
test
import
support
...
...
@@ -403,8 +405,103 @@ class CGIHTTPServerTestCase(BaseTestCase):
class
SocketlessRequestHandler
(
SimpleHTTPRequestHandler
):
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
(
b'<html><body>Data</body></html>
\
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.
Test the support for the Expect 100-continue header.
"""
HTTPResponseMatch
=
re
.
compile
(
b'HTTP/1.[0-9]+ 200 OK'
)
def
setUp
(
self
):
self
.
handler
=
SocketlessRequestHandler
()
def
send_typical_request
(
self
,
message
):
input
=
BytesIO
(
message
)
output
=
BytesIO
()
self
.
handler
.
rfile
=
input
self
.
handler
.
wfile
=
output
self
.
handler
.
handle_one_request
()
output
.
seek
(
0
)
return
output
.
readlines
()
def
verify_get_called
(
self
):
self
.
assertTrue
(
self
.
handler
.
get_called
)
def
verify_expected_headers
(
self
,
headers
):
for
fieldName
in
b'Server: '
,
b'Date: '
,
b'Content-Type: '
:
self
.
assertEqual
(
sum
(
h
.
startswith
(
fieldName
)
for
h
in
headers
),
1
)
def
verify_http_server_response
(
self
,
response
):
match
=
self
.
HTTPResponseMatch
.
search
(
response
)
self
.
assertTrue
(
match
is
not
None
)
def
test_http_1_1
(
self
):
result
=
self
.
send_typical_request
(
b'GET / HTTP/1.1
\
r
\
n
\
r
\
n
'
)
self
.
verify_http_server_response
(
result
[
0
])
self
.
verify_expected_headers
(
result
[
1
:
-
1
])
self
.
verify_get_called
()
self
.
assertEqual
(
result
[
-
1
],
b'<html><body>Data</body></html>
\
r
\
n
'
)
def
test_http_1_0
(
self
):
result
=
self
.
send_typical_request
(
b'GET / HTTP/1.0
\
r
\
n
\
r
\
n
'
)
self
.
verify_http_server_response
(
result
[
0
])
self
.
verify_expected_headers
(
result
[
1
:
-
1
])
self
.
verify_get_called
()
self
.
assertEqual
(
result
[
-
1
],
b'<html><body>Data</body></html>
\
r
\
n
'
)
def
test_http_0_9
(
self
):
result
=
self
.
send_typical_request
(
b'GET / HTTP/0.9
\
r
\
n
\
r
\
n
'
)
self
.
assertEqual
(
len
(
result
),
1
)
self
.
assertEqual
(
result
[
0
],
b'<html><body>Data</body></html>
\
r
\
n
'
)
self
.
verify_get_called
()
def
test_with_continue_1_0
(
self
):
result
=
self
.
send_typical_request
(
b'GET / HTTP/1.0
\
r
\
n
Expect: 100-continue
\
r
\
n
\
r
\
n
'
)
self
.
verify_http_server_response
(
result
[
0
])
self
.
verify_expected_headers
(
result
[
1
:
-
1
])
self
.
verify_get_called
()
self
.
assertEqual
(
result
[
-
1
],
b'<html><body>Data</body></html>
\
r
\
n
'
)
def
test_with_continue_1_1
(
self
):
result
=
self
.
send_typical_request
(
b'GET / HTTP/1.1
\
r
\
n
Expect: 100-continue
\
r
\
n
\
r
\
n
'
)
self
.
assertEqual
(
result
[
0
],
b'HTTP/1.1 100 Continue
\
r
\
n
'
)
self
.
assertEqual
(
result
[
1
],
b'HTTP/1.1 200 OK
\
r
\
n
'
)
self
.
verify_expected_headers
(
result
[
2
:
-
1
])
self
.
verify_get_called
()
self
.
assertEqual
(
result
[
-
1
],
b'<html><body>Data</body></html>
\
r
\
n
'
)
def
test_with_continue_rejected
(
self
):
usual_handler
=
self
.
handler
# Save to avoid breaking any subsequent tests.
self
.
handler
=
RejectingSocketlessRequestHandler
()
result
=
self
.
send_typical_request
(
b'GET / HTTP/1.1
\
r
\
n
Expect: 100-continue
\
r
\
n
\
r
\
n
'
)
self
.
assertEqual
(
result
[
0
],
b'HTTP/1.1 417 Expectation Failed
\
r
\
n
'
)
self
.
verify_expected_headers
(
result
[
1
:
-
1
])
# The expect handler should short circuit the usual get method by
# returning false here, so get_called should be false
self
.
assertFalse
(
self
.
handler
.
get_called
)
self
.
assertEqual
(
sum
(
r
==
b'Connection: close
\
r
\
n
'
for
r
in
result
[
1
:
-
1
]),
1
)
self
.
handler
=
usual_handler
# Restore to avoid breaking any subsequent tests.
class
SimpleHTTPRequestHandlerTestCase
(
unittest
.
TestCase
):
""" Test url parsing """
def
setUp
(
self
):
...
...
@@ -431,6 +528,7 @@ def test_main(verbose=None):
cwd
=
os
.
getcwd
()
try
:
support
.
run_unittest
(
BaseHTTPRequestHandlerTestCase
,
BaseHTTPServerTestCase
,
SimpleHTTPServerTestCase
,
CGIHTTPServerTestCase
,
...
...
Misc/NEWS
View file @
0f476d49
...
...
@@ -76,6 +76,9 @@ Core and Builtins
Library
-------
- Issue #1491: BaseHTTPServer nows send a 100 Continue response before sending
a 200 OK for the Expect: 100-continue request header.
- Issue #9360: Cleanup and improvements to the nntplib module. The API
now conforms to the philosophy of bytes and unicode separation in Python 3.
A test suite has also been added.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment