##// END OF EJS Templates
merge default into stable for 1.8 code freeze
merge default into stable for 1.8 code freeze

File last commit:

r12797:076bbbf0 stable
r13427:2432b322 merge stable
Show More
server.py
309 lines | 10.7 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
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
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
Nicolas Dumazet
pylint, pyflakes: remove unused or duplicate imports
r10905 from mercurial import util, error
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)
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 class _httprequesthandler(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
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 @staticmethod
def preparehttpserver(httpserver, ssl_cert):
"""Prepare .socket of new HTTPServer instance"""
pass
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
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 class _httprequesthandleropenssl(_httprequesthandler):
"""HTTPS handler based on pyOpenSSL"""
Wesley J. Landaker
Make hg serve set the wsgi.url_scheme property correctly....
r4870
url_scheme = 'https'
Thomas Arendsen Hein
removed trailing whitespace
r4957
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 @staticmethod
def preparehttpserver(httpserver, ssl_cert):
try:
import OpenSSL
OpenSSL.SSL.Context
except ImportError:
raise util.Abort(_("SSL support is unavailable"))
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
ctx.use_privatekey_file(ssl_cert)
ctx.use_certificate_file(ssl_cert)
sock = socket.socket(httpserver.address_family, httpserver.socket_type)
httpserver.socket = OpenSSL.SSL.Connection(ctx, sock)
httpserver.server_bind()
httpserver.server_activate()
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):
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 import OpenSSL
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 try:
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 _httprequesthandler.do_write(self)
except OpenSSL.SSL.SysCallError, inst:
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 if inst.args[0] != errno.EPIPE:
raise
def handle_one_request(self):
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 import OpenSSL
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 try:
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 _httprequesthandler.handle_one_request(self)
except (OpenSSL.SSL.SysCallError, OpenSSL.SSL.ZeroReturnError):
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 self.close_connection = True
pass
Mads Kiilerich
hgweb: use Pythons ssl module for HTTPS serve when using Python 2.6 or later...
r12784 class _httprequesthandlerssl(_httprequesthandler):
"""HTTPS handler based on Pythons ssl module (introduced in 2.6)"""
url_scheme = 'https'
@staticmethod
def preparehttpserver(httpserver, ssl_cert):
try:
import ssl
ssl.wrap_socket
except ImportError:
raise util.Abort(_("SSL support is unavailable"))
httpserver.socket = ssl.wrap_socket(httpserver.socket, server_side=True,
Mads Kiilerich
hgweb: let HTTPS serve use more compatible and less secure encryption...
r12797 certfile=ssl_cert, ssl_version=ssl.PROTOCOL_SSLv23)
Mads Kiilerich
hgweb: use Pythons ssl module for HTTPS serve when using Python 2.6 or later...
r12784
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)
Dirkjan Ochtman
server: externalize and streamline mixin setup
r10639 try:
from threading import activeCount
_mixin = SocketServer.ThreadingMixIn
except ImportError:
if hasattr(os, "fork"):
_mixin = SocketServer.ForkingMixIn
else:
class _mixin:
pass
Dirkjan Ochtman
server: unnest server classes into module namespace
r10643 def openlog(opt, default):
if opt and opt != '-':
return open(opt, 'a')
return default
class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer):
# SO_REUSEADDR has broken semantics on windows
if os.name == 'nt':
allow_reuse_address = 0
def __init__(self, ui, app, addr, handler, **kwargs):
BaseHTTPServer.HTTPServer.__init__(self, addr, handler, **kwargs)
self.daemon_threads = True
self.application = app
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 handler.preparehttpserver(self, ui.config('web', 'certificate'))
Dirkjan Ochtman
server: unnest server classes into module namespace
r10643
prefix = ui.config('web', 'prefix', '')
if prefix:
prefix = '/' + prefix.strip('/')
self.prefix = prefix
alog = openlog(ui.config('web', 'accesslog', '-'), sys.stdout)
elog = openlog(ui.config('web', 'errorlog', '-'), sys.stderr)
self.accesslog = alog
self.errorlog = elog
self.addr, self.port = self.socket.getsockname()[0:2]
self.fqaddr = socket.getfqdn(addr[0])
class IPv6HTTPServer(MercurialHTTPServer):
address_family = getattr(socket, 'AF_INET6', None)
def __init__(self, *args, **kwargs):
if self.address_family is None:
raise error.RepoError(_('IPv6 is not available on this system'))
super(IPv6HTTPServer, self).__init__(*args, **kwargs)
Dirkjan Ochtman
server: initialize wsgi app in command, then wrap server around it
r10644 def create_server(ui, app):
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Dirkjan Ochtman
server: initialize wsgi app in command, then wrap server around it
r10644 if ui.config('web', 'certificate'):
Mads Kiilerich
hgweb: use Pythons ssl module for HTTPS serve when using Python 2.6 or later...
r12784 if sys.version_info >= (2, 6):
handler = _httprequesthandlerssl
else:
handler = _httprequesthandleropenssl
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860 else:
Mads Kiilerich
hgweb: refactor all pyOpenSSL references into one class
r12783 handler = _httprequesthandler
Brendan Cully
Add SSL support to hg serve, activated via --certificate option
r4860
Dirkjan Ochtman
server: initialize wsgi app in command, then wrap server around it
r10644 if ui.configbool('web', 'ipv6'):
Dirkjan Ochtman
server: abstract setup of ipv6 vs. normal server
r10641 cls = IPv6HTTPServer
else:
cls = MercurialHTTPServer
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()
Dirkjan Ochtman
server: initialize wsgi app in command, then wrap server around it
r10644 address = ui.config('web', 'address', '')
Brodie Rao
mail/hgweb: support service names for ports (issue2350)...
r12076 port = util.getport(ui.config('web', 'port', 8000))
Matt Mackall
hgweb: internalize some socket details
r3628 try:
Dirkjan Ochtman
server: initialize wsgi app in command, then wrap server around it
r10644 return cls(ui, app, (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]))