8 |
8 |
9 from mercurial.demandload import demandload |
9 from mercurial.demandload import demandload |
10 demandload(globals(), "socket sys cgi os errno") |
10 demandload(globals(), "socket sys cgi os errno") |
11 from mercurial.i18n import gettext as _ |
11 from mercurial.i18n import gettext as _ |
12 |
12 |
13 class hgrequest(object): |
13 class wsgiapplication(object): |
14 def __init__(self, inp=None, out=None, env=None): |
14 def __init__(self, destmaker): |
15 self.inp = inp or sys.stdin |
15 self.destmaker = destmaker |
16 self.out = out or sys.stdout |
16 |
17 self.env = env or os.environ |
17 def __call__(self, wsgienv, start_response): |
|
18 return _wsgirequest(self.destmaker(), wsgienv, start_response) |
|
19 |
|
20 class _wsgioutputfile(object): |
|
21 def __init__(self, request): |
|
22 self.request = request |
|
23 |
|
24 def write(self, data): |
|
25 self.request.write(data) |
|
26 def writelines(self, lines): |
|
27 for line in lines: |
|
28 self.write(line) |
|
29 def flush(self): |
|
30 return None |
|
31 def close(self): |
|
32 return None |
|
33 |
|
34 class _wsgirequest(object): |
|
35 def __init__(self, destination, wsgienv, start_response): |
|
36 version = wsgienv['wsgi.version'] |
|
37 if (version < (1,0)) or (version >= (2, 0)): |
|
38 raise RuntimeError("Unknown and unsupported WSGI version %d.%d" \ |
|
39 % version) |
|
40 self.inp = wsgienv['wsgi.input'] |
|
41 self.out = _wsgioutputfile(self) |
|
42 self.server_write = None |
|
43 self.err = wsgienv['wsgi.errors'] |
|
44 self.threaded = wsgienv['wsgi.multithread'] |
|
45 self.multiprocess = wsgienv['wsgi.multiprocess'] |
|
46 self.run_once = wsgienv['wsgi.run_once'] |
|
47 self.env = wsgienv |
18 self.form = cgi.parse(self.inp, self.env, keep_blank_values=1) |
48 self.form = cgi.parse(self.inp, self.env, keep_blank_values=1) |
19 self.will_close = True |
49 self.start_response = start_response |
|
50 self.headers = [] |
|
51 destination.run(self) |
|
52 |
|
53 def __iter__(self): |
|
54 return iter([]) |
20 |
55 |
21 def read(self, count=-1): |
56 def read(self, count=-1): |
22 return self.inp.read(count) |
57 return self.inp.read(count) |
23 |
58 |
24 def write(self, *things): |
59 def write(self, *things): |
|
60 if self.server_write is None: |
|
61 if not self.headers: |
|
62 raise RuntimeError("request.write called before headers sent.") |
|
63 self.server_write = self.start_response('200 Script output follows', |
|
64 self.headers) |
|
65 self.start_response = None |
|
66 self.headers = None |
25 for thing in things: |
67 for thing in things: |
26 if hasattr(thing, "__iter__"): |
68 if hasattr(thing, "__iter__"): |
27 for part in thing: |
69 for part in thing: |
28 self.write(part) |
70 self.write(part) |
29 else: |
71 else: |
30 try: |
72 try: |
31 self.out.write(str(thing)) |
73 self.server_write(str(thing)) |
32 except socket.error, inst: |
74 except socket.error, inst: |
33 if inst[0] != errno.ECONNRESET: |
75 if inst[0] != errno.ECONNRESET: |
34 raise |
76 raise |
35 |
77 |
36 def done(self): |
|
37 if self.will_close: |
|
38 self.inp.close() |
|
39 self.out.close() |
|
40 else: |
|
41 self.out.flush() |
|
42 |
|
43 def header(self, headers=[('Content-type','text/html')]): |
78 def header(self, headers=[('Content-type','text/html')]): |
44 for header in headers: |
79 self.headers.extend(headers) |
45 self.out.write("%s: %s\r\n" % header) |
|
46 self.out.write("\r\n") |
|
47 |
80 |
48 def httphdr(self, type, filename=None, length=0, headers={}): |
81 def httphdr(self, type, filename=None, length=0, headers={}): |
49 headers = headers.items() |
82 headers = headers.items() |
50 headers.append(('Content-type', type)) |
83 headers.append(('Content-type', type)) |
51 if filename: |
84 if filename: |
52 headers.append(('Content-disposition', 'attachment; filename=%s' % |
85 headers.append(('Content-disposition', 'attachment; filename=%s' % |
53 filename)) |
86 filename)) |
54 # we do not yet support http 1.1 chunked transfer, so we have |
|
55 # to force connection to close if content-length not known |
|
56 if length: |
87 if length: |
57 headers.append(('Content-length', str(length))) |
88 headers.append(('Content-length', str(length))) |
58 self.will_close = False |
|
59 else: |
|
60 headers.append(('Connection', 'close')) |
|
61 self.will_close = True |
|
62 self.header(headers) |
89 self.header(headers) |