[PATCH] Keep authentication information after the first fail HTTP access (issue3567)

Stéphane Klein sklein at bearstech.com
Mon Feb 17 07:27:53 CST 2014


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Le 07/02/14 03:09, Mads Kiilerich a écrit :
> On 01/20/2014 05:15 PM, Mads Kiilerich wrote:
>> On 01/20/2014 04:57 PM, Stéphane Klein wrote:
>>> Le 20/01/14 01:52, Mads Kiilerich a écrit :
>>>> With these changes the patch looks good to me. It fixes an annoying
>>>> problem that has been around forever.
>>> Do you mean that you have fixed my patch or do I need to resend my
>>> patch with this change ? in other word : shall I do something to help
>>> to "push this patch" ?
>> 
>> I do think that 
>> http://selenic.com/pipermail/mercurial-devel/2014-January/055766.html
>> should be enough. But if you disagree or would like to improve on it then
>> please take it back or start from your latest version or something.
>> 
>> You can probably help pushing this patch forward by doing some history
>> digging in the Python repo and see why
>> http://hg.python.org/cpython/rev/ac02f655b31e was backed out again. It
>> would be nice to have a compelling argument why my change is good or bad.
>> http://bz.selenic.com/show_bug.cgi?id=2739 can perhaps also provide some
>> background information.
> 
> Your patch didn't make it for 2.9. :-(
> 
> My test that will show that it works is now in 'default'.
> 
> Please resend for 'default' with corresponding test update ... or aim at 
> 'stable' again if you feel adventurous.
> 
> /Mads
> 


# HG changeset patch
# User Stéphane Klein <contact at stephane-klein.info>
# Date 1392643459 -3600
#      Mon Feb 17 14:24:19 2014 +0100
# Node ID e64f75d26305e44f3136db6d147385f94f043134
# Parent  0e2877f8605dcaf4fdf2ab7e0046f1f6f80161dd
http: reuse authentication info after the first failed request (issue3567)

Context : mercurial access to repository server with http access, and this
server is protected by basic auth.

Before patch :

* mercurial try an anonymous access to server, server return 401 response and
  mercurial resend request with login / password information

After patch :

* mercurial try an anonymous access to server, server return
  401 response. For all next requests, mercurial keep in memory this
  information (this server need basic auth information).

This patch reduce the number of http access against mercurial server.

Example, before patch :

10.10.168.170 - - [25/Oct/2013:15:44:51 +0200] "GET /hg/testagt?cmd=capabilities
HTTP/1.1" 401 260 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:44:52 +0200] "GET /hg/testagt?cmd=capabilities
HTTP/1.1" 200 147 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:00 +0200] "GET /hg/testagt?cmd=capabilities
HTTP/1.1" 401 260 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:01 +0200] "GET /hg/testagt?cmd=capabilities
HTTP/1.1" 200 147 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:03 +0200] "GET /hg/testagt?cmd=batch
HTTP/1.1" 401 260 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:04 +0200] "GET /hg/testagt?cmd=batch
HTTP/1.1" 200 42 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:06 +0200] "GET /hg/testagt?cmd=getbundle
HTTP/1.1" 401 260 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:07 +0200] "GET /hg/testagt?cmd=getbundle
HTTP/1.1" 200 61184 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:09 +0200] "GET /hg/testagt?cmd=listkeys
HTTP/1.1" 401 260 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:10 +0200] "GET /hg/testagt?cmd=listkeys
HTTP/1.1" 200 15 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:12 +0200] "GET /hg/testagt?cmd=listkeys
HTTP/1.1" 401 260 "-" "mercurial/proto-1.0"
10.10.168.170 - - [25/Oct/2013:15:45:12 +0200] "GET /hg/testagt?cmd=listkeys
HTTP/1.1" 200 - "-" "mercurial/proto-1.0"

Example after patch :

10.10.168.170 - - [28/Oct/2013:11:49:14 +0100] "GET /hg/testagt?cmd=capabilities
HTTP/1.1" 401 260 "-" "mercurial/proto-1.0"
10.10.168.170 - - [28/Oct/2013:11:49:15 +0100] "GET /hg/testagt?cmd=capabilities
HTTP/1.1" 200 147 "-" "mercurial/proto-1.0"
10.10.168.170 - - [28/Oct/2013:11:49:17 +0100] "GET /hg/testagt?cmd=batch
HTTP/1.1" 200 42 "-" "mercurial/proto-1.0"
10.10.168.170 - - [28/Oct/2013:11:49:19 +0100] "GET /hg/testagt?cmd=getbundle
HTTP/1.1" 200 61184 "-" "mercurial/proto-1.0"
10.10.168.170 - - [28/Oct/2013:11:49:22 +0100] "GET /hg/testagt?cmd=listkeys
HTTP/1.1" 200 15 "-" "mercurial/proto-1.0"
10.10.168.170 - - [28/Oct/2013:11:49:24 +0100] "GET /hg/testagt?cmd=listkeys
HTTP/1.1" 200 - "-" "mercurial/proto-1.0"

In this last example, you can see only one 401 response.

diff -r 0e2877f8605d -r e64f75d26305 mercurial/url.py
- --- a/mercurial/url.py	Sat Feb 15 22:09:32 2014 -0600
+++ b/mercurial/url.py	Mon Feb 17 14:24:19 2014 +0100
@@ -8,6 +8,7 @@
 # GNU General Public License version 2 or any later version.

 import urllib, urllib2, httplib, os, socket, cStringIO
+import base64
 from i18n import _
 import keepalive, util, sslutil
 import httpconnection as httpconnectionmod
@@ -422,9 +423,22 @@

 class httpbasicauthhandler(urllib2.HTTPBasicAuthHandler):
     def __init__(self, *args, **kwargs):
+        self.auth = None
         urllib2.HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
         self.retried_req = None

+    def http_request(self, request):
+        if self.auth:
+            request.add_unredirected_header(self.auth_header, self.auth)
+
+        return request
+
+    def https_request(self, request):
+        if self.auth:
+            request.add_unredirected_header(self.auth_header, self.auth)
+
+        return request
+
     def reset_retry_count(self):
         # Python 2.6.5 will call this on 401 or 407 errors and thus loop
         # forever. We disable reset_retry_count completely and reset in
@@ -439,6 +453,19 @@
         return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(
                         self, auth_header, host, req, headers)

+    def retry_http_basic_auth(self, host, req, realm):
+        user, pw = self.passwd.find_user_password(realm, req.get_full_url())
+        if pw is not None:
+            raw = "%s:%s" % (user, pw)
+            auth = 'Basic %s' % base64.b64encode(raw).strip()
+            if req.headers.get(self.auth_header, None) == auth:
+                return None
+            self.auth = auth
+            req.add_header(self.auth_header, auth)
+            return self.parent.open(req)
+        else:
+            return None
+
 handlerfuncs = []

- -- 
Stéphane Klein <sklein at bearstech.com>
GSM : 06 61 48 76 04
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iF4EAREIAAYFAlMCDlkACgkQU9O4HJsr4YzYpgEAi0XiApZuBBEUbhic5VjKmoTD
9VvrU+2CeF3/Fqh5HFIBAMdTZ8uay1qMei84+jOZmEPIdlqiJU7U1i+TVZgW2BvQ
=Gxkk
-----END PGP SIGNATURE-----


More information about the Mercurial-devel mailing list