##// END OF EJS Templates
match: document bad callback semantics
match: document bad callback semantics

File last commit:

r8663:45f626a3 default
r8678:43598055 default
Show More
server.py
298 lines | 10.5 KiB | text/x-python | PythonLexer
Eric Hopper
Fixing up comment headers for split up code.
r2391 # hgweb/server.py - The standalone hg web server.
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Thomas Arendsen Hein
sync with -stable
r4016 import os, sys, errno, urllib, BaseHTTPServer, socket, SocketServer, traceback
Matt Mackall
error: move repo errors...
r7637 from mercurial import hg, util, error
Matt Mackall
Replace demandload with new demandimport
r3877 from hgweb_mod import hgweb
from hgwebdir_mod import hgwebdir
Martin Geisler
i18n: import _ instead of gettext
r7225 from mercurial.i18n import _
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
def _splitURI(uri):
""" Return path and query splited from uri
Just like CGI environment, the path is unquoted, the query is
not.
"""
if '?' in uri:
path, query = uri.split('?', 1)
else:
path, query = uri, ''
return urllib.unquote(path), query
Eric Hopper
This patch make several WSGI related alterations....
r2506 class _error_logger(object):
def __init__(self, handler):
self.handler = handler
def flush(self):
pass
Benoit Boissinot
hgweb: fix errors spotted by pychecker
r3130 def write(self, str):
Eric Hopper
This patch make several WSGI related alterations....
r2506 self.writelines(str.split('\n'))
Benoit Boissinot
hgweb: fix errors spotted by pychecker
r3130 def writelines(self, seq):
Eric Hopper
This patch make several WSGI related alterations....
r2506 for msg in seq:
self.handler.log_error("HG error: %s", msg)
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler):
Wesley J. Landaker
Make hg serve set the wsgi.url_scheme property correctly....
r4870
url_scheme = 'http'
Thomas Arendsen Hein
removed trailing whitespace
r4957
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 def __init__(self, *args, **kargs):
Vadim Gelfer
http server: support persistent connections....
r2434 self.protocol_version = 'HTTP/1.1'
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs)
Patrick Mezard
hgweb.server: flush log files after every access
r5549 def _log_any(self, fp, format, *args):
fp.write("%s - - [%s] %s\n" % (self.client_address[0],
self.log_date_time_string(),
format % args))
fp.flush()
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 def log_error(self, format, *args):
Patrick Mezard
hgweb.server: flush log files after every access
r5549 self._log_any(self.server.errorlog, format, *args)
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
def log_message(self, format, *args):
Patrick Mezard
hgweb.server: flush log files after every access
r5549 self._log_any(self.server.accesslog, format, *args)
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 def do_write(self):
try:
self.do_hgweb()
except socket.error, inst:
if inst[0] != errno.EPIPE:
raise
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 def do_POST(self):
try:
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 self.do_write()
Benoit Boissinot
remove unused variables
r7280 except StandardError:
Thomas Arendsen Hein
Handle exceptions in do_hgweb: Send "Internal Server Error", log traceback
r4015 self._start_response("500 Internal Server Error", [])
self._write("Internal Server Error")
tb = "".join(traceback.format_exception(*sys.exc_info()))
Martin Geisler
wrap string literals in error messages
r8663 self.log_error("Exception happened during processing "
"request '%s':\n%s", self.path, tb)
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
def do_GET(self):
self.do_POST()
def do_hgweb(self):
Michele Cella
adding "prefix" option to "hg serve" (command line and [web] section)...
r5835 path, query = _splitURI(self.path)
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
env = {}
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
env['REQUEST_METHOD'] = self.command
env['SERVER_NAME'] = self.server.server_name
env['SERVER_PORT'] = str(self.server.server_port)
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 env['REQUEST_URI'] = self.path
Michele Cella
adding "prefix" option to "hg serve" (command line and [web] section)...
r5835 env['SCRIPT_NAME'] = self.server.prefix
env['PATH_INFO'] = path[len(self.server.prefix):]
Matt Mackall
hg serve: don't do DNS lookups
r4359 env['REMOTE_HOST'] = self.client_address[0]
env['REMOTE_ADDR'] = self.client_address[0]
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 if query:
env['QUERY_STRING'] = query
if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
else:
env['CONTENT_TYPE'] = self.headers.typeheader
length = self.headers.getheader('content-length')
if length:
env['CONTENT_LENGTH'] = length
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 for header in [h for h in self.headers.keys()
Eric Hopper
Fix server to set up a more WSGI compliant environment.
r2505 if h not in ('content-type', 'content-length')]:
hkey = 'HTTP_' + header.replace('-', '_').upper()
hval = self.headers.getheader(header)
hval = hval.replace('\n', '').strip()
if hval:
env[hkey] = hval
env['SERVER_PROTOCOL'] = self.request_version
Eric Hopper
This patch make several WSGI related alterations....
r2506 env['wsgi.version'] = (1, 0)
Brendan Cully
cosmetics
r4871 env['wsgi.url_scheme'] = self.url_scheme
Eric Hopper
This patch make several WSGI related alterations....
r2506 env['wsgi.input'] = self.rfile
env['wsgi.errors'] = _error_logger(self)
env['wsgi.multithread'] = isinstance(self.server,
SocketServer.ThreadingMixIn)
env['wsgi.multiprocess'] = isinstance(self.server,
SocketServer.ForkingMixIn)
env['wsgi.run_once'] = 0
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Eric Hopper
This patch make several WSGI related alterations....
r2506 self.close_connection = True
self.saved_status = None
self.saved_headers = []
self.sent_headers = False
Eric Hopper
Put support for persistent connections back in.
r2508 self.length = None
Dirkjan Ochtman
hgweb: all protocol functions have become generators...
r6784 for chunk in self.server.application(env, self._start_response):
self._write(chunk)
Eric Hopper
This patch make several WSGI related alterations....
r2506
def send_headers(self):
if not self.saved_status:
Martin Geisler
wrap string literals in error messages
r8663 raise AssertionError("Sending headers before "
"start_response() called")
Eric Hopper
This patch make several WSGI related alterations....
r2506 saved_status = self.saved_status.split(None, 1)
saved_status[0] = int(saved_status[0])
self.send_response(*saved_status)
Eric Hopper
Put support for persistent connections back in.
r2508 should_close = True
Eric Hopper
This patch make several WSGI related alterations....
r2506 for h in self.saved_headers:
self.send_header(*h)
Eric Hopper
Put support for persistent connections back in.
r2508 if h[0].lower() == 'content-length':
should_close = False
self.length = int(h[1])
Alexis S. L. Carvalho
Respect "Connection: close" headers sent by HTTP clients....
r2582 # The value of the Connection header is a list of case-insensitive
# tokens separated by commas and optional whitespace.
Vadim Gelfer
clean up trailing white space.
r2600 if 'close' in [token.strip().lower() for token in
Alexis S. L. Carvalho
Respect "Connection: close" headers sent by HTTP clients....
r2582 self.headers.get('connection', '').split(',')]:
should_close = True
Eric Hopper
Put support for persistent connections back in.
r2508 if should_close:
self.send_header('Connection', 'close')
self.close_connection = should_close
Eric Hopper
This patch make several WSGI related alterations....
r2506 self.end_headers()
self.sent_headers = True
def _start_response(self, http_status, headers, exc_info=None):
code, msg = http_status.split(None, 1)
code = int(code)
self.saved_status = http_status
Eric Hopper
Put support for persistent connections back in.
r2508 bad_headers = ('connection', 'transfer-encoding')
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 self.saved_headers = [h for h in headers
if h[0].lower() not in bad_headers]
Eric Hopper
This patch make several WSGI related alterations....
r2506 return self._write
def _write(self, data):
if not self.saved_status:
raise AssertionError("data written before start_response() called")
elif not self.sent_headers:
self.send_headers()
Eric Hopper
Put support for persistent connections back in.
r2508 if self.length is not None:
if len(data) > self.length:
Martin Geisler
wrap string literals in error messages
r8663 raise AssertionError("Content-length header sent, but more "
"bytes than specified are being written.")
Eric Hopper
Put support for persistent connections back in.
r2508 self.length = self.length - len(data)
Eric Hopper
This patch make several WSGI related alterations....
r2506 self.wfile.write(data)
self.wfile.flush()
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 class _shgwebhandler(_hgwebhandler):
Wesley J. Landaker
Make hg serve set the wsgi.url_scheme property correctly....
r4870
url_scheme = 'https'
Thomas Arendsen Hein
removed trailing whitespace
r4957
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 def setup(self):
self.connection = self.request
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
def do_write(self):
from OpenSSL.SSL import SysCallError
try:
super(_shgwebhandler, self).do_write()
except SysCallError, inst:
if inst.args[0] != errno.EPIPE:
raise
def handle_one_request(self):
from OpenSSL.SSL import SysCallError, ZeroReturnError
try:
super(_shgwebhandler, self).handle_one_request()
except (SysCallError, ZeroReturnError):
self.close_connection = True
pass
Eric Hopper
Adjusting hgweb splitup to be a little cleaner.
r2392 def create_server(ui, repo):
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 use_threads = True
def openlog(opt, default):
if opt and opt != '-':
Mirko Friedenhagen
server: append to logfiles
r5690 return open(opt, 'a')
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 return default
Eric Hopper
Fix hgwebdir after 9858477ed74cce9dc8f4069f9453a1bda0e13ba1 broke it.
r5083 if repo is None:
Benoit Boissinot
unobfuscate part of f94dbc6c7eaf
r5086 myui = ui
Eric Hopper
Fix hgwebdir after 9858477ed74cce9dc8f4069f9453a1bda0e13ba1 broke it.
r5083 else:
Benoit Boissinot
unobfuscate part of f94dbc6c7eaf
r5086 myui = repo.ui
address = myui.config("web", "address", "")
port = int(myui.config("web", "port", 8000))
Michele Cella
hgweb: fixes to make hg serve prefix handling more robust
r5970 prefix = myui.config("web", "prefix", "")
if prefix:
prefix = "/" + prefix.strip("/")
Benoit Boissinot
unobfuscate part of f94dbc6c7eaf
r5086 use_ipv6 = myui.configbool("web", "ipv6")
webdir_conf = myui.config("web", "webdir_conf")
Benoit Boissinot
merge with -stable
r5150 ssl_cert = myui.config("web", "certificate")
Benoit Boissinot
unobfuscate part of f94dbc6c7eaf
r5086 accesslog = openlog(myui.config("web", "accesslog", "-"), sys.stdout)
errorlog = openlog(myui.config("web", "errorlog", "-"), sys.stderr)
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
if use_threads:
try:
from threading import activeCount
except ImportError:
use_threads = False
if use_threads:
_mixin = SocketServer.ThreadingMixIn
else:
if hasattr(os, "fork"):
_mixin = SocketServer.ForkingMixIn
else:
Thomas Arendsen Hein
white space and line break cleanups
r3673 class _mixin:
pass
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer):
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Patrick Mezard
web/server: disable address reuse option for BaseHTTPServer on windows...
r4130 # SO_REUSEADDR has broken semantics on windows
if os.name == 'nt':
allow_reuse_address = 0
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 def __init__(self, *args, **kargs):
BaseHTTPServer.HTTPServer.__init__(self, *args, **kargs)
self.accesslog = accesslog
self.errorlog = errorlog
Brendan Cully
Make hgweb threads into daemon threads....
r2650 self.daemon_threads = True
Alexis S. L. Carvalho
avoid wsgiapplication <-> MercurialHTTPServer circular reference
r4245 def make_handler():
if webdir_conf:
hgwebobj = hgwebdir(webdir_conf, ui)
elif repo is not None:
hgwebobj = hgweb(hg.repository(repo.ui, repo.root))
else:
Matt Mackall
error: move repo errors...
r7637 raise error.RepoError(_("There is no Mercurial repository"
" here (.hg not found)"))
Alexis S. L. Carvalho
avoid wsgiapplication <-> MercurialHTTPServer circular reference
r4245 return hgwebobj
Dirkjan Ochtman
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
r5566 self.application = make_handler()
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 if ssl_cert:
try:
from OpenSSL import SSL
ctx = SSL.Context(SSL.SSLv23_METHOD)
except ImportError:
Martin Geisler
i18n: mark strings for translation in Mercurial
r6953 raise util.Abort(_("SSL support is unavailable"))
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 ctx.use_privatekey_file(ssl_cert)
ctx.use_certificate_file(ssl_cert)
sock = socket.socket(self.address_family, self.socket_type)
self.socket = SSL.Connection(ctx, sock)
self.server_bind()
self.server_activate()
Stephen Deasey
hgweb: clarify which address and port can/cannot be bound at startup (bug 769)...
r6262 self.addr, self.port = self.socket.getsockname()[0:2]
self.prefix = prefix
self.fqaddr = socket.getfqdn(address)
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 class IPv6HTTPServer(MercurialHTTPServer):
address_family = getattr(socket, 'AF_INET6', None)
def __init__(self, *args, **kwargs):
if self.address_family is None:
Martin Geisler
hgweb: better English in IPv6 error message
r7928 raise error.RepoError(_('IPv6 is not available on this system'))
Eric Hopper
Fix two small bugs that would've prevented the web interface and IPv6...
r2507 super(IPv6HTTPServer, self).__init__(*args, **kwargs)
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 if ssl_cert:
handler = _shgwebhandler
else:
handler = _hgwebhandler
Dirkjan Ochtman
hgweb: pre-init mimetypes module (fixes ugly bug in python-2.6.2 mimetypes)...
r8224 # ugly hack due to python issue5853 (for threaded use)
import mimetypes; mimetypes.init()
Matt Mackall
hgweb: internalize some socket details
r3628 try:
if use_ipv6:
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 return IPv6HTTPServer((address, port), handler)
Matt Mackall
hgweb: internalize some socket details
r3628 else:
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 return MercurialHTTPServer((address, port), handler)
Matt Mackall
hgweb: internalize some socket details
r3628 except socket.error, inst:
Stephen Deasey
hgweb: clarify which address and port can/cannot be bound at startup (bug 769)...
r6262 raise util.Abort(_("cannot start server at '%s:%d': %s")
% (address, port, inst.args[1]))