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
7bc0d872
Commit
7bc0d872
authored
Dec 19, 2010
by
Senthil Kumaran
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue3243 - Support iterable bodies in httplib. Patch contributions by Xuanji Li and Chris AtLee.
parent
8a60e948
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
112 additions
and
17 deletions
+112
-17
Doc/library/http.client.rst
Doc/library/http.client.rst
+8
-4
Doc/library/urllib.request.rst
Doc/library/urllib.request.rst
+10
-6
Lib/http/client.py
Lib/http/client.py
+15
-2
Lib/test/test_httplib.py
Lib/test/test_httplib.py
+16
-0
Lib/test/test_urllib2.py
Lib/test/test_urllib2.py
+48
-3
Lib/urllib/request.py
Lib/urllib/request.py
+12
-2
Misc/NEWS
Misc/NEWS
+3
-0
No files found.
Doc/library/http.client.rst
View file @
7bc0d872
...
@@ -393,14 +393,18 @@ HTTPConnection Objects
...
@@ -393,14 +393,18 @@ HTTPConnection Objects
string.
string.
The *body* may also be an open :term:`file object`, in which case the
The *body* may also be an open :term:`file object`, in which case the
contents of the file is sent; this file object should support
contents of the file is sent; this file object should support ``fileno()``
``fileno()`` and ``read()`` methods. The header Content-Length is
and ``read()`` methods. The header Content-Length is automatically set to
automatically set to the length of the file as reported by
the length of the file as reported by stat. The *body* argument may also be
stat.
an iterable and Contet-Length header should be explicitly provided when the
body is an iterable.
The *headers* argument should be a mapping of extra HTTP
The *headers* argument should be a mapping of extra HTTP
headers to send with the request.
headers to send with the request.
.. versionadded:: 3.2
*body* can be an iterable
.. method:: HTTPConnection.getresponse()
.. method:: HTTPConnection.getresponse()
Should be called after a request is sent to get the response from the server.
Should be called after a request is sent to get the response from the server.
...
...
Doc/library/urllib.request.rst
View file @
7bc0d872
...
@@ -21,13 +21,14 @@ The :mod:`urllib.request` module defines the following functions:
...
@@ -21,13 +21,14 @@ The :mod:`urllib.request` module defines the following functions:
:class:`Request` object.
:class:`Request` object.
*data* may be a string specifying additional data to send to the
*data* may be a string specifying additional data to send to the
server, or ``None`` if no such data is needed. Currently HTTP
server, or ``None`` if no such data is needed. *data* may also be an
requests are the only ones that use *data*; the HTTP request will
iterable object and in that case Content-Length value must be specified in
be a POST instead of a GET when the *data* parameter is provided.
the headers. Currently HTTP requests are the only ones that use *data*; the
*data* should be a buffer in the standard
HTTP request will be a POST instead of a GET when the *data* parameter is
provided. *data* should be a buffer in the standard
:mimetype:`application/x-www-form-urlencoded` format. The
:mimetype:`application/x-www-form-urlencoded` format. The
:func:`urllib.parse.urlencode` function takes a mapping or sequence
:func:`urllib.parse.urlencode` function takes a mapping or sequence
of
of
2-tuples and returns a string in this format. urllib.request module uses
2-tuples and returns a string in this format. urllib.request module uses
HTTP/1.1 and includes ``Connection:close`` header in its HTTP requests.
HTTP/1.1 and includes ``Connection:close`` header in its HTTP requests.
The optional *timeout* parameter specifies a timeout in seconds for
The optional *timeout* parameter specifies a timeout in seconds for
...
@@ -76,6 +77,9 @@ The :mod:`urllib.request` module defines the following functions:
...
@@ -76,6 +77,9 @@ The :mod:`urllib.request` module defines the following functions:
HTTPS virtual hosts are now supported if possible (that is, if
HTTPS virtual hosts are now supported if possible (that is, if
:data:`ssl.HAS_SNI` is true).
:data:`ssl.HAS_SNI` is true).
.. versionadded:: 3.2
*data* can be an iterable object.
.. function:: install_opener(opener)
.. function:: install_opener(opener)
Install an :class:`OpenerDirector` instance as the default global opener.
Install an :class:`OpenerDirector` instance as the default global opener.
...
...
Lib/http/client.py
View file @
7bc0d872
...
@@ -71,6 +71,7 @@ import email.message
...
@@ -71,6 +71,7 @@ import email.message
import
io
import
io
import
os
import
os
import
socket
import
socket
import
collections
from
urllib.parse
import
urlsplit
from
urllib.parse
import
urlsplit
import
warnings
import
warnings
...
@@ -730,7 +731,11 @@ class HTTPConnection:
...
@@ -730,7 +731,11 @@ class HTTPConnection:
self
.
__state
=
_CS_IDLE
self
.
__state
=
_CS_IDLE
def
send
(
self
,
data
):
def
send
(
self
,
data
):
"""Send `data' to the server."""
"""Send `data' to the server.
``data`` can be a string object, a bytes object, an array object, a
file-like object that supports a .read() method, or an iterable object.
"""
if
self
.
sock
is
None
:
if
self
.
sock
is
None
:
if
self
.
auto_open
:
if
self
.
auto_open
:
self
.
connect
()
self
.
connect
()
...
@@ -762,8 +767,16 @@ class HTTPConnection:
...
@@ -762,8 +767,16 @@ class HTTPConnection:
if
encode
:
if
encode
:
datablock
=
datablock
.
encode
(
"iso-8859-1"
)
datablock
=
datablock
.
encode
(
"iso-8859-1"
)
self
.
sock
.
sendall
(
datablock
)
self
.
sock
.
sendall
(
datablock
)
else
:
try
:
self
.
sock
.
sendall
(
data
)
self
.
sock
.
sendall
(
data
)
except
TypeError
:
if
isinstance
(
data
,
collections
.
Iterable
):
for
d
in
data
:
self
.
sock
.
sendall
(
d
)
else
:
raise
TypeError
(
"data should be byte-like object
\
or an iterable, got %r "
%
type
(
it
))
def
_output
(
self
,
s
):
def
_output
(
self
,
s
):
"""Add a line of output to the current request buffer.
"""Add a line of output to the current request buffer.
...
...
Lib/test/test_httplib.py
View file @
7bc0d872
...
@@ -230,6 +230,22 @@ class BasicTest(TestCase):
...
@@ -230,6 +230,22 @@ class BasicTest(TestCase):
conn
.
send
(
io
.
BytesIO
(
expected
))
conn
.
send
(
io
.
BytesIO
(
expected
))
self
.
assertEqual
(
expected
,
sock
.
data
)
self
.
assertEqual
(
expected
,
sock
.
data
)
def
test_send_iter
(
self
):
expected
=
b'GET /foo HTTP/1.1
\
r
\
n
Host: example.com
\
r
\
n
'
\
b'Accept-Encoding: identity
\
r
\
n
Content-Length: 11
\
r
\
n
'
\
b'
\
r
\
n
onetwothree'
def
body
():
yield
b"one"
yield
b"two"
yield
b"three"
conn
=
client
.
HTTPConnection
(
'example.com'
)
sock
=
FakeSocket
(
""
)
conn
.
sock
=
sock
conn
.
request
(
'GET'
,
'/foo'
,
body
(),
{
'Content-Length'
:
'11'
})
self
.
assertEquals
(
sock
.
data
,
expected
)
def
test_chunked
(
self
):
def
test_chunked
(
self
):
chunked_start
=
(
chunked_start
=
(
'HTTP/1.1 200 OK
\
r
\
n
'
'HTTP/1.1 200 OK
\
r
\
n
'
...
...
Lib/test/test_urllib2.py
View file @
7bc0d872
...
@@ -4,6 +4,7 @@ from test import support
...
@@ -4,6 +4,7 @@ from test import support
import
os
import
os
import
io
import
io
import
socket
import
socket
import
array
import
urllib.request
import
urllib.request
from
urllib.request
import
Request
,
OpenerDirector
from
urllib.request
import
Request
,
OpenerDirector
...
@@ -765,7 +766,7 @@ class HandlerTests(unittest.TestCase):
...
@@ -765,7 +766,7 @@ class HandlerTests(unittest.TestCase):
o
=
h
.
parent
=
MockOpener
()
o
=
h
.
parent
=
MockOpener
()
url
=
"http://example.com/"
url
=
"http://example.com/"
for
method
,
data
in
[(
"GET"
,
None
),
(
"POST"
,
"blah"
)]:
for
method
,
data
in
[(
"GET"
,
None
),
(
"POST"
,
b
"blah"
)]:
req
=
Request
(
url
,
data
,
{
"Foo"
:
"bar"
})
req
=
Request
(
url
,
data
,
{
"Foo"
:
"bar"
})
req
.
timeout
=
None
req
.
timeout
=
None
req
.
add_unredirected_header
(
"Spam"
,
"eggs"
)
req
.
add_unredirected_header
(
"Spam"
,
"eggs"
)
...
@@ -795,7 +796,7 @@ class HandlerTests(unittest.TestCase):
...
@@ -795,7 +796,7 @@ class HandlerTests(unittest.TestCase):
# check adding of standard headers
# check adding of standard headers
o
.
addheaders
=
[(
"Spam"
,
"eggs"
)]
o
.
addheaders
=
[(
"Spam"
,
"eggs"
)]
for
data
in
""
,
None
:
# POST, GET
for
data
in
b
""
,
None
:
# POST, GET
req
=
Request
(
"http://example.com/"
,
data
)
req
=
Request
(
"http://example.com/"
,
data
)
r
=
MockResponse
(
200
,
"OK"
,
{},
""
)
r
=
MockResponse
(
200
,
"OK"
,
{},
""
)
newreq
=
h
.
do_request_
(
req
)
newreq
=
h
.
do_request_
(
req
)
...
@@ -821,6 +822,50 @@ class HandlerTests(unittest.TestCase):
...
@@ -821,6 +822,50 @@ class HandlerTests(unittest.TestCase):
self
.
assertEqual
(
req
.
unredirected_hdrs
[
"Host"
],
"baz"
)
self
.
assertEqual
(
req
.
unredirected_hdrs
[
"Host"
],
"baz"
)
self
.
assertEqual
(
req
.
unredirected_hdrs
[
"Spam"
],
"foo"
)
self
.
assertEqual
(
req
.
unredirected_hdrs
[
"Spam"
],
"foo"
)
# Check iterable body support
def
iterable_body
():
yield
b"one"
yield
b"two"
yield
b"three"
for
headers
in
{},
{
"Content-Length"
:
11
}:
req
=
Request
(
"http://example.com/"
,
iterable_body
(),
headers
)
if
not
headers
:
# Having an iterable body without a Content-Length should
# raise an exception
self
.
assertRaises
(
ValueError
,
h
.
do_request_
,
req
)
else
:
newreq
=
h
.
do_request_
(
req
)
# A file object
"""
file_obj = io.StringIO()
file_obj.write("Something
\
n
Something
\
n
Something
\
n
")
for headers in {}, {"Content-Length": 30}:
req = Request("http://example.com/", file_obj, headers)
if not headers:
# Having an iterable body without a Content-Length should
# raise an exception
self.assertRaises(ValueError, h.do_request_, req)
else:
newreq = h.do_request_(req)
self.assertEqual(int(newreq.get_header('Content-length')),30)
file_obj.close()
# array.array Iterable - Content Length is calculated
iterable_array = array.array("I",[1,2,3,4])
for headers in {}, {"Content-Length": 16}:
req = Request("http://example.com/", iterable_array, headers)
newreq = h.do_request_(req)
self.assertEqual(int(newreq.get_header('Content-length')),16)
"""
def
test_http_doubleslash
(
self
):
def
test_http_doubleslash
(
self
):
# Checks the presence of any unnecessary double slash in url does not
# Checks the presence of any unnecessary double slash in url does not
# break anything. Previously, a double slash directly after the host
# break anything. Previously, a double slash directly after the host
...
@@ -828,7 +873,7 @@ class HandlerTests(unittest.TestCase):
...
@@ -828,7 +873,7 @@ class HandlerTests(unittest.TestCase):
h
=
urllib
.
request
.
AbstractHTTPHandler
()
h
=
urllib
.
request
.
AbstractHTTPHandler
()
o
=
h
.
parent
=
MockOpener
()
o
=
h
.
parent
=
MockOpener
()
data
=
""
data
=
b
""
ds_urls
=
[
ds_urls
=
[
"http://example.com/foo/bar/baz.html"
,
"http://example.com/foo/bar/baz.html"
,
"http://example.com//foo/bar/baz.html"
,
"http://example.com//foo/bar/baz.html"
,
...
...
Lib/urllib/request.py
View file @
7bc0d872
...
@@ -94,6 +94,7 @@ import re
...
@@ -94,6 +94,7 @@ import re
import
socket
import
socket
import
sys
import
sys
import
time
import
time
import
collections
from
urllib.error
import
URLError
,
HTTPError
,
ContentTooShortError
from
urllib.error
import
URLError
,
HTTPError
,
ContentTooShortError
from
urllib.parse
import
(
from
urllib.parse
import
(
...
@@ -1053,8 +1054,17 @@ class AbstractHTTPHandler(BaseHandler):
...
@@ -1053,8 +1054,17 @@ class AbstractHTTPHandler(BaseHandler):
'Content-type'
,
'Content-type'
,
'application/x-www-form-urlencoded'
)
'application/x-www-form-urlencoded'
)
if
not
request
.
has_header
(
'Content-length'
):
if
not
request
.
has_header
(
'Content-length'
):
try
:
mv
=
memoryview
(
data
)
except
TypeError
:
print
(
data
)
if
isinstance
(
data
,
collections
.
Iterable
):
raise
ValueError
(
"Content-Length should be specified
\
for iterable data of type %r %r"
%
(
type
(
data
),
data
))
else
:
request
.
add_unredirected_header
(
request
.
add_unredirected_header
(
'Content-length'
,
'%d'
%
len
(
data
)
)
'Content-length'
,
'%d'
%
len
(
mv
)
*
mv
.
itemsize
)
sel_host
=
host
sel_host
=
host
if
request
.
has_proxy
():
if
request
.
has_proxy
():
...
...
Misc/NEWS
View file @
7bc0d872
...
@@ -23,6 +23,9 @@ Core and Builtins
...
@@ -23,6 +23,9 @@ Core and Builtins
Library
Library
-------
-------
- Issue #3243: Support iterable bodies in httplib. Patch Contributions by
Xuanji Li and Chris AtLee.
- Issue #10611: SystemExit exception will no longer kill a unittest run.
- Issue #10611: SystemExit exception will no longer kill a unittest run.
- Issue #9857: It is now possible to skip a test in a setUp, tearDown or clean
- Issue #9857: It is now possible to skip a test in a setUp, tearDown or clean
...
...
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