summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLudovic Chabant <ludovic@chabant.com>2019-02-28 07:26:34 +0000
committerDrew DeVault <sir@cmpwn.com>2019-03-01 14:40:59 -0700
commit2761ac568844f593603196893d815deec2e758ab (patch)
treebfd0c7c16697d0dfc64f26e98bfaf173d2c4964e
parentf06d92f9cbe1563e19ac9c680a4a5efdcaf0aeb5 (diff)
Add debug server support for http cloning
-rw-r--r--run.py97
1 files changed, 95 insertions, 2 deletions
diff --git a/run.py b/run.py
index 1a4417d..a86e500 100644
--- a/run.py
+++ b/run.py
@@ -1,4 +1,97 @@
+import logging
+import os.path
+import re
+import subprocess
+from srht.config import cfg
+from werkzeug.exceptions import BadRequest
+from werkzeug.wrappers import Request, Response
+from werkzeug.wsgi import wrap_file
+
+def configure_git_arguments(parser):
+ parser.add_argument('--http-serve', action='store_true',
+ help="Also serve the Git repositories for HTTP cloning.")
+
+def configure_git_app(app, args):
+ if not args.http_serve:
+ return
+
+ gitreposdir = cfg('git.sr.ht', 'repos')
+ print("Serving git repos from {}".format(gitreposdir))
+ app.wsgi_app = HttpGitRepos(app.wsgi_app, gitreposdir)
+
+re_git1 = re.compile(
+ r"^.*/objects/([0-9a-f]+/[0-9a-f]+|pack/pack-[0-9a-f]+.(pack|idx)).*$")
+re_git2 = re.compile(
+ r"^.*/(HEAD|info/refs|objects/info/.*|git-(upload|receive)-pack).*$")
+
+logger = logging.getLogger('werkzeug')
+
+class HttpGitRepos:
+ def __init__(self, app, reposdir, ssl=None):
+ self._app = app
+ self._reposdir = reposdir
+ self._ssl = None
+
+ def __call__(self, environ, start_response):
+ request = Request(environ)
+
+ if re_git1.search(request.path):
+ path = os.path.join(self._reposdir, request.path.lstrip('/'))
+ if os.path.exists(path):
+ f = wrap_file(environ, open(path))
+ return Response(f, direct_passthrough=True)
+
+ if re_git2.search(request.path):
+ subenv = environ.copy()
+ for k in list(subenv.keys()):
+ if (k.startswith('wsgi') or k.startswith('werkzeug') or
+ type(subenv[k]) is not str):
+ del subenv[k]
+
+ subenv['GIT_PROJECT_ROOT'] = self._reposdir
+ subenv['GIT_HTTP_EXPORT_ALL'] = "1"
+ p = subprocess.Popen(['git', 'http-backend'],
+ cwd=self._reposdir, env=subenv, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ try:
+ stdin = request.data
+ stdout, stderr = p.communicate(input=stdin, timeout=30)
+ except subprocess.TimeoutExpired:
+ logger.warning("Git HTTP backend timed out:")
+ logger.warning(stderr.decode())
+ return BadRequest()(environ, start_response)
+
+ sep = stdout.find(b'\r\n\r\n')
+ headers = []
+ body_start = 0
+ if sep > 0:
+ body_start = sep + 4
+ raw_headers = stdout[:sep].decode()
+ for i, line in enumerate(raw_headers.split('\r\n')):
+ sepidx = line.find(':')
+ if sepidx > 0:
+ headers.append((line[:sepidx], line[sepidx+1:].lstrip()))
+ else:
+ logger.warning("Skipping malformed header: %s" % line)
+
+ if stderr:
+ logger.warning("Errors while serving Git repo:")
+ logger.warning(stderr.decode())
+ body = stdout[body_start:]
+ r = Response(body, headers=headers)
+ return r(environ, start_response)
+
+ return self._app(environ, start_response)
+
if __name__ == '__main__':
- from srht.debug import run_service
+ from srht.debug import configure_static_folder, configure_static_serving
+ from srht.debug import configure_static_arguments, build_parser, run_app
from gitsrht.app import app
- run_service(app)
+ configure_static_folder(app)
+ parser = build_parser(app)
+ configure_static_arguments(parser)
+ configure_git_arguments(parser)
+ args = parser.parse_args()
+ configure_static_serving(app, args)
+ configure_git_app(app, args)
+ run_app(app)