##// END OF EJS Templates
hgweb: remove dead code
Benoit Boissinot -
r6403:f615ece5 default
parent child Browse files
Show More
@@ -1,298 +1,293 b''
1 # hgweb/server.py - The standalone hg web server.
1 # hgweb/server.py - The standalone hg web server.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 import os, sys, errno, urllib, BaseHTTPServer, socket, SocketServer, traceback
9 import os, sys, errno, urllib, BaseHTTPServer, socket, SocketServer, traceback
10 from mercurial import hg, util
10 from mercurial import hg, util
11 from mercurial.repo import RepoError
11 from mercurial.repo import RepoError
12 from hgweb_mod import hgweb
12 from hgweb_mod import hgweb
13 from hgwebdir_mod import hgwebdir
13 from hgwebdir_mod import hgwebdir
14 from mercurial.i18n import gettext as _
14 from mercurial.i18n import gettext as _
15
15
16 def _splitURI(uri):
16 def _splitURI(uri):
17 """ Return path and query splited from uri
17 """ Return path and query splited from uri
18
18
19 Just like CGI environment, the path is unquoted, the query is
19 Just like CGI environment, the path is unquoted, the query is
20 not.
20 not.
21 """
21 """
22 if '?' in uri:
22 if '?' in uri:
23 path, query = uri.split('?', 1)
23 path, query = uri.split('?', 1)
24 else:
24 else:
25 path, query = uri, ''
25 path, query = uri, ''
26 return urllib.unquote(path), query
26 return urllib.unquote(path), query
27
27
28 class _error_logger(object):
28 class _error_logger(object):
29 def __init__(self, handler):
29 def __init__(self, handler):
30 self.handler = handler
30 self.handler = handler
31 def flush(self):
31 def flush(self):
32 pass
32 pass
33 def write(self, str):
33 def write(self, str):
34 self.writelines(str.split('\n'))
34 self.writelines(str.split('\n'))
35 def writelines(self, seq):
35 def writelines(self, seq):
36 for msg in seq:
36 for msg in seq:
37 self.handler.log_error("HG error: %s", msg)
37 self.handler.log_error("HG error: %s", msg)
38
38
39 class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler):
39 class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler):
40
40
41 url_scheme = 'http'
41 url_scheme = 'http'
42
42
43 def __init__(self, *args, **kargs):
43 def __init__(self, *args, **kargs):
44 self.protocol_version = 'HTTP/1.1'
44 self.protocol_version = 'HTTP/1.1'
45 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs)
45 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs)
46
46
47 def _log_any(self, fp, format, *args):
47 def _log_any(self, fp, format, *args):
48 fp.write("%s - - [%s] %s\n" % (self.client_address[0],
48 fp.write("%s - - [%s] %s\n" % (self.client_address[0],
49 self.log_date_time_string(),
49 self.log_date_time_string(),
50 format % args))
50 format % args))
51 fp.flush()
51 fp.flush()
52
52
53 def log_error(self, format, *args):
53 def log_error(self, format, *args):
54 self._log_any(self.server.errorlog, format, *args)
54 self._log_any(self.server.errorlog, format, *args)
55
55
56 def log_message(self, format, *args):
56 def log_message(self, format, *args):
57 self._log_any(self.server.accesslog, format, *args)
57 self._log_any(self.server.accesslog, format, *args)
58
58
59 def do_write(self):
59 def do_write(self):
60 try:
60 try:
61 self.do_hgweb()
61 self.do_hgweb()
62 except socket.error, inst:
62 except socket.error, inst:
63 if inst[0] != errno.EPIPE:
63 if inst[0] != errno.EPIPE:
64 raise
64 raise
65
65
66 def do_POST(self):
66 def do_POST(self):
67 try:
67 try:
68 self.do_write()
68 self.do_write()
69 except StandardError, inst:
69 except StandardError, inst:
70 self._start_response("500 Internal Server Error", [])
70 self._start_response("500 Internal Server Error", [])
71 self._write("Internal Server Error")
71 self._write("Internal Server Error")
72 tb = "".join(traceback.format_exception(*sys.exc_info()))
72 tb = "".join(traceback.format_exception(*sys.exc_info()))
73 self.log_error("Exception happened during processing request '%s':\n%s",
73 self.log_error("Exception happened during processing request '%s':\n%s",
74 self.path, tb)
74 self.path, tb)
75
75
76 def do_GET(self):
76 def do_GET(self):
77 self.do_POST()
77 self.do_POST()
78
78
79 def do_hgweb(self):
79 def do_hgweb(self):
80 path, query = _splitURI(self.path)
80 path, query = _splitURI(self.path)
81
81
82 env = {}
82 env = {}
83 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
83 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
84 env['REQUEST_METHOD'] = self.command
84 env['REQUEST_METHOD'] = self.command
85 env['SERVER_NAME'] = self.server.server_name
85 env['SERVER_NAME'] = self.server.server_name
86 env['SERVER_PORT'] = str(self.server.server_port)
86 env['SERVER_PORT'] = str(self.server.server_port)
87 env['REQUEST_URI'] = self.path
87 env['REQUEST_URI'] = self.path
88 env['SCRIPT_NAME'] = self.server.prefix
88 env['SCRIPT_NAME'] = self.server.prefix
89 env['PATH_INFO'] = path[len(self.server.prefix):]
89 env['PATH_INFO'] = path[len(self.server.prefix):]
90 env['REMOTE_HOST'] = self.client_address[0]
90 env['REMOTE_HOST'] = self.client_address[0]
91 env['REMOTE_ADDR'] = self.client_address[0]
91 env['REMOTE_ADDR'] = self.client_address[0]
92 if query:
92 if query:
93 env['QUERY_STRING'] = query
93 env['QUERY_STRING'] = query
94
94
95 if self.headers.typeheader is None:
95 if self.headers.typeheader is None:
96 env['CONTENT_TYPE'] = self.headers.type
96 env['CONTENT_TYPE'] = self.headers.type
97 else:
97 else:
98 env['CONTENT_TYPE'] = self.headers.typeheader
98 env['CONTENT_TYPE'] = self.headers.typeheader
99 length = self.headers.getheader('content-length')
99 length = self.headers.getheader('content-length')
100 if length:
100 if length:
101 env['CONTENT_LENGTH'] = length
101 env['CONTENT_LENGTH'] = length
102 for header in [h for h in self.headers.keys()
102 for header in [h for h in self.headers.keys()
103 if h not in ('content-type', 'content-length')]:
103 if h not in ('content-type', 'content-length')]:
104 hkey = 'HTTP_' + header.replace('-', '_').upper()
104 hkey = 'HTTP_' + header.replace('-', '_').upper()
105 hval = self.headers.getheader(header)
105 hval = self.headers.getheader(header)
106 hval = hval.replace('\n', '').strip()
106 hval = hval.replace('\n', '').strip()
107 if hval:
107 if hval:
108 env[hkey] = hval
108 env[hkey] = hval
109 env['SERVER_PROTOCOL'] = self.request_version
109 env['SERVER_PROTOCOL'] = self.request_version
110 env['wsgi.version'] = (1, 0)
110 env['wsgi.version'] = (1, 0)
111 env['wsgi.url_scheme'] = self.url_scheme
111 env['wsgi.url_scheme'] = self.url_scheme
112 env['wsgi.input'] = self.rfile
112 env['wsgi.input'] = self.rfile
113 env['wsgi.errors'] = _error_logger(self)
113 env['wsgi.errors'] = _error_logger(self)
114 env['wsgi.multithread'] = isinstance(self.server,
114 env['wsgi.multithread'] = isinstance(self.server,
115 SocketServer.ThreadingMixIn)
115 SocketServer.ThreadingMixIn)
116 env['wsgi.multiprocess'] = isinstance(self.server,
116 env['wsgi.multiprocess'] = isinstance(self.server,
117 SocketServer.ForkingMixIn)
117 SocketServer.ForkingMixIn)
118 env['wsgi.run_once'] = 0
118 env['wsgi.run_once'] = 0
119
119
120 self.close_connection = True
120 self.close_connection = True
121 self.saved_status = None
121 self.saved_status = None
122 self.saved_headers = []
122 self.saved_headers = []
123 self.sent_headers = False
123 self.sent_headers = False
124 self.length = None
124 self.length = None
125 self.server.application(env, self._start_response)
125 self.server.application(env, self._start_response)
126
126
127 def send_headers(self):
127 def send_headers(self):
128 if not self.saved_status:
128 if not self.saved_status:
129 raise AssertionError("Sending headers before start_response() called")
129 raise AssertionError("Sending headers before start_response() called")
130 saved_status = self.saved_status.split(None, 1)
130 saved_status = self.saved_status.split(None, 1)
131 saved_status[0] = int(saved_status[0])
131 saved_status[0] = int(saved_status[0])
132 self.send_response(*saved_status)
132 self.send_response(*saved_status)
133 should_close = True
133 should_close = True
134 for h in self.saved_headers:
134 for h in self.saved_headers:
135 self.send_header(*h)
135 self.send_header(*h)
136 if h[0].lower() == 'content-length':
136 if h[0].lower() == 'content-length':
137 should_close = False
137 should_close = False
138 self.length = int(h[1])
138 self.length = int(h[1])
139 # The value of the Connection header is a list of case-insensitive
139 # The value of the Connection header is a list of case-insensitive
140 # tokens separated by commas and optional whitespace.
140 # tokens separated by commas and optional whitespace.
141 if 'close' in [token.strip().lower() for token in
141 if 'close' in [token.strip().lower() for token in
142 self.headers.get('connection', '').split(',')]:
142 self.headers.get('connection', '').split(',')]:
143 should_close = True
143 should_close = True
144 if should_close:
144 if should_close:
145 self.send_header('Connection', 'close')
145 self.send_header('Connection', 'close')
146 self.close_connection = should_close
146 self.close_connection = should_close
147 self.end_headers()
147 self.end_headers()
148 self.sent_headers = True
148 self.sent_headers = True
149
149
150 def _start_response(self, http_status, headers, exc_info=None):
150 def _start_response(self, http_status, headers, exc_info=None):
151 code, msg = http_status.split(None, 1)
151 code, msg = http_status.split(None, 1)
152 code = int(code)
152 code = int(code)
153 self.saved_status = http_status
153 self.saved_status = http_status
154 bad_headers = ('connection', 'transfer-encoding')
154 bad_headers = ('connection', 'transfer-encoding')
155 self.saved_headers = [h for h in headers
155 self.saved_headers = [h for h in headers
156 if h[0].lower() not in bad_headers]
156 if h[0].lower() not in bad_headers]
157 return self._write
157 return self._write
158
158
159 def _write(self, data):
159 def _write(self, data):
160 if not self.saved_status:
160 if not self.saved_status:
161 raise AssertionError("data written before start_response() called")
161 raise AssertionError("data written before start_response() called")
162 elif not self.sent_headers:
162 elif not self.sent_headers:
163 self.send_headers()
163 self.send_headers()
164 if self.length is not None:
164 if self.length is not None:
165 if len(data) > self.length:
165 if len(data) > self.length:
166 raise AssertionError("Content-length header sent, but more bytes than specified are being written.")
166 raise AssertionError("Content-length header sent, but more bytes than specified are being written.")
167 self.length = self.length - len(data)
167 self.length = self.length - len(data)
168 self.wfile.write(data)
168 self.wfile.write(data)
169 self.wfile.flush()
169 self.wfile.flush()
170
170
171 class _shgwebhandler(_hgwebhandler):
171 class _shgwebhandler(_hgwebhandler):
172
172
173 url_scheme = 'https'
173 url_scheme = 'https'
174
174
175 def setup(self):
175 def setup(self):
176 self.connection = self.request
176 self.connection = self.request
177 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
177 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
178 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
178 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
179
179
180 def do_write(self):
180 def do_write(self):
181 from OpenSSL.SSL import SysCallError
181 from OpenSSL.SSL import SysCallError
182 try:
182 try:
183 super(_shgwebhandler, self).do_write()
183 super(_shgwebhandler, self).do_write()
184 except SysCallError, inst:
184 except SysCallError, inst:
185 if inst.args[0] != errno.EPIPE:
185 if inst.args[0] != errno.EPIPE:
186 raise
186 raise
187
187
188 def handle_one_request(self):
188 def handle_one_request(self):
189 from OpenSSL.SSL import SysCallError, ZeroReturnError
189 from OpenSSL.SSL import SysCallError, ZeroReturnError
190 try:
190 try:
191 super(_shgwebhandler, self).handle_one_request()
191 super(_shgwebhandler, self).handle_one_request()
192 except (SysCallError, ZeroReturnError):
192 except (SysCallError, ZeroReturnError):
193 self.close_connection = True
193 self.close_connection = True
194 pass
194 pass
195
195
196 def create_server(ui, repo):
196 def create_server(ui, repo):
197 use_threads = True
197 use_threads = True
198
198
199 def openlog(opt, default):
199 def openlog(opt, default):
200 if opt and opt != '-':
200 if opt and opt != '-':
201 return open(opt, 'a')
201 return open(opt, 'a')
202 return default
202 return default
203
203
204 if repo is None:
204 if repo is None:
205 myui = ui
205 myui = ui
206 else:
206 else:
207 myui = repo.ui
207 myui = repo.ui
208 address = myui.config("web", "address", "")
208 address = myui.config("web", "address", "")
209 port = int(myui.config("web", "port", 8000))
209 port = int(myui.config("web", "port", 8000))
210 prefix = myui.config("web", "prefix", "")
210 prefix = myui.config("web", "prefix", "")
211 if prefix:
211 if prefix:
212 prefix = "/" + prefix.strip("/")
212 prefix = "/" + prefix.strip("/")
213 use_ipv6 = myui.configbool("web", "ipv6")
213 use_ipv6 = myui.configbool("web", "ipv6")
214 webdir_conf = myui.config("web", "webdir_conf")
214 webdir_conf = myui.config("web", "webdir_conf")
215 ssl_cert = myui.config("web", "certificate")
215 ssl_cert = myui.config("web", "certificate")
216 accesslog = openlog(myui.config("web", "accesslog", "-"), sys.stdout)
216 accesslog = openlog(myui.config("web", "accesslog", "-"), sys.stdout)
217 errorlog = openlog(myui.config("web", "errorlog", "-"), sys.stderr)
217 errorlog = openlog(myui.config("web", "errorlog", "-"), sys.stderr)
218
218
219 if use_threads:
219 if use_threads:
220 try:
220 try:
221 from threading import activeCount
221 from threading import activeCount
222 except ImportError:
222 except ImportError:
223 use_threads = False
223 use_threads = False
224
224
225 if use_threads:
225 if use_threads:
226 _mixin = SocketServer.ThreadingMixIn
226 _mixin = SocketServer.ThreadingMixIn
227 else:
227 else:
228 if hasattr(os, "fork"):
228 if hasattr(os, "fork"):
229 _mixin = SocketServer.ForkingMixIn
229 _mixin = SocketServer.ForkingMixIn
230 else:
230 else:
231 class _mixin:
231 class _mixin:
232 pass
232 pass
233
233
234 class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer):
234 class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer):
235
235
236 # SO_REUSEADDR has broken semantics on windows
236 # SO_REUSEADDR has broken semantics on windows
237 if os.name == 'nt':
237 if os.name == 'nt':
238 allow_reuse_address = 0
238 allow_reuse_address = 0
239
239
240 def __init__(self, *args, **kargs):
240 def __init__(self, *args, **kargs):
241 BaseHTTPServer.HTTPServer.__init__(self, *args, **kargs)
241 BaseHTTPServer.HTTPServer.__init__(self, *args, **kargs)
242 self.accesslog = accesslog
242 self.accesslog = accesslog
243 self.errorlog = errorlog
243 self.errorlog = errorlog
244 self.daemon_threads = True
244 self.daemon_threads = True
245 def make_handler():
245 def make_handler():
246 if webdir_conf:
246 if webdir_conf:
247 hgwebobj = hgwebdir(webdir_conf, ui)
247 hgwebobj = hgwebdir(webdir_conf, ui)
248 elif repo is not None:
248 elif repo is not None:
249 hgwebobj = hgweb(hg.repository(repo.ui, repo.root))
249 hgwebobj = hgweb(hg.repository(repo.ui, repo.root))
250 else:
250 else:
251 raise RepoError(_("There is no Mercurial repository here"
251 raise RepoError(_("There is no Mercurial repository here"
252 " (.hg not found)"))
252 " (.hg not found)"))
253 return hgwebobj
253 return hgwebobj
254 self.application = make_handler()
254 self.application = make_handler()
255
255
256 if ssl_cert:
256 if ssl_cert:
257 try:
257 try:
258 from OpenSSL import SSL
258 from OpenSSL import SSL
259 ctx = SSL.Context(SSL.SSLv23_METHOD)
259 ctx = SSL.Context(SSL.SSLv23_METHOD)
260 except ImportError:
260 except ImportError:
261 raise util.Abort("SSL support is unavailable")
261 raise util.Abort("SSL support is unavailable")
262 ctx.use_privatekey_file(ssl_cert)
262 ctx.use_privatekey_file(ssl_cert)
263 ctx.use_certificate_file(ssl_cert)
263 ctx.use_certificate_file(ssl_cert)
264 sock = socket.socket(self.address_family, self.socket_type)
264 sock = socket.socket(self.address_family, self.socket_type)
265 self.socket = SSL.Connection(ctx, sock)
265 self.socket = SSL.Connection(ctx, sock)
266 self.server_bind()
266 self.server_bind()
267 self.server_activate()
267 self.server_activate()
268
268
269 self.addr, self.port = self.socket.getsockname()[0:2]
269 self.addr, self.port = self.socket.getsockname()[0:2]
270 self.prefix = prefix
270 self.prefix = prefix
271
272 self.fqaddr = socket.getfqdn(address)
271 self.fqaddr = socket.getfqdn(address)
273 try:
274 socket.getaddrbyhost(self.fqaddr)
275 except:
276 fqaddr = address
277
272
278 class IPv6HTTPServer(MercurialHTTPServer):
273 class IPv6HTTPServer(MercurialHTTPServer):
279 address_family = getattr(socket, 'AF_INET6', None)
274 address_family = getattr(socket, 'AF_INET6', None)
280
275
281 def __init__(self, *args, **kwargs):
276 def __init__(self, *args, **kwargs):
282 if self.address_family is None:
277 if self.address_family is None:
283 raise RepoError(_('IPv6 not available on this system'))
278 raise RepoError(_('IPv6 not available on this system'))
284 super(IPv6HTTPServer, self).__init__(*args, **kwargs)
279 super(IPv6HTTPServer, self).__init__(*args, **kwargs)
285
280
286 if ssl_cert:
281 if ssl_cert:
287 handler = _shgwebhandler
282 handler = _shgwebhandler
288 else:
283 else:
289 handler = _hgwebhandler
284 handler = _hgwebhandler
290
285
291 try:
286 try:
292 if use_ipv6:
287 if use_ipv6:
293 return IPv6HTTPServer((address, port), handler)
288 return IPv6HTTPServer((address, port), handler)
294 else:
289 else:
295 return MercurialHTTPServer((address, port), handler)
290 return MercurialHTTPServer((address, port), handler)
296 except socket.error, inst:
291 except socket.error, inst:
297 raise util.Abort(_("cannot start server at '%s:%d': %s")
292 raise util.Abort(_("cannot start server at '%s:%d': %s")
298 % (address, port, inst.args[1]))
293 % (address, port, inst.args[1]))
General Comments 0
You need to be logged in to leave comments. Login now