--- a/mercurial/hgweb/server.py Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/hgweb/server.py Sun Oct 06 09:45:02 2019 -0400
@@ -30,9 +30,8 @@
urlerr = util.urlerr
urlreq = util.urlreq
-from . import (
- common,
-)
+from . import common
+
def _splitURI(uri):
"""Return path and query that has been split from uri
@@ -46,17 +45,22 @@
path, query = uri, r''
return urlreq.unquote(path), query
+
class _error_logger(object):
def __init__(self, handler):
self.handler = handler
+
def flush(self):
pass
+
def write(self, str):
self.writelines(str.split('\n'))
+
def writelines(self, seq):
for msg in seq:
self.handler.log_error(r"HG error: %s", encoding.strfromlocal(msg))
+
class _httprequesthandler(httpservermod.basehttprequesthandler):
url_scheme = 'http'
@@ -70,10 +74,17 @@
httpservermod.basehttprequesthandler.__init__(self, *args, **kargs)
def _log_any(self, fp, format, *args):
- fp.write(pycompat.sysbytes(
- r"%s - - [%s] %s" % (self.client_address[0],
- self.log_date_time_string(),
- format % args)) + '\n')
+ fp.write(
+ pycompat.sysbytes(
+ r"%s - - [%s] %s"
+ % (
+ self.client_address[0],
+ self.log_date_time_string(),
+ format % args,
+ )
+ )
+ + '\n'
+ )
fp.flush()
def log_error(self, format, *args):
@@ -85,11 +96,16 @@
def log_request(self, code=r'-', size=r'-'):
xheaders = []
if util.safehasattr(self, 'headers'):
- xheaders = [h for h in self.headers.items()
- if h[0].startswith(r'x-')]
- self.log_message(r'"%s" %s %s%s',
- self.requestline, str(code), str(size),
- r''.join([r' %s:%s' % h for h in sorted(xheaders)]))
+ xheaders = [
+ h for h in self.headers.items() if h[0].startswith(r'x-')
+ ]
+ self.log_message(
+ r'"%s" %s %s%s',
+ self.requestline,
+ str(code),
+ str(size),
+ r''.join([r' %s:%s' % h for h in sorted(xheaders)]),
+ )
def do_write(self):
try:
@@ -104,15 +120,22 @@
except Exception as e:
# I/O below could raise another exception. So log the original
# exception first to ensure it is recorded.
- if not (isinstance(e, (OSError, socket.error))
- and e.errno == errno.ECONNRESET):
+ if not (
+ isinstance(e, (OSError, socket.error))
+ and e.errno == errno.ECONNRESET
+ ):
tb = r"".join(traceback.format_exception(*sys.exc_info()))
# We need a native-string newline to poke in the log
# message, because we won't get a newline when using an
# r-string. This is the easy way out.
newline = chr(10)
- self.log_error(r"Exception happened during processing "
- r"request '%s':%s%s", self.path, newline, tb)
+ self.log_error(
+ r"Exception happened during processing "
+ r"request '%s':%s%s",
+ self.path,
+ newline,
+ tb,
+ )
self._start_response(r"500 Internal Server Error", [])
self._write(b"Internal Server Error")
@@ -129,10 +152,10 @@
path, query = _splitURI(self.path)
# Ensure the slicing of path below is valid
- if (path != self.server.prefix
- and not path.startswith(self.server.prefix + b'/')):
- self._start_response(pycompat.strurl(common.statusmessage(404)),
- [])
+ if path != self.server.prefix and not path.startswith(
+ self.server.prefix + b'/'
+ ):
+ self._start_response(pycompat.strurl(common.statusmessage(404)), [])
if self.command == 'POST':
# Paranoia: tell the client we're going to close the
# socket so they don't try and reuse a socket that
@@ -151,7 +174,7 @@
env[r'SERVER_PORT'] = str(self.server.server_port)
env[r'REQUEST_URI'] = self.path
env[r'SCRIPT_NAME'] = pycompat.sysstr(self.server.prefix)
- env[r'PATH_INFO'] = pycompat.sysstr(path[len(self.server.prefix):])
+ env[r'PATH_INFO'] = pycompat.sysstr(path[len(self.server.prefix) :])
env[r'REMOTE_HOST'] = self.client_address[0]
env[r'REMOTE_ADDR'] = self.client_address[0]
env[r'QUERY_STRING'] = query or r''
@@ -170,8 +193,11 @@
length = self.headers.getheader(r'content-length')
if length:
env[r'CONTENT_LENGTH'] = length
- for header in [h for h in self.headers.keys()
- if h.lower() not in (r'content-type', r'content-length')]:
+ for header in [
+ h
+ for h in self.headers.keys()
+ if h.lower() not in (r'content-type', r'content-length')
+ ]:
hkey = r'HTTP_' + header.replace(r'-', r'_').upper()
hval = self.headers.get(header)
hval = hval.replace(r'\n', r'').strip()
@@ -185,11 +211,13 @@
env[r'wsgi.input'] = self.rfile
env[r'wsgi.errors'] = _error_logger(self)
- env[r'wsgi.multithread'] = isinstance(self.server,
- socketserver.ThreadingMixIn)
+ env[r'wsgi.multithread'] = isinstance(
+ self.server, socketserver.ThreadingMixIn
+ )
if util.safehasattr(socketserver, 'ForkingMixIn'):
- env[r'wsgi.multiprocess'] = isinstance(self.server,
- socketserver.ForkingMixIn)
+ env[r'wsgi.multiprocess'] = isinstance(
+ self.server, socketserver.ForkingMixIn
+ )
else:
env[r'wsgi.multiprocess'] = False
@@ -209,8 +237,9 @@
def send_headers(self):
if not self.saved_status:
- raise AssertionError("Sending headers before "
- "start_response() called")
+ raise AssertionError(
+ "Sending headers before " "start_response() called"
+ )
saved_status = self.saved_status.split(None, 1)
saved_status[0] = int(saved_status[0])
self.send_response(*saved_status)
@@ -220,10 +249,11 @@
self.send_header(*h)
if h[0].lower() == r'content-length':
self.length = int(h[1])
- if (self.length is None and
- saved_status[0] != common.HTTP_NOT_MODIFIED):
- self._chunked = (not self.close_connection and
- self.request_version == r'HTTP/1.1')
+ if self.length is None and saved_status[0] != common.HTTP_NOT_MODIFIED:
+ self._chunked = (
+ not self.close_connection
+ and self.request_version == r'HTTP/1.1'
+ )
if self._chunked:
self.send_header(r'Transfer-Encoding', r'chunked')
else:
@@ -237,8 +267,9 @@
code = int(code)
self.saved_status = http_status
bad_headers = (r'connection', r'transfer-encoding')
- self.saved_headers = [h for h in headers
- if h[0].lower() not in bad_headers]
+ self.saved_headers = [
+ h for h in headers if h[0].lower() not in bad_headers
+ ]
return self._write
def _write(self, data):
@@ -248,8 +279,10 @@
self.send_headers()
if self.length is not None:
if len(data) > self.length:
- raise AssertionError("Content-length header sent, but more "
- "bytes than specified are being written.")
+ raise AssertionError(
+ "Content-length header sent, but more "
+ "bytes than specified are being written."
+ )
self.length = self.length - len(data)
elif self._chunked and data:
data = '%x\r\n%s\r\n' % (len(data), data)
@@ -266,6 +299,7 @@
return encoding.strfromlocal(self.server.serverheader)
return httpservermod.basehttprequesthandler.version_string(self)
+
class _httprequesthandlerssl(_httprequesthandler):
"""HTTPS handler based on Python's ssl module"""
@@ -275,6 +309,7 @@
def preparehttpserver(httpserver, ui):
try:
from .. import sslutil
+
sslutil.modernssl
except ImportError:
raise error.Abort(_("SSL support is unavailable"))
@@ -286,33 +321,40 @@
cafile = ui.config('devel', 'servercafile')
reqcert = ui.configbool('devel', 'serverrequirecert')
- httpserver.socket = sslutil.wrapserversocket(httpserver.socket,
- ui,
- certfile=certfile,
- cafile=cafile,
- requireclientcert=reqcert)
+ httpserver.socket = sslutil.wrapserversocket(
+ httpserver.socket,
+ ui,
+ certfile=certfile,
+ cafile=cafile,
+ requireclientcert=reqcert,
+ )
def setup(self):
self.connection = self.request
self.rfile = self.request.makefile(r"rb", self.rbufsize)
self.wfile = self.request.makefile(r"wb", self.wbufsize)
+
try:
import threading
- threading.activeCount() # silence pyflakes and bypass demandimport
+
+ threading.activeCount() # silence pyflakes and bypass demandimport
_mixin = socketserver.ThreadingMixIn
except ImportError:
if util.safehasattr(os, "fork"):
_mixin = socketserver.ForkingMixIn
else:
+
class _mixin(object):
pass
+
def openlog(opt, default):
if opt and opt != '-':
return open(opt, 'ab')
return default
+
class MercurialHTTPServer(_mixin, httpservermod.httpserver, object):
# SO_REUSEADDR has broken semantics on windows
@@ -341,13 +383,16 @@
self.serverheader = ui.config('web', 'server-header')
+
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)
+
def create_server(ui, app):
if ui.config('web', 'certificate'):
@@ -363,6 +408,7 @@
# ugly hack due to python issue5853 (for threaded use)
try:
import mimetypes
+
mimetypes.init()
except UnicodeDecodeError:
# Python 2.x's mimetypes module attempts to decode strings
@@ -370,14 +416,14 @@
# as ascii (clown fail), because the default Python Unicode
# codec is hardcoded as ascii.
- sys.argv # unwrap demand-loader so that reload() works
+ sys.argv # unwrap demand-loader so that reload() works
# resurrect sys.setdefaultencoding()
try:
importlib.reload(sys)
except AttributeError:
reload(sys)
oldenc = sys.getdefaultencoding()
- sys.setdefaultencoding("latin1") # or any full 8-bit encoding
+ sys.setdefaultencoding("latin1") # or any full 8-bit encoding
mimetypes.init()
sys.setdefaultencoding(oldenc)
@@ -386,5 +432,7 @@
try:
return cls(ui, app, (address, port), handler)
except socket.error as inst:
- raise error.Abort(_("cannot start server at '%s:%d': %s")
- % (address, port, encoding.strtolocal(inst.args[1])))
+ raise error.Abort(
+ _("cannot start server at '%s:%d': %s")
+ % (address, port, encoding.strtolocal(inst.args[1]))
+ )