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)