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
ff5cd457
Commit
ff5cd457
authored
Jun 05, 2016
by
Martin Panter
Browse files
Options
Browse Files
Download
Plain Diff
Issue #24291: Merge wsgi partial write fix from 3.5
parents
1b749c5e
ed0425c6
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
111 additions
and
7 deletions
+111
-7
Doc/library/wsgiref.rst
Doc/library/wsgiref.rst
+3
-0
Lib/test/test_wsgiref.py
Lib/test/test_wsgiref.py
+80
-1
Lib/wsgiref/handlers.py
Lib/wsgiref/handlers.py
+11
-1
Lib/wsgiref/simple_server.py
Lib/wsgiref/simple_server.py
+12
-5
Misc/NEWS
Misc/NEWS
+5
-0
No files found.
Doc/library/wsgiref.rst
View file @
ff5cd457
...
@@ -515,6 +515,9 @@ input, output, and error streams.
...
@@ -515,6 +515,9 @@ input, output, and error streams.
streams are stored in the :attr:`stdin`, :attr:`stdout`, :attr:`stderr`, and
streams are stored in the :attr:`stdin`, :attr:`stdout`, :attr:`stderr`, and
:attr:`environ` attributes.
:attr:`environ` attributes.
The :meth:`~io.BufferedIOBase.write` method of *stdout* should write
each chunk in full, like :class:`io.BufferedIOBase`.
..
class:: BaseHandler()
..
class:: BaseHandler()
...
...
Lib/test/test_wsgiref.py
View file @
ff5cd457
from
unittest
import
mock
from
unittest
import
mock
from
test
import
support
from
test.test_httpservers
import
NoLogRequestHandler
from
unittest
import
TestCase
from
unittest
import
TestCase
from
wsgiref.util
import
setup_testing_defaults
from
wsgiref.util
import
setup_testing_defaults
from
wsgiref.headers
import
Headers
from
wsgiref.headers
import
Headers
from
wsgiref.handlers
import
BaseHandler
,
BaseCGIHandler
from
wsgiref.handlers
import
BaseHandler
,
BaseCGIHandler
,
SimpleHandler
from
wsgiref
import
util
from
wsgiref
import
util
from
wsgiref.validate
import
validator
from
wsgiref.validate
import
validator
from
wsgiref.simple_server
import
WSGIServer
,
WSGIRequestHandler
from
wsgiref.simple_server
import
WSGIServer
,
WSGIRequestHandler
from
wsgiref.simple_server
import
make_server
from
wsgiref.simple_server
import
make_server
from
http.client
import
HTTPConnection
from
io
import
StringIO
,
BytesIO
,
BufferedReader
from
io
import
StringIO
,
BytesIO
,
BufferedReader
from
socketserver
import
BaseServer
from
socketserver
import
BaseServer
from
platform
import
python_implementation
from
platform
import
python_implementation
import
os
import
os
import
re
import
re
import
signal
import
sys
import
sys
import
unittest
import
unittest
...
@@ -245,6 +249,56 @@ class IntegrationTests(TestCase):
...
@@ -245,6 +249,56 @@ class IntegrationTests(TestCase):
],
],
out
.
splitlines
())
out
.
splitlines
())
def
test_interrupted_write
(
self
):
# BaseHandler._write() and _flush() have to write all data, even if
# it takes multiple send() calls. Test this by interrupting a send()
# call with a Unix signal.
threading
=
support
.
import_module
(
"threading"
)
pthread_kill
=
support
.
get_attribute
(
signal
,
"pthread_kill"
)
def
app
(
environ
,
start_response
):
start_response
(
"200 OK"
,
[])
return
[
bytes
(
support
.
SOCK_MAX_SIZE
)]
class
WsgiHandler
(
NoLogRequestHandler
,
WSGIRequestHandler
):
pass
server
=
make_server
(
support
.
HOST
,
0
,
app
,
handler_class
=
WsgiHandler
)
self
.
addCleanup
(
server
.
server_close
)
interrupted
=
threading
.
Event
()
def
signal_handler
(
signum
,
frame
):
interrupted
.
set
()
original
=
signal
.
signal
(
signal
.
SIGUSR1
,
signal_handler
)
self
.
addCleanup
(
signal
.
signal
,
signal
.
SIGUSR1
,
original
)
received
=
None
main_thread
=
threading
.
get_ident
()
def
run_client
():
http
=
HTTPConnection
(
*
server
.
server_address
)
http
.
request
(
"GET"
,
"/"
)
with
http
.
getresponse
()
as
response
:
response
.
read
(
100
)
# The main thread should now be blocking in a send() system
# call. But in theory, it could get interrupted by other
# signals, and then retried. So keep sending the signal in a
# loop, in case an earlier signal happens to be delivered at
# an inconvenient moment.
while
True
:
pthread_kill
(
main_thread
,
signal
.
SIGUSR1
)
if
interrupted
.
wait
(
timeout
=
float
(
1
)):
break
nonlocal
received
received
=
len
(
response
.
read
())
http
.
close
()
background
=
threading
.
Thread
(
target
=
run_client
)
background
.
start
()
server
.
handle_request
()
background
.
join
()
self
.
assertEqual
(
received
,
support
.
SOCK_MAX_SIZE
-
100
)
class
UtilityTests
(
TestCase
):
class
UtilityTests
(
TestCase
):
...
@@ -701,6 +755,31 @@ class HandlerTests(TestCase):
...
@@ -701,6 +755,31 @@ class HandlerTests(TestCase):
h
.
run
(
error_app
)
h
.
run
(
error_app
)
self
.
assertEqual
(
side_effects
[
'close_called'
],
True
)
self
.
assertEqual
(
side_effects
[
'close_called'
],
True
)
def
testPartialWrite
(
self
):
written
=
bytearray
()
class
PartialWriter
:
def
write
(
self
,
b
):
partial
=
b
[:
7
]
written
.
extend
(
partial
)
return
len
(
partial
)
def
flush
(
self
):
pass
environ
=
{
"SERVER_PROTOCOL"
:
"HTTP/1.0"
}
h
=
SimpleHandler
(
BytesIO
(),
PartialWriter
(),
sys
.
stderr
,
environ
)
msg
=
"should not do partial writes"
with
self
.
assertWarnsRegex
(
DeprecationWarning
,
msg
):
h
.
run
(
hello_app
)
self
.
assertEqual
(
b"HTTP/1.0 200 OK
\
r
\
n
"
b"Content-Type: text/plain
\
r
\
n
"
b"Date: Mon, 05 Jun 2006 18:49:54 GMT
\
r
\
n
"
b"Content-Length: 13
\
r
\
n
"
b"
\
r
\
n
"
b"Hello, world!"
,
written
)
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
unittest
.
main
()
unittest
.
main
()
Lib/wsgiref/handlers.py
View file @
ff5cd457
...
@@ -450,7 +450,17 @@ class SimpleHandler(BaseHandler):
...
@@ -450,7 +450,17 @@ class SimpleHandler(BaseHandler):
self
.
environ
.
update
(
self
.
base_env
)
self
.
environ
.
update
(
self
.
base_env
)
def
_write
(
self
,
data
):
def
_write
(
self
,
data
):
self
.
stdout
.
write
(
data
)
result
=
self
.
stdout
.
write
(
data
)
if
result
is
None
or
result
==
len
(
data
):
return
from
warnings
import
warn
warn
(
"SimpleHandler.stdout.write() should not do partial writes"
,
DeprecationWarning
)
while
True
:
data
=
data
[
result
:]
if
not
data
:
break
result
=
self
.
stdout
.
write
(
data
)
def
_flush
(
self
):
def
_flush
(
self
):
self
.
stdout
.
flush
()
self
.
stdout
.
flush
()
...
...
Lib/wsgiref/simple_server.py
View file @
ff5cd457
...
@@ -11,6 +11,7 @@ module. See also the BaseHTTPServer module docs for other API information.
...
@@ -11,6 +11,7 @@ module. See also the BaseHTTPServer module docs for other API information.
"""
"""
from
http.server
import
BaseHTTPRequestHandler
,
HTTPServer
from
http.server
import
BaseHTTPRequestHandler
,
HTTPServer
from
io
import
BufferedWriter
import
sys
import
sys
import
urllib.parse
import
urllib.parse
from
wsgiref.handlers
import
SimpleHandler
from
wsgiref.handlers
import
SimpleHandler
...
@@ -126,11 +127,17 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
...
@@ -126,11 +127,17 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
if
not
self
.
parse_request
():
# An error code has been sent, just exit
if
not
self
.
parse_request
():
# An error code has been sent, just exit
return
return
handler
=
ServerHandler
(
# Avoid passing the raw file object wfile, which can do partial
self
.
rfile
,
self
.
wfile
,
self
.
get_stderr
(),
self
.
get_environ
()
# writes (Issue 24291)
)
stdout
=
BufferedWriter
(
self
.
wfile
)
handler
.
request_handler
=
self
# backpointer for logging
try
:
handler
.
run
(
self
.
server
.
get_app
())
handler
=
ServerHandler
(
self
.
rfile
,
stdout
,
self
.
get_stderr
(),
self
.
get_environ
()
)
handler
.
request_handler
=
self
# backpointer for logging
handler
.
run
(
self
.
server
.
get_app
())
finally
:
stdout
.
detach
()
...
...
Misc/NEWS
View file @
ff5cd457
...
@@ -27,6 +27,11 @@ Core and Builtins
...
@@ -27,6 +27,11 @@ Core and Builtins
Library
Library
-------
-------
- Issue #24291: Fix wsgiref.simple_server.WSGIRequestHandler to completely
write data to the client. Previously it could do partial writes and
truncate data. Also, wsgiref.handler.ServerHandler can now handle stdout
doing partial writes, but this is deprecated.
- Issue #21272: Use _sysconfigdata.py to initialize distutils.sysconfig.
- Issue #21272: Use _sysconfigdata.py to initialize distutils.sysconfig.
- Issue #19611: :mod:`inspect` now reports the implicit ``.0`` parameters
- Issue #19611: :mod:`inspect` now reports the implicit ``.0`` parameters
...
...
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