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