Added the 'follow_redirects' attribute to Http()
diff --git a/Makefile b/Makefile
index 4de3c9c..5ad0253 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
release:
python2.4 setup.py sdist --formats=gztar,zip
doc:
- ./mkhowto --html ref.tex
+ pudge -v -f --modules=httplib2 --dest=build/doc
+ #./mkhowto --html ref.tex
diff --git a/httplib2/__init__.py b/httplib2/__init__.py
index 00137d7..63ef1a2 100644
--- a/httplib2/__init__.py
+++ b/httplib2/__init__.py
@@ -7,6 +7,10 @@
Requires Python 2.3 or later
+Supports:
+ - HTTPS
+ - Basic
+ - Digest
"""
__author__ = "Joe Gregorio (joe@bitworking.org)"
@@ -702,9 +706,17 @@
class Http:
- """An HTTP client that handles all
- methods, caching, ETags, compression,
- HTTPS, Basic, Digest, WSSE, etc.
+ """An HTTP client that handles:
+- all methods
+- caching
+- ETags
+- compression,
+- HTTPS
+- Basic
+- Digest
+- WSSE
+
+and more.
"""
def __init__(self, cache=None, timeout=None):
# Map domain name to an httplib connection
@@ -725,6 +737,11 @@
# authorization objects
self.authorizations = []
+ # If set to False then no redirects are followed, even safe ones.
+ self.follow_redirects = True
+
+ # If 'follow_redirects' is True, and this is set to True then
+ # all redirecs are followed, including unsafe ones.
self.follow_all_redirects = False
self.ignore_etag = False
@@ -809,8 +826,8 @@
authorization.response(response, body)
break
- if (self.follow_all_redirects or method in ["GET", "HEAD"]) or response.status == 303:
- if response.status in [300, 301, 302, 303, 307]:
+ if ((self.follow_all_redirects or method in ["GET", "HEAD"]) or response.status == 303):
+ if self.follow_redirects and response.status in [300, 301, 302, 303, 307]:
# Pick out the location header and basically start from the beginning
# remembering first to strip the ETag header and decrement our 'depth'
if redirections:
diff --git a/httplib2test.py b/httplib2test.py
index cbd8b7b..27e1a2d 100755
--- a/httplib2test.py
+++ b/httplib2test.py
@@ -204,6 +204,13 @@
self.assertEqual(response.previous.status, 300)
self.assertEqual(response.previous.fromcache, False)
+ def testGet300WithLocationNoRedirect(self):
+ # Test the we automatically follow 300 redirects if a Location: header is provided
+ self.http.follow_redirects = False
+ uri = urlparse.urljoin(base, "300/with-location-header.asis")
+ (response, content) = self.http.request(uri, "GET")
+ self.assertEqual(response.status, 300)
+
def testGet300WithoutLocation(self):
# Not giving a Location: header in a 300 response is acceptable
# In which case we just return the 300 response
@@ -233,6 +240,17 @@
self.assertEqual(response.previous.status, 301)
self.assertEqual(response.previous.fromcache, True)
+
+ def testGet301NoRedirect(self):
+ # Test that we automatically follow 301 redirects
+ # and that we cache the 301 response
+ self.http.follow_redirects = False
+ uri = urlparse.urljoin(base, "301/onestep.asis")
+ destination = urlparse.urljoin(base, "302/final-destination.txt")
+ (response, content) = self.http.request(uri, "GET")
+ self.assertEqual(response.status, 301)
+
+
def testGet302(self):
# Test that we automatically follow 302 redirects
# and that we DO NOT cache the 302 response
@@ -321,7 +339,6 @@
# Test that we can handle HTTPS
(response, content) = self.http.request("https://google.com/adsense/", "GET")
self.assertEqual(200, response.status)
- self.assertEqual(None, response.previous)
def testGetViaHttpsSpecViolationOnLocation(self):
# Test that we follow redirects through HTTPS
@@ -334,19 +351,11 @@
def testGetViaHttpsKeyCert(self):
- """At this point I can only test
- that the key and cert files are passed in
- correctly to httplib. It would be nice to have
- a real https endpoint to test against.
- """
- http = httplib2.Http()
- try:
- (response, content) = http.request("https://example.org", "GET")
- except:
- pass
- self.assertEqual(http.connections["https:example.org"].key_file, None)
- self.assertEqual(http.connections["https:example.org"].cert_file, None)
-
+ # At this point I can only test
+ # that the key and cert files are passed in
+ # correctly to httplib. It would be nice to have
+ # a real https endpoint to test against.
+ http = httplib2.Http(timeout=2)
http.add_certificate("akeyfile", "acertfile", "bitworking.org")
try:
@@ -356,6 +365,15 @@
self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
+ try:
+ (response, content) = http.request("https://notthere.bitworking.org", "GET")
+ except:
+ pass
+ self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
+ self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
+
+
+
def testGet303(self):
# Do a follow-up GET on a Location: header
@@ -366,6 +384,14 @@
self.assertEqual(content, "This is the final destination.\n")
self.assertEqual(response.previous.status, 303)
+ def testGet303NoRedirect(self):
+ # Do a follow-up GET on a Location: header
+ # returned from a POST that gave a 303.
+ self.http.follow_redirects = False
+ uri = urlparse.urljoin(base, "303/303.cgi")
+ (response, content) = self.http.request(uri, "POST", " ")
+ self.assertEqual(response.status, 303)
+
def test303ForDifferentMethods(self):
# Test that all methods can be used
uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
diff --git a/libhttplib2.tex b/libhttplib2.tex
index e876751..dec2573 100644
--- a/libhttplib2.tex
+++ b/libhttplib2.tex
@@ -233,6 +233,15 @@
Remove all the names and passwords used for authentication.
\end{methoddesc}
+\begin{memberdesc}[Http]{follow_redirects}
+If \code{True}, which is the default, safe redirects are followed, where
+safe means that the client is only doing a \code{GET} or \code{HEAD} on the
+URI to which it is being redirected. If \code{False} then no redirects are followed.
+Note that a False 'follow_redirects' takes precedence over a True 'follow_all_redirects'.
+Another way of saying that is for 'follow_all_redirects' to have any affect, 'follow_redirects'
+must by True.
+\end{memberdesc}
+
\begin{memberdesc}[Http]{follow_all_redirects}
If \code{False}, which is the default, only safe redirects are followed, where
safe means that the client is only doing a \code{GET} or \code{HEAD} on the