comparison mercurial/hgweb/__init__.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 f789602ba840
children 2db831b33e8f
comparison
equal deleted inserted replaced
2352:61909dfb316d 2355:eb08fb4d41e1
8 8
9 import os, cgi, sys 9 import os, cgi, sys
10 import mimetypes 10 import mimetypes
11 from mercurial.demandload import demandload 11 from mercurial.demandload import demandload
12 demandload(globals(), "time re socket zlib errno ConfigParser tempfile") 12 demandload(globals(), "time re socket zlib errno ConfigParser tempfile")
13 demandload(globals(), "StringIO BaseHTTPServer SocketServer urllib")
14 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater") 13 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater")
14 demandload(globals(), "mercurial.hgweb.request:hgrequest")
15 demandload(globals(), "mercurial.hgweb.server:create_server")
15 from mercurial.node import * 16 from mercurial.node import *
16 from mercurial.i18n import gettext as _ 17 from mercurial.i18n import gettext as _
17
18 def splitURI(uri):
19 """ Return path and query splited from uri
20
21 Just like CGI environment, the path is unquoted, the query is
22 not.
23 """
24 if '?' in uri:
25 path, query = uri.split('?', 1)
26 else:
27 path, query = uri, ''
28 return urllib.unquote(path), query
29 18
30 def up(p): 19 def up(p):
31 if p[0] != "/": 20 if p[0] != "/":
32 p = "/" + p 21 p = "/" + p
33 if p[-1] == "/": 22 if p[-1] == "/":
66 ct = mimetypes.guess_type(path)[0] or "text/plain" 55 ct = mimetypes.guess_type(path)[0] or "text/plain"
67 return "Content-type: %s\n\n%s" % (ct, file(path).read()) 56 return "Content-type: %s\n\n%s" % (ct, file(path).read())
68 except (TypeError, OSError): 57 except (TypeError, OSError):
69 # illegal fname or unreadable file 58 # illegal fname or unreadable file
70 return "" 59 return ""
71
72 class hgrequest(object):
73 def __init__(self, inp=None, out=None, env=None):
74 self.inp = inp or sys.stdin
75 self.out = out or sys.stdout
76 self.env = env or os.environ
77 self.form = cgi.parse(self.inp, self.env, keep_blank_values=1)
78
79 def write(self, *things):
80 for thing in things:
81 if hasattr(thing, "__iter__"):
82 for part in thing:
83 self.write(part)
84 else:
85 try:
86 self.out.write(str(thing))
87 except socket.error, inst:
88 if inst[0] != errno.ECONNRESET:
89 raise
90
91 def header(self, headers=[('Content-type','text/html')]):
92 for header in headers:
93 self.out.write("%s: %s\r\n" % header)
94 self.out.write("\r\n")
95
96 def httphdr(self, type, file="", size=0):
97
98 headers = [('Content-type', type)]
99 if file:
100 headers.append(('Content-disposition', 'attachment; filename=%s' % file))
101 if size > 0:
102 headers.append(('Content-length', str(size)))
103 self.header(headers)
104 60
105 class hgweb(object): 61 class hgweb(object):
106 def __init__(self, repo, name=None): 62 def __init__(self, repo, name=None):
107 if type(repo) == type(""): 63 if type(repo) == type(""):
108 self.repo = hg.repository(ui.ui(), repo) 64 self.repo = hg.repository(ui.ui(), repo)
890 req.write(staticfile(static, fname) 846 req.write(staticfile(static, fname)
891 or self.t("error", error="%r not found" % fname)) 847 or self.t("error", error="%r not found" % fname))
892 848
893 else: 849 else:
894 req.write(self.t("error")) 850 req.write(self.t("error"))
895
896 def create_server(ui, repo):
897 use_threads = True
898
899 def openlog(opt, default):
900 if opt and opt != '-':
901 return open(opt, 'w')
902 return default
903
904 address = ui.config("web", "address", "")
905 port = int(ui.config("web", "port", 8000))
906 use_ipv6 = ui.configbool("web", "ipv6")
907 webdir_conf = ui.config("web", "webdir_conf")
908 accesslog = openlog(ui.config("web", "accesslog", "-"), sys.stdout)
909 errorlog = openlog(ui.config("web", "errorlog", "-"), sys.stderr)
910
911 if use_threads:
912 try:
913 from threading import activeCount
914 except ImportError:
915 use_threads = False
916
917 if use_threads:
918 _mixin = SocketServer.ThreadingMixIn
919 else:
920 if hasattr(os, "fork"):
921 _mixin = SocketServer.ForkingMixIn
922 else:
923 class _mixin: pass
924
925 class MercurialHTTPServer(_mixin, BaseHTTPServer.HTTPServer):
926 pass
927
928 class IPv6HTTPServer(MercurialHTTPServer):
929 address_family = getattr(socket, 'AF_INET6', None)
930
931 def __init__(self, *args, **kwargs):
932 if self.address_family is None:
933 raise hg.RepoError(_('IPv6 not available on this system'))
934 BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
935
936 class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
937
938 def log_error(self, format, *args):
939 errorlog.write("%s - - [%s] %s\n" % (self.address_string(),
940 self.log_date_time_string(),
941 format % args))
942
943 def log_message(self, format, *args):
944 accesslog.write("%s - - [%s] %s\n" % (self.address_string(),
945 self.log_date_time_string(),
946 format % args))
947
948 def do_POST(self):
949 try:
950 self.do_hgweb()
951 except socket.error, inst:
952 if inst[0] != errno.EPIPE:
953 raise
954
955 def do_GET(self):
956 self.do_POST()
957
958 def do_hgweb(self):
959 path_info, query = splitURI(self.path)
960
961 env = {}
962 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
963 env['REQUEST_METHOD'] = self.command
964 env['SERVER_NAME'] = self.server.server_name
965 env['SERVER_PORT'] = str(self.server.server_port)
966 env['REQUEST_URI'] = "/"
967 env['PATH_INFO'] = path_info
968 if query:
969 env['QUERY_STRING'] = query
970 host = self.address_string()
971 if host != self.client_address[0]:
972 env['REMOTE_HOST'] = host
973 env['REMOTE_ADDR'] = self.client_address[0]
974
975 if self.headers.typeheader is None:
976 env['CONTENT_TYPE'] = self.headers.type
977 else:
978 env['CONTENT_TYPE'] = self.headers.typeheader
979 length = self.headers.getheader('content-length')
980 if length:
981 env['CONTENT_LENGTH'] = length
982 accept = []
983 for line in self.headers.getallmatchingheaders('accept'):
984 if line[:1] in "\t\n\r ":
985 accept.append(line.strip())
986 else:
987 accept = accept + line[7:].split(',')
988 env['HTTP_ACCEPT'] = ','.join(accept)
989
990 req = hgrequest(self.rfile, self.wfile, env)
991 self.send_response(200, "Script output follows")
992
993 if webdir_conf:
994 hgwebobj = hgwebdir(webdir_conf)
995 elif repo is not None:
996 hgwebobj = hgweb(repo.__class__(repo.ui, repo.origroot))
997 else:
998 raise hg.RepoError(_('no repo found'))
999 hgwebobj.run(req)
1000
1001
1002 if use_ipv6:
1003 return IPv6HTTPServer((address, port), hgwebhandler)
1004 else:
1005 return MercurialHTTPServer((address, port), hgwebhandler)
1006 851
1007 # This is a stopgap 852 # This is a stopgap
1008 class hgwebdir(object): 853 class hgwebdir(object):
1009 def __init__(self, config): 854 def __init__(self, config):
1010 def cleannames(items): 855 def cleannames(items):