##// END OF EJS Templates
Respect "Connection: close" headers sent by HTTP clients....
Respect "Connection: close" headers sent by HTTP clients. A HTTP client can indicate that it doesn't support (or doesn't want) persistent connections by sending this header. This not only makes the server more compliant with the RFC, but also reduces the run time of test-http-proxy when run with python 2.3 from ~125s to ~5s (it doesn't affect it with python 2.4, which was already ~5s).

File last commit:

r2439:e8c4f3d3 default
r2582:276de216 default
Show More
sshserver.py
169 lines | 4.6 KiB | text/x-python | PythonLexer
# sshserver.py - ssh protocol server support for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
from demandload import demandload
from i18n import gettext as _
from node import *
demandload(globals(), "os sys tempfile util")
class sshserver(object):
def __init__(self, ui, repo):
self.ui = ui
self.repo = repo
self.lock = None
self.fin = sys.stdin
self.fout = sys.stdout
sys.stdout = sys.stderr
# Prevent insertion/deletion of CRs
util.set_binary(self.fin)
util.set_binary(self.fout)
def getarg(self):
argline = self.fin.readline()[:-1]
arg, l = argline.split()
val = self.fin.read(int(l))
return arg, val
def respond(self, v):
self.fout.write("%d\n" % len(v))
self.fout.write(v)
self.fout.flush()
def serve_forever(self):
while self.serve_one(): pass
sys.exit(0)
def serve_one(self):
cmd = self.fin.readline()[:-1]
if cmd:
impl = getattr(self, 'do_' + cmd, None)
if impl: impl()
else: self.respond("")
return cmd != ''
def do_heads(self):
h = self.repo.heads()
self.respond(" ".join(map(hex, h)) + "\n")
def do_hello(self):
'''the hello command returns a set of lines describing various
interesting things about the server, in an RFC822-like format.
Currently the only one defined is "capabilities", which
consists of a line in the form:
capabilities: space separated list of tokens
'''
r = "capabilities: unbundle\n"
self.respond(r)
def do_lock(self):
'''DEPRECATED - allowing remote client to lock repo is not safe'''
self.lock = self.repo.lock()
self.respond("")
def do_unlock(self):
'''DEPRECATED'''
if self.lock:
self.lock.release()
self.lock = None
self.respond("")
def do_branches(self):
arg, nodes = self.getarg()
nodes = map(bin, nodes.split(" "))
r = []
for b in self.repo.branches(nodes):
r.append(" ".join(map(hex, b)) + "\n")
self.respond("".join(r))
def do_between(self):
arg, pairs = self.getarg()
pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
r = []
for b in self.repo.between(pairs):
r.append(" ".join(map(hex, b)) + "\n")
self.respond("".join(r))
def do_changegroup(self):
nodes = []
arg, roots = self.getarg()
nodes = map(bin, roots.split(" "))
cg = self.repo.changegroup(nodes, 'serve')
while True:
d = cg.read(4096)
if not d:
break
self.fout.write(d)
self.fout.flush()
def do_addchangegroup(self):
'''DEPRECATED'''
if not self.lock:
self.respond("not locked")
return
self.respond("")
r = self.repo.addchangegroup(self.fin, 'serve')
self.respond(str(r))
def do_unbundle(self):
their_heads = self.getarg()[1].split()
def check_heads():
heads = map(hex, self.repo.heads())
return their_heads == [hex('force')] or their_heads == heads
# fail early if possible
if not check_heads():
self.respond(_('unsynced changes'))
return
self.respond('')
# write bundle data to temporary file because it can be big
try:
fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
fp = os.fdopen(fd, 'wb+')
count = int(self.fin.readline())
while count:
fp.write(self.fin.read(count))
count = int(self.fin.readline())
was_locked = self.lock is not None
if not was_locked:
self.lock = self.repo.lock()
try:
if not check_heads():
# someone else committed/pushed/unbundled while we
# were transferring data
self.respond(_('unsynced changes'))
return
self.respond('')
# push can proceed
fp.seek(0)
r = self.repo.addchangegroup(fp, 'serve')
self.respond(str(r))
finally:
if not was_locked:
self.lock.release()
self.lock = None
finally:
fp.close()
os.unlink(tempname)