Mercurial > hg
annotate mercurial/sshserver.py @ 2434:a2df85adface
http server: support persistent connections.
only "hg serve" affected yet. http server running cgi script will not
use persistent connections. support for fastcgi will help that.
clients that support keepalive can use one tcp connection for all
commands during clone and pull. this makes latency of binary search
during pull much lower over wan.
if server does not know content-length, it will force connection to
close at end. right fix is to use chunked transfer-encoding but this is
easier and does not hurt performance. only command that is affected is
"changegroup" which is always last command during a pull.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Thu, 15 Jun 2006 12:55:58 -0700 |
parents | b17eebc911ae |
children | e8c4f3d3df8c |
rev | line source |
---|---|
2399 | 1 # sshserver.py - ssh protocol server support for mercurial |
2396 | 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 from demandload import demandload | |
9 from i18n import gettext as _ | |
10 from node import * | |
11 demandload(globals(), "sys util") | |
12 | |
13 class sshserver(object): | |
14 def __init__(self, ui, repo): | |
15 self.ui = ui | |
16 self.repo = repo | |
17 self.lock = None | |
18 self.fin = sys.stdin | |
19 self.fout = sys.stdout | |
20 | |
21 sys.stdout = sys.stderr | |
22 | |
23 # Prevent insertion/deletion of CRs | |
24 util.set_binary(self.fin) | |
25 util.set_binary(self.fout) | |
26 | |
27 def getarg(self): | |
28 argline = self.fin.readline()[:-1] | |
29 arg, l = argline.split() | |
30 val = self.fin.read(int(l)) | |
31 return arg, val | |
32 | |
33 def respond(self, v): | |
34 self.fout.write("%d\n" % len(v)) | |
35 self.fout.write(v) | |
36 self.fout.flush() | |
37 | |
38 def serve_forever(self): | |
39 while self.serve_one(): pass | |
40 sys.exit(0) | |
41 | |
42 def serve_one(self): | |
43 cmd = self.fin.readline()[:-1] | |
44 if cmd: | |
45 impl = getattr(self, 'do_' + cmd, None) | |
46 if impl: impl() | |
2397
e9d402506514
merge change to ssh protocol.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2396
diff
changeset
|
47 else: self.respond("") |
2396 | 48 return cmd != '' |
49 | |
50 def do_heads(self): | |
51 h = self.repo.heads() | |
52 self.respond(" ".join(map(hex, h)) + "\n") | |
53 | |
2419
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
54 def do_hello(self): |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
55 '''the hello command returns a set of lines describing various |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
56 interesting things about the server, in an RFC822-like format. |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
57 Currently the only one defined is "capabilities", which |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
58 consists of a line in the form: |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
59 |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
60 capabilities: space separated list of tokens |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
61 ''' |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
62 |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
63 r = "capabilities:\n" |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
64 self.respond(r) |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
65 |
2396 | 66 def do_lock(self): |
67 self.lock = self.repo.lock() | |
68 self.respond("") | |
69 | |
70 def do_unlock(self): | |
71 if self.lock: | |
72 self.lock.release() | |
73 self.lock = None | |
74 self.respond("") | |
75 | |
76 def do_branches(self): | |
77 arg, nodes = self.getarg() | |
78 nodes = map(bin, nodes.split(" ")) | |
79 r = [] | |
80 for b in self.repo.branches(nodes): | |
81 r.append(" ".join(map(hex, b)) + "\n") | |
82 self.respond("".join(r)) | |
83 | |
84 def do_between(self): | |
85 arg, pairs = self.getarg() | |
86 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")] | |
87 r = [] | |
88 for b in self.repo.between(pairs): | |
89 r.append(" ".join(map(hex, b)) + "\n") | |
90 self.respond("".join(r)) | |
91 | |
92 def do_changegroup(self): | |
93 nodes = [] | |
94 arg, roots = self.getarg() | |
95 nodes = map(bin, roots.split(" ")) | |
96 | |
97 cg = self.repo.changegroup(nodes, 'serve') | |
98 while True: | |
99 d = cg.read(4096) | |
100 if not d: | |
101 break | |
102 self.fout.write(d) | |
103 | |
104 self.fout.flush() | |
105 | |
106 def do_addchangegroup(self): | |
107 if not self.lock: | |
108 self.respond("not locked") | |
109 return | |
110 | |
111 self.respond("") | |
112 r = self.repo.addchangegroup(self.fin, 'serve') | |
113 self.respond(str(r)) |