mercurial/httprepo.py
changeset 1089 142b5d5ec9cc
parent 1072 05dc7aba22eb
child 1251 84cf8834efb5
equal deleted inserted replaced
1088:39b916b1d8e4 1089:142b5d5ec9cc
       
     1 # httprepo.py - HTTP repository proxy classes for mercurial
       
     2 #
       
     3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
       
     4 #
       
     5 # This software may be used and distributed according to the terms
       
     6 # of the GNU General Public License, incorporated herein by reference.
       
     7 
       
     8 import urllib, urllib2, urlparse, os, zlib
       
     9 from node import *
       
    10 from remoterepo import *
       
    11 
       
    12 class httprepository(remoterepository):
       
    13     def __init__(self, ui, path):
       
    14         # fix missing / after hostname
       
    15         s = urlparse.urlsplit(path)
       
    16         partial = s[2]
       
    17         if not partial: partial = "/"
       
    18         self.url = urlparse.urlunsplit((s[0], s[1], partial, '', ''))
       
    19         self.ui = ui
       
    20         no_list = [ "localhost", "127.0.0.1" ]
       
    21         host = ui.config("http_proxy", "host")
       
    22         if host is None:
       
    23             host = os.environ.get("http_proxy")
       
    24         if host and host.startswith('http://'):
       
    25             host = host[7:]
       
    26         user = ui.config("http_proxy", "user")
       
    27         passwd = ui.config("http_proxy", "passwd")
       
    28         no = ui.config("http_proxy", "no")
       
    29         if no is None:
       
    30             no = os.environ.get("no_proxy")
       
    31         if no:
       
    32             no_list = no_list + no.split(",")
       
    33 
       
    34         no_proxy = 0
       
    35         for h in no_list:
       
    36             if (path.startswith("http://" + h + "/") or
       
    37                 path.startswith("http://" + h + ":") or
       
    38                 path == "http://" + h):
       
    39                 no_proxy = 1
       
    40 
       
    41         # Note: urllib2 takes proxy values from the environment and those will
       
    42         # take precedence
       
    43         for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
       
    44             try:
       
    45                 if os.environ.has_key(env):
       
    46                     del os.environ[env]
       
    47             except OSError:
       
    48                 pass
       
    49 
       
    50         proxy_handler = urllib2.BaseHandler()
       
    51         if host and not no_proxy:
       
    52             proxy_handler = urllib2.ProxyHandler({"http" : "http://" + host})
       
    53 
       
    54         authinfo = None
       
    55         if user and passwd:
       
    56             passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
       
    57             passmgr.add_password(None, host, user, passwd)
       
    58             authinfo = urllib2.ProxyBasicAuthHandler(passmgr)
       
    59 
       
    60         opener = urllib2.build_opener(proxy_handler, authinfo)
       
    61         urllib2.install_opener(opener)
       
    62 
       
    63     def dev(self):
       
    64         return -1
       
    65 
       
    66     def do_cmd(self, cmd, **args):
       
    67         self.ui.debug("sending %s command\n" % cmd)
       
    68         q = {"cmd": cmd}
       
    69         q.update(args)
       
    70         qs = urllib.urlencode(q)
       
    71         cu = "%s?%s" % (self.url, qs)
       
    72         resp = urllib2.urlopen(cu)
       
    73         proto = resp.headers['content-type']
       
    74 
       
    75         # accept old "text/plain" and "application/hg-changegroup" for now
       
    76         if not proto.startswith('application/mercurial') and \
       
    77                not proto.startswith('text/plain') and \
       
    78                not proto.startswith('application/hg-changegroup'):
       
    79             raise RepoError("'%s' does not appear to be an hg repository"
       
    80                             % self.url)
       
    81 
       
    82         if proto.startswith('application/mercurial'):
       
    83             version = proto[22:]
       
    84             if float(version) > 0.1:
       
    85                 raise RepoError("'%s' uses newer protocol %s" %
       
    86                                 (self.url, version))
       
    87 
       
    88         return resp
       
    89 
       
    90     def heads(self):
       
    91         d = self.do_cmd("heads").read()
       
    92         try:
       
    93             return map(bin, d[:-1].split(" "))
       
    94         except:
       
    95             self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
       
    96             raise
       
    97 
       
    98     def branches(self, nodes):
       
    99         n = " ".join(map(hex, nodes))
       
   100         d = self.do_cmd("branches", nodes=n).read()
       
   101         try:
       
   102             br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
       
   103             return br
       
   104         except:
       
   105             self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
       
   106             raise
       
   107 
       
   108     def between(self, pairs):
       
   109         n = "\n".join(["-".join(map(hex, p)) for p in pairs])
       
   110         d = self.do_cmd("between", pairs=n).read()
       
   111         try:
       
   112             p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
       
   113             return p
       
   114         except:
       
   115             self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
       
   116             raise
       
   117 
       
   118     def changegroup(self, nodes):
       
   119         n = " ".join(map(hex, nodes))
       
   120         f = self.do_cmd("changegroup", roots=n)
       
   121         bytes = 0
       
   122 
       
   123         class zread:
       
   124             def __init__(self, f):
       
   125                 self.zd = zlib.decompressobj()
       
   126                 self.f = f
       
   127                 self.buf = ""
       
   128             def read(self, l):
       
   129                 while l > len(self.buf):
       
   130                     r = self.f.read(4096)
       
   131                     if r:
       
   132                         self.buf += self.zd.decompress(r)
       
   133                     else:
       
   134                         self.buf += self.zd.flush()
       
   135                         break
       
   136                 d, self.buf = self.buf[:l], self.buf[l:]
       
   137                 return d
       
   138 
       
   139         return zread(f)
       
   140 
       
   141 class httpsrepository(httprepository):
       
   142     pass