From 3a9d9f22791dfe8947d9b08ff83c80a5ed49bd95 Mon Sep 17 00:00:00 2001 From: Akira Kitada Date: Mon, 25 Nov 2013 22:29:53 +0900 Subject: [PATCH] Fix hangs on streaming uploads with HTTPDigestAuth When using Digest Authentication, the client resends the same request after the server responds with the 401 "Unauthorized". However, when doing streaming uploads, it gets stuck because the body data (a file-like object) is already consumed at the initial request. The patch fixes this by rewinding the file-like object before resending the request. --- requests/auth.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/requests/auth.py b/requests/auth.py index e11a1fa..a3de123 100644 --- a/requests/auth.py +++ b/requests/auth.py @@ -63,6 +63,7 @@ class HTTPDigestAuth(AuthBase): self.last_nonce = '' self.nonce_count = 0 self.chal = {} + self.pos = None def build_digest_header(self, method, url): @@ -150,6 +151,10 @@ class HTTPDigestAuth(AuthBase): def handle_401(self, r, **kwargs): """Takes the given response and tries digest-auth, if needed.""" + if self.pos is not None: + # Rewind the file position indicator of the body to where + # it was to resend the request. + r.request.body.seek(self.pos) num_401_calls = getattr(self, 'num_401_calls', 1) s_auth = r.headers.get('www-authenticate', '') @@ -181,5 +186,9 @@ class HTTPDigestAuth(AuthBase): # If we have a saved nonce, skip the 401 if self.last_nonce: r.headers['Authorization'] = self.build_digest_header(r.method, r.url) + try: + self.pos = r.body.tell() + except AttributeError: + pass r.register_hook('response', self.handle_401) return r -- 2.34.1