4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> |
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> |
5 # |
5 # |
6 # This software may be used and distributed according to the terms of the |
6 # This software may be used and distributed according to the terms of the |
7 # GNU General Public License version 2 or any later version. |
7 # GNU General Public License version 2 or any later version. |
8 |
8 |
9 import os, zlib, sys, cStringIO, urllib |
9 import os, sys, urllib |
10 from mercurial import ui, hg, hook, error, encoding, templater, wireproto, util |
10 from mercurial import ui, hg, hook, error, encoding, templater, util |
11 from common import get_mtime, ErrorResponse, permhooks |
11 from common import get_mtime, ErrorResponse, permhooks |
12 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR |
12 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR |
13 from request import wsgirequest |
13 from request import wsgirequest |
14 import webcommands, protocol, webutil |
14 import webcommands, protocol, webutil |
15 |
15 |
19 'stream_out': 'pull', |
19 'stream_out': 'pull', |
20 'listkeys': 'pull', |
20 'listkeys': 'pull', |
21 'unbundle': 'push', |
21 'unbundle': 'push', |
22 'pushkey': 'push', |
22 'pushkey': 'push', |
23 } |
23 } |
24 |
|
25 HGTYPE = 'application/mercurial-0.1' |
|
26 class webproto(object): |
|
27 def __init__(self, req): |
|
28 self.req = req |
|
29 self.response = '' |
|
30 def getargs(self, args): |
|
31 data = {} |
|
32 keys = args.split() |
|
33 for k in keys: |
|
34 if k == '*': |
|
35 star = {} |
|
36 for key in self.req.form.keys(): |
|
37 if key not in keys: |
|
38 star[key] = self.req.form[key][0] |
|
39 data['*'] = star |
|
40 else: |
|
41 data[k] = self.req.form[k][0] |
|
42 return [data[k] for k in keys] |
|
43 def sendchangegroup(self, cg): |
|
44 self.req.respond(HTTP_OK, HGTYPE) |
|
45 z = zlib.compressobj() |
|
46 while 1: |
|
47 chunk = cg.read(4096) |
|
48 if not chunk: |
|
49 break |
|
50 self.req.write(z.compress(chunk)) |
|
51 self.req.write(z.flush()) |
|
52 def sendstream(self, source): |
|
53 self.req.respond(HTTP_OK, HGTYPE) |
|
54 for chunk in source: |
|
55 self.req.write(chunk) |
|
56 def respond(self, s): |
|
57 self.req.respond(HTTP_OK, HGTYPE, length=len(s)) |
|
58 self.response = s |
|
59 def getfile(self, fp): |
|
60 length = int(self.req.env['CONTENT_LENGTH']) |
|
61 for s in util.filechunkiter(self.req, limit=length): |
|
62 fp.write(s) |
|
63 def redirect(self): |
|
64 self.oldio = sys.stdout, sys.stderr |
|
65 sys.stderr = sys.stdout = cStringIO.StringIO() |
|
66 def respondpush(self, ret): |
|
67 val = sys.stdout.getvalue() |
|
68 sys.stdout, sys.stderr = self.oldio |
|
69 self.req.respond(HTTP_OK, HGTYPE) |
|
70 self.response = '%d\n%s' % (ret, val) |
|
71 def _client(self): |
|
72 return 'remote:%s:%s:%s' % ( |
|
73 self.req.env.get('wsgi.url_scheme') or 'http', |
|
74 urllib.quote(self.req.env.get('REMOTE_HOST', '')), |
|
75 urllib.quote(self.req.env.get('REMOTE_USER', ''))) |
|
76 |
|
77 def callproto(repo, req, cmd): |
|
78 p = webproto(req) |
|
79 r = wireproto.dispatch(repo, p, cmd) |
|
80 yield p.response |
|
81 |
24 |
82 class hgweb(object): |
25 class hgweb(object): |
83 def __init__(self, repo, name=None, baseui=None): |
26 def __init__(self, repo, name=None, baseui=None): |
84 if isinstance(repo, str): |
27 if isinstance(repo, str): |
85 if baseui: |
28 if baseui: |
167 # process this if it's a protocol request |
110 # process this if it's a protocol request |
168 # protocol bits don't need to create any URLs |
111 # protocol bits don't need to create any URLs |
169 # and the clients always use the old URL structure |
112 # and the clients always use the old URL structure |
170 |
113 |
171 cmd = req.form.get('cmd', [''])[0] |
114 cmd = req.form.get('cmd', [''])[0] |
172 if cmd and cmd in protocol.__all__: |
115 if protocol.iscmd(cmd): |
173 if query: |
116 if query: |
174 raise ErrorResponse(HTTP_NOT_FOUND) |
117 raise ErrorResponse(HTTP_NOT_FOUND) |
175 try: |
118 if cmd in perms: |
176 if cmd in perms: |
119 try: |
177 try: |
120 self.check_perm(req, perms[cmd]) |
178 self.check_perm(req, perms[cmd]) |
121 except ErrorResponse, inst: |
179 except ErrorResponse, inst: |
122 if cmd == 'unbundle': |
180 if cmd == 'unbundle': |
123 req.drain() |
181 req.drain() |
124 req.respond(inst, protocol.HGTYPE) |
182 raise |
125 return '0\n%s\n' % inst.message |
183 if cmd in wireproto.commands: |
126 return protocol.call(self.repo, req, cmd) |
184 return callproto(self.repo, req, cmd) |
|
185 method = getattr(protocol, cmd) |
|
186 return method(self.repo, req) |
|
187 except ErrorResponse, inst: |
|
188 req.respond(inst, protocol.HGTYPE) |
|
189 if not inst.message: |
|
190 return [] |
|
191 return '0\n%s\n' % inst.message, |
|
192 |
127 |
193 # translate user-visible url structure to internal structure |
128 # translate user-visible url structure to internal structure |
194 |
129 |
195 args = query.split('/', 2) |
130 args = query.split('/', 2) |
196 if 'cmd' not in req.form and args and args[0]: |
131 if 'cmd' not in req.form and args and args[0]: |