Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/hgweb/server.py @ 2355:eb08fb4d41e1
Splitting up hgweb so it's easier to change.
author | Eric Hopper <hopper@omnifarious.org> |
---|---|
date | Wed, 31 May 2006 08:03:29 -0700 |
parents | mercurial/hgweb/__init__.py@f789602ba840 |
children | d351a3be3371 |
comparison
equal
deleted
inserted
replaced
2352:61909dfb316d | 2355:eb08fb4d41e1 |
---|---|
1 # hgweb.py - web interface to a mercurial repository | |
2 # | |
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
4 # Copyright 2005 Matt Mackall <mpm@selenic.com> | |
5 # | |
6 # This software may be used and distributed according to the terms | |
7 # of the GNU General Public License, incorporated herein by reference. | |
8 | |
9 from mercurial.demandload import demandload | |
10 import os, sys, errno | |
11 demandload(globals(), "urllib BaseHTTPServer socket SocketServer") | |
12 demandload(globals(), "mercurial:ui,hg,util,templater") | |
13 demandload(globals(), "mercurial.hgweb.request:hgrequest") | |
14 from mercurial.i18n import gettext as _ | |
15 | |
16 def _splitURI(uri): | |
17 """ Return path and query splited from uri | |
18 | |
19 Just like CGI environment, the path is unquoted, the query is | |
20 not. | |
21 """ | |
22 if '?' in uri: | |
23 path, query = uri.split('?', 1) | |
24 else: | |
25 path, query = uri, '' | |
26 return urllib.unquote(path), query | |
27 | |
28 class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler): | |
29 def __init__(self, *args, **kargs): | |
30 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs) | |
31 | |
32 def log_error(self, format, *args): | |
33 errorlog = self.server.errorlog | |
34 errorlog.write("%s - - [%s] %s\n" % (self.address_string(), | |
35 self.log_date_time_string(), | |
36 format % args)) | |
37 | |
38 def log_message(self, format, *args): | |
39 accesslog = self.server.accesslog | |
40 accesslog.write("%s - - [%s] %s\n" % (self.address_string(), | |
41 self.log_date_time_string(), | |
42 format % args)) | |
43 | |
44 def do_POST(self): | |
45 try: | |
46 self.do_hgweb() | |
47 except socket.error, inst: | |
48 if inst[0] != errno.EPIPE: | |
49 raise | |
50 | |
51 def do_GET(self): | |
52 self.do_POST() | |
53 | |
54 def do_hgweb(self): | |
55 path_info, query = _splitURI(self.path) | |
56 | |
57 env = {} | |
58 env['GATEWAY_INTERFACE'] = 'CGI/1.1' | |
59 env['REQUEST_METHOD'] = self.command | |
60 env['SERVER_NAME'] = self.server.server_name | |
61 env['SERVER_PORT'] = str(self.server.server_port) | |
62 env['REQUEST_URI'] = "/" | |
63 env['PATH_INFO'] = path_info | |
64 if query: | |
65 env['QUERY_STRING'] = query | |
66 host = self.address_string() | |
67 if host != self.client_address[0]: | |
68 env['REMOTE_HOST'] = host | |
69 env['REMOTE_ADDR'] = self.client_address[0] | |
70 | |
71 if self.headers.typeheader is None: | |
72 env['CONTENT_TYPE'] = self.headers.type | |
73 else: | |
74 env['CONTENT_TYPE'] = self.headers.typeheader | |
75 length = self.headers.getheader('content-length') | |
76 if length: | |
77 env['CONTENT_LENGTH'] = length | |
78 accept = [] | |
79 for line in self.headers.getallmatchingheaders('accept'): | |
80 if line[:1] in "\t\n\r ": | |
81 accept.append(line.strip()) | |
82 else: | |
83 accept = accept + line[7:].split(',') | |
84 env['HTTP_ACCEPT'] = ','.join(accept) | |
85 | |
86 req = hgrequest(self.rfile, self.wfile, env) | |
87 self.send_response(200, "Script output follows") | |
88 self.server.make_and_run_handler(req) | |
89 | |
90 def create_server(ui, repo, webdirmaker, repoviewmaker): | |
91 use_threads = True | |
92 | |
93 def openlog(opt, default): | |
94 if opt and opt != '-': | |
95 return open(opt, 'w') | |
96 return default | |
97 | |
98 address = ui.config("web", "address", "") | |
99 port = int(ui.config("web", "port", 8000)) | |
100 use_ipv6 = ui.configbool("web", "ipv6") | |
101 webdir_conf = ui.config("web", "webdir_conf") | |
102 accesslog = openlog(ui.config("web", "accesslog", "-"), sys.stdout) | |
103 errorlog = openlog(ui.config("web", "errorlog", "-"), sys.stderr) | |
104 | |
105 if use_threads: | |
106 try: | |
107 from threading import activeCount | |
108 except ImportError: | |
109 use_threads = False | |
110 | |
111 if use_threads: | |
112 _mixin = SocketServer.ThreadingMixIn | |
113 else: | |
114 if hasattr(os, "fork"): | |
115 _mixin = SocketServer.ForkingMixIn | |
116 else: | |
117 class _mixin: pass | |
118 | |
119 class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer): | |
120 def __init__(self, *args, **kargs): | |
121 BaseHTTPServer.HTTPServer.__init__(self, *args, **kargs) | |
122 self.accesslog = accesslog | |
123 self.errorlog = errorlog | |
124 self.repo = repo | |
125 self.webdir_conf = webdir_conf | |
126 self.webdirmaker = webdirmaker | |
127 self.repoviewmaker = repoviewmaker | |
128 | |
129 def make_and_run_handler(self, req): | |
130 if self.webdir_conf: | |
131 hgwebobj = self.webdirmaker(self.server.webdir_conf) | |
132 elif self.repo is not None: | |
133 hgwebobj = self.repoviewmaker(repo.__class__(repo.ui, | |
134 repo.origroot)) | |
135 else: | |
136 raise hg.RepoError(_('no repo found')) | |
137 hgwebobj.run(req) | |
138 | |
139 class IPv6HTTPServer(MercurialHTTPServer): | |
140 address_family = getattr(socket, 'AF_INET6', None) | |
141 | |
142 def __init__(self, *args, **kwargs): | |
143 if self.address_family is None: | |
144 raise hg.RepoError(_('IPv6 not available on this system')) | |
145 super(IPv6HTTPServer, self).__init__(*args, **kargs) | |
146 | |
147 if use_ipv6: | |
148 return IPv6HTTPServer((address, port), _hgwebhandler) | |
149 else: | |
150 return MercurialHTTPServer((address, port), _hgwebhandler) |