1 # sshserver.py - ssh protocol server support for mercurial |
|
2 # |
|
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> |
|
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> |
|
5 # |
|
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. |
|
8 |
|
9 from __future__ import absolute_import |
|
10 |
|
11 import sys |
|
12 |
|
13 from .i18n import _ |
|
14 from . import ( |
|
15 encoding, |
|
16 error, |
|
17 hook, |
|
18 util, |
|
19 wireproto, |
|
20 ) |
|
21 |
|
22 class sshserver(wireproto.abstractserverproto): |
|
23 def __init__(self, ui, repo): |
|
24 self.ui = ui |
|
25 self.repo = repo |
|
26 self.lock = None |
|
27 self.fin = ui.fin |
|
28 self.fout = ui.fout |
|
29 self.name = 'ssh' |
|
30 |
|
31 hook.redirect(True) |
|
32 ui.fout = repo.ui.fout = ui.ferr |
|
33 |
|
34 # Prevent insertion/deletion of CRs |
|
35 util.setbinary(self.fin) |
|
36 util.setbinary(self.fout) |
|
37 |
|
38 def getargs(self, args): |
|
39 data = {} |
|
40 keys = args.split() |
|
41 for n in xrange(len(keys)): |
|
42 argline = self.fin.readline()[:-1] |
|
43 arg, l = argline.split() |
|
44 if arg not in keys: |
|
45 raise error.Abort(_("unexpected parameter %r") % arg) |
|
46 if arg == '*': |
|
47 star = {} |
|
48 for k in xrange(int(l)): |
|
49 argline = self.fin.readline()[:-1] |
|
50 arg, l = argline.split() |
|
51 val = self.fin.read(int(l)) |
|
52 star[arg] = val |
|
53 data['*'] = star |
|
54 else: |
|
55 val = self.fin.read(int(l)) |
|
56 data[arg] = val |
|
57 return [data[k] for k in keys] |
|
58 |
|
59 def getarg(self, name): |
|
60 return self.getargs(name)[0] |
|
61 |
|
62 def getfile(self, fpout): |
|
63 self.sendresponse('') |
|
64 count = int(self.fin.readline()) |
|
65 while count: |
|
66 fpout.write(self.fin.read(count)) |
|
67 count = int(self.fin.readline()) |
|
68 |
|
69 def redirect(self): |
|
70 pass |
|
71 |
|
72 def sendresponse(self, v): |
|
73 self.fout.write("%d\n" % len(v)) |
|
74 self.fout.write(v) |
|
75 self.fout.flush() |
|
76 |
|
77 def sendstream(self, source): |
|
78 write = self.fout.write |
|
79 for chunk in source.gen: |
|
80 write(chunk) |
|
81 self.fout.flush() |
|
82 |
|
83 def sendpushresponse(self, rsp): |
|
84 self.sendresponse('') |
|
85 self.sendresponse(str(rsp.res)) |
|
86 |
|
87 def sendpusherror(self, rsp): |
|
88 self.sendresponse(rsp.res) |
|
89 |
|
90 def sendooberror(self, rsp): |
|
91 self.ui.ferr.write('%s\n-\n' % rsp.message) |
|
92 self.ui.ferr.flush() |
|
93 self.fout.write('\n') |
|
94 self.fout.flush() |
|
95 |
|
96 def serve_forever(self): |
|
97 try: |
|
98 while self.serve_one(): |
|
99 pass |
|
100 finally: |
|
101 if self.lock is not None: |
|
102 self.lock.release() |
|
103 sys.exit(0) |
|
104 |
|
105 handlers = { |
|
106 str: sendresponse, |
|
107 wireproto.streamres: sendstream, |
|
108 wireproto.streamres_legacy: sendstream, |
|
109 wireproto.pushres: sendpushresponse, |
|
110 wireproto.pusherr: sendpusherror, |
|
111 wireproto.ooberror: sendooberror, |
|
112 } |
|
113 |
|
114 def serve_one(self): |
|
115 cmd = self.fin.readline()[:-1] |
|
116 if cmd and cmd in wireproto.commands: |
|
117 rsp = wireproto.dispatch(self.repo, self, cmd) |
|
118 self.handlers[rsp.__class__](self, rsp) |
|
119 elif cmd: |
|
120 impl = getattr(self, 'do_' + cmd, None) |
|
121 if impl: |
|
122 r = impl() |
|
123 if r is not None: |
|
124 self.sendresponse(r) |
|
125 else: |
|
126 self.sendresponse("") |
|
127 return cmd != '' |
|
128 |
|
129 def _client(self): |
|
130 client = encoding.environ.get('SSH_CLIENT', '').split(' ', 1)[0] |
|
131 return 'remote:ssh:' + client |
|