]> granicus.if.org Git - python/commitdiff
Fix closes issue 1673007 urllib.request to support HEAD requests with a new method...
authorSenthil Kumaran <senthil@uthcode.com>
Sun, 16 Oct 2011 15:54:44 +0000 (23:54 +0800)
committerSenthil Kumaran <senthil@uthcode.com>
Sun, 16 Oct 2011 15:54:44 +0000 (23:54 +0800)
Doc/library/urllib.request.rst
Doc/whatsnew/3.3.rst
Lib/test/test_urllib.py
Lib/urllib/request.py
Misc/NEWS

index c08cbc68fe31a7bac62899ffdea058d1e6f3b150..ecb357e2edf4f6c7c722147f966e6c04a82a3ff1 100644 (file)
@@ -132,7 +132,7 @@ The :mod:`urllib.request` module defines the following functions:
 
 The following classes are provided:
 
-.. class:: Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False)
+.. class:: Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
 
    This class is an abstraction of a URL request.
 
@@ -140,8 +140,8 @@ The following classes are provided:
 
    *data* may be a string specifying additional data to send to the
    server, or ``None`` if no such data is needed.  Currently HTTP
-   requests are the only ones that use *data*; the HTTP request will
-   be a POST instead of a GET when the *data* parameter is provided.
+   requests are the only ones that use *data*, in order to choose between
+   ``'GET'`` and ``'POST'`` when *method* is not specified.
    *data* should be a buffer in the standard
    :mimetype:`application/x-www-form-urlencoded` format.  The
    :func:`urllib.parse.urlencode` function takes a mapping or sequence
@@ -157,8 +157,8 @@ The following classes are provided:
    :mod:`urllib`'s default user agent string is
    ``"Python-urllib/2.6"`` (on Python 2.6).
 
-   The final two arguments are only of interest for correct handling
-   of third-party HTTP cookies:
+   The following two arguments, *origin_req_host* and *unverifiable*,
+   are only of interest for correct handling of third-party HTTP cookies:
 
    *origin_req_host* should be the request-host of the origin
    transaction, as defined by :rfc:`2965`.  It defaults to
@@ -175,6 +175,13 @@ The following classes are provided:
    document, and the user had no option to approve the automatic
    fetching of the image, this should be true.
 
+   *method* should be a string that indicates the HTTP request method that
+   will be used (e.g. ``'HEAD'``).  Its value is stored in the
+   :attr:`Request.method` attribute and is used by :meth:`Request.get_method()`.
+
+   .. versionchanged:: 3.3
+    :attr:`Request.method` argument is added to the Request class.
+
 
 .. class:: OpenerDirector()
 
@@ -369,6 +376,15 @@ request.
    boolean, indicates whether the request is unverifiable as defined
    by RFC 2965.
 
+.. attribute:: Request.method
+
+   The HTTP request method to use.  This value is used by
+   :meth:`Request.get_method` to override the computed HTTP request
+   method that would otherwise be returned.  This attribute is
+   initialized with the value of the *method* argument passed to the constructor.
+
+   ..versionadded:: 3.3
+
 .. method:: Request.add_data(data)
 
    Set the :class:`Request` data to *data*.  This is ignored by all handlers except
@@ -378,8 +394,13 @@ request.
 
 .. method:: Request.get_method()
 
-   Return a string indicating the HTTP request method.  This is only meaningful for
-   HTTP requests, and currently always returns ``'GET'`` or ``'POST'``.
+   Return a string indicating the HTTP request method.  If
+   :attr:`Request.method` is not ``None``, return its value, otherwise return
+   ``'GET'`` if :attr:`Request.data` is ``None``, or ``'POST'`` if it's not.
+   This is only meaningful for HTTP requests.
+
+    .. versionchanged:: 3.3
+    get_method now looks at the value of :attr:`Request.method` first.
 
 
 .. method:: Request.has_data()
index 6c57d72d5d6032d86c8c83be2e446536df58cbce..945aa97757f16b2ada940ae3a2a289796150cc09 100644 (file)
@@ -474,6 +474,16 @@ shutil
     path also specifying the user/group names and not only their numeric
     ids. (Contributed by Sandro Tosi in :issue:`12191`)
 
+urllib
+------
+
+The :class:`~urllib.request.Request` class, now accepts a *method* argument
+used by :meth:`~urllib.request.Request.get_method` to determine what HTTP method
+should be used.  For example, this will send an ``'HEAD'`` request::
+
+   >>> urlopen(Request('http://www.python.org', method='HEAD'))
+
+(:issue:`1673007`)
 
 Optimizations
 =============
index 77637a627d3a8380f042ec5e6bc5529958d5f02d..4e34ae52c333a9ea5d65a884c39c38cf930146d0 100644 (file)
@@ -1157,6 +1157,28 @@ class URLopener_Tests(unittest.TestCase):
 #         self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
 #         ftp.close()
 
+class RequestTests(unittest.TestCase):
+    """Unit tests for urllib.request.Request."""
+
+    def test_default_values(self):
+        Request = urllib.request.Request
+        request = Request("http://www.python.org")
+        self.assertEqual(request.get_method(), 'GET')
+        request = Request("http://www.python.org", {})
+        self.assertEqual(request.get_method(), 'POST')
+
+    def test_with_method_arg(self):
+        Request = urllib.request.Request
+        request = Request("http://www.python.org", method='HEAD')
+        self.assertEqual(request.method, 'HEAD')
+        self.assertEqual(request.get_method(), 'HEAD')
+        request = Request("http://www.python.org", {}, method='HEAD')
+        self.assertEqual(request.method, 'HEAD')
+        self.assertEqual(request.get_method(), 'HEAD')
+        request = Request("http://www.python.org", method='GET')
+        self.assertEqual(request.get_method(), 'GET')
+        request.method = 'HEAD'
+        self.assertEqual(request.get_method(), 'HEAD')
 
 
 def test_main():
@@ -1172,6 +1194,7 @@ def test_main():
         Utility_Tests,
         URLopener_Tests,
         #FTPWrapperTests,
+        RequestTests,
     )
 
 
index a947608b1177938b1cc1da98e403f5465900062e..65ce287588ffb13b45eae848c607ae39925adbbe 100644 (file)
@@ -177,7 +177,8 @@ def request_host(request):
 class Request:
 
     def __init__(self, url, data=None, headers={},
-                 origin_req_host=None, unverifiable=False):
+                 origin_req_host=None, unverifiable=False,
+                 method=None):
         # unwrap('<URL:type://host/path>') --> 'type://host/path'
         self.full_url = unwrap(url)
         self.full_url, self.fragment = splittag(self.full_url)
@@ -191,6 +192,7 @@ class Request:
             origin_req_host = request_host(self)
         self.origin_req_host = origin_req_host
         self.unverifiable = unverifiable
+        self.method = method
         self._parse()
 
     def _parse(self):
@@ -202,7 +204,10 @@ class Request:
             self.host = unquote(self.host)
 
     def get_method(self):
-        if self.data is not None:
+        """Return a string indicating the HTTP request method."""
+        if self.method is not None:
+            return self.method
+        elif self.data is not None:
             return "POST"
         else:
             return "GET"
index f02e8786cb2c2337a4109c25ff496ed96f92d477..f490a7a1080c03f3faed455d9de41adda3b59a1f 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -304,6 +304,10 @@ Core and Builtins
 
 Library
 -------
+
+- issue #1673007: urllib2  to support HEAD request via new method argument.
+  Patch contributions by David Stanek, Patrick Westerhoff and Ezio Melotti.
+
 - Issue #12386: packaging does not fail anymore when writing the RESOURCES
   file.