diff options
author | Raymond Hettinger <python@rcn.com> | 2003-04-24 15:32:12 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2003-04-24 15:32:12 (GMT) |
commit | 024aaa1bfe27cbc47c2a7f88c21c9bb1b6605191 (patch) | |
tree | 4281503f96d6e650cd0338bfbbf58c5479f9dc51 /Lib | |
parent | 1d5854fdc49073a3e49799192bc762ae0a68b64f (diff) | |
download | cpython-024aaa1bfe27cbc47c2a7f88c21c9bb1b6605191.zip cpython-024aaa1bfe27cbc47c2a7f88c21c9bb1b6605191.tar.gz cpython-024aaa1bfe27cbc47c2a7f88c21c9bb1b6605191.tar.bz2 |
SF Patch 549151: urllib2 POSTs on redirect
(contributed by John J Lee)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/urllib.py | 4 | ||||
-rw-r--r-- | Lib/urllib2.py | 38 |
2 files changed, 38 insertions, 4 deletions
diff --git a/Lib/urllib.py b/Lib/urllib.py index bd8347e..42851ee 100644 --- a/Lib/urllib.py +++ b/Lib/urllib.py @@ -586,6 +586,10 @@ class FancyURLopener(URLopener): """Error 301 -- also relocated (permanently).""" return self.http_error_302(url, fp, errcode, errmsg, headers, data) + def http_error_303(self, url, fp, errcode, errmsg, headers, data=None): + """Error 303 -- also relocated (essentially identical to 302).""" + return self.http_error_302(url, fp, errcode, errmsg, headers, data) + def http_error_401(self, url, fp, errcode, errmsg, headers, data=None): """Error 401 -- authentication required. See this URL for a description of the basic authentication scheme: diff --git a/Lib/urllib2.py b/Lib/urllib2.py index f189b39..b6b2ac6 100644 --- a/Lib/urllib2.py +++ b/Lib/urllib2.py @@ -11,8 +11,8 @@ option. The OpenerDirector is a composite object that invokes the Handlers needed to open the requested URL. For example, the HTTPHandler performs HTTP GET and POST requests and deals with non-error returns. The HTTPRedirectHandler automatically deals with -HTTP 301 & 302 redirect errors, and the HTTPDigestAuthHandler deals -with digest authentication. +HTTP 301, 302, 303 and 307 redirect errors, and the HTTPDigestAuthHandler +deals with digest authentication. urlopen(url, data=None) -- basic usage is that same as original urllib. pass the url and optionally data to post to an HTTP URL, and @@ -207,6 +207,12 @@ class Request: return getattr(self, attr) raise AttributeError, attr + def get_method(self): + if self.has_data(): + return "POST" + else: + return "GET" + def add_data(self, data): self.data = data @@ -402,6 +408,26 @@ class HTTPDefaultErrorHandler(BaseHandler): raise HTTPError(req.get_full_url(), code, msg, hdrs, fp) class HTTPRedirectHandler(BaseHandler): + def redirect_request(self, req, fp, code, msg, headers): + """Return a Request or None in response to a redirect. + + This is called by the http_error_30x methods when a redirection + response is received. If a redirection should take place, return a new + Request to allow http_error_30x to perform the redirect. Otherwise, + raise HTTPError if no-one else should try to handle this url. Return + None if you can't but another Handler might. + + """ + if (code in (301, 302, 303, 307) and req.method() in ("GET", "HEAD") or + code in (302, 303) and req.method() == "POST"): + # Strictly (according to RFC 2616), 302 in response to a POST + # MUST NOT cause a redirection without confirmation from the user + # (of urllib2, in this case). In practice, essentially all clients + # do redirect in this case, so we do the same. + return Request(newurl, headers=req.headers) + else: + raise HTTPError(req.get_full_url(), code, msg, hdrs, fp) + # Implementation note: To avoid the server sending us into an # infinite loop, the request object needs to track what URLs we # have already seen. Do this by adding a handler-specific @@ -418,7 +444,11 @@ class HTTPRedirectHandler(BaseHandler): # XXX Probably want to forget about the state of the current # request, although that might interact poorly with other # handlers that also use handler-specific request attributes - new = Request(newurl, req.get_data(), req.headers) + new = self.redirect_request(req, fp, code, msg, headers) + if new is None: + return + + # loop detection new.error_302_dict = {} if hasattr(req, 'error_302_dict'): if len(req.error_302_dict)>10 or \ @@ -435,7 +465,7 @@ class HTTPRedirectHandler(BaseHandler): return self.parent.open(new) - http_error_301 = http_error_302 + http_error_301 = http_error_303 = http_error_307 = http_error_302 inf_msg = "The HTTP server returned a redirect error that would" \ "lead to an infinite loop.\n" \ |