Mercurial > public > mercurial-scm > hg-stable
annotate mercurial/hgweb/request.py @ 36872:cf69df7ea385
hgweb: remove wsgirequest.form (API)
Now that everything is ported to consume from parsedrequest.qsparams,
we no longer have a need for wsgirequest.form. Let's remove all
references to it.
.. api::
The WSGI request object no longer exposes a ``form`` attribute
containing parsed query string data. Use the ``qsparams`` attribute
instead.
Differential Revision: https://phab.mercurial-scm.org/D2782
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sat, 10 Mar 2018 12:31:11 -0800 |
parents | ec0af9c59270 |
children | a755fd3b7146 |
rev | line source |
---|---|
2391
d351a3be3371
Fixing up comment headers for split up code.
Eric Hopper <hopper@omnifarious.org>
parents:
2355
diff
changeset
|
1 # hgweb/request.py - An http request from either CGI or the standalone server. |
131 | 2 # |
238
3b92f8fe47ae
hgweb.py: kill #! line, clean up copyright notice
mpm@selenic.com
parents:
222
diff
changeset
|
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> |
2859 | 4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> |
131 | 5 # |
8225
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
7742
diff
changeset
|
6 # This software may be used and distributed according to the terms of the |
10263 | 7 # GNU General Public License version 2 or any later version. |
131 | 8 |
27046
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
9 from __future__ import absolute_import |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
10 |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
11 import errno |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
12 import socket |
36822
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
13 import wsgiref.headers as wsgiheaders |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
14 #import wsgiref.validate |
27046
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
15 |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
16 from .common import ( |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
17 ErrorResponse, |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
18 HTTP_NOT_MODIFIED, |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
19 statusmessage, |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
20 ) |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
21 |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
22 from ..thirdparty import ( |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
23 attr, |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
24 ) |
27046
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
25 from .. import ( |
36867
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
26 error, |
34514
528b21b853aa
request: coerce content-type to native str
Augie Fackler <augie@google.com>
parents:
34513
diff
changeset
|
27 pycompat, |
27046
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
28 util, |
37fcfe52c68c
hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents:
26846
diff
changeset
|
29 ) |
138 | 30 |
36868
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
31 class multidict(object): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
32 """A dict like object that can store multiple values for a key. |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
33 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
34 Used to store parsed request parameters. |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
35 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
36 This is inspired by WebOb's class of the same name. |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
37 """ |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
38 def __init__(self): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
39 # Stores (key, value) 2-tuples. This isn't the most efficient. But we |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
40 # don't rely on parameters that much, so it shouldn't be a perf issue. |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
41 # we can always add dict for fast lookups. |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
42 self._items = [] |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
43 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
44 def __getitem__(self, key): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
45 """Returns the last set value for a key.""" |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
46 for k, v in reversed(self._items): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
47 if k == key: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
48 return v |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
49 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
50 raise KeyError(key) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
51 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
52 def __setitem__(self, key, value): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
53 """Replace a values for a key with a new value.""" |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
54 try: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
55 del self[key] |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
56 except KeyError: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
57 pass |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
58 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
59 self._items.append((key, value)) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
60 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
61 def __delitem__(self, key): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
62 """Delete all values for a key.""" |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
63 oldlen = len(self._items) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
64 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
65 self._items[:] = [(k, v) for k, v in self._items if k != key] |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
66 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
67 if oldlen == len(self._items): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
68 raise KeyError(key) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
69 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
70 def __contains__(self, key): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
71 return any(k == key for k, v in self._items) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
72 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
73 def __len__(self): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
74 return len(self._items) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
75 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
76 def get(self, key, default=None): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
77 try: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
78 return self.__getitem__(key) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
79 except KeyError: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
80 return default |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
81 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
82 def add(self, key, value): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
83 """Add a new value for a key. Does not replace existing values.""" |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
84 self._items.append((key, value)) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
85 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
86 def getall(self, key): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
87 """Obtains all values for a key.""" |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
88 return [v for k, v in self._items if k == key] |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
89 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
90 def getone(self, key): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
91 """Obtain a single value for a key. |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
92 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
93 Raises KeyError if key not defined or it has multiple values set. |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
94 """ |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
95 vals = self.getall(key) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
96 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
97 if not vals: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
98 raise KeyError(key) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
99 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
100 if len(vals) > 1: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
101 raise KeyError('multiple values for %r' % key) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
102 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
103 return vals[0] |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
104 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
105 def asdictoflists(self): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
106 d = {} |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
107 for k, v in self._items: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
108 if k in d: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
109 d[k].append(v) |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
110 else: |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
111 d[k] = [v] |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
112 |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
113 return d |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
114 |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
115 @attr.s(frozen=True) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
116 class parsedrequest(object): |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
117 """Represents a parsed WSGI request. |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
118 |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
119 Contains both parsed parameters as well as a handle on the input stream. |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
120 """ |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
121 |
36854
16292bbda39c
hgweb: store and use request method on parsed request
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36853
diff
changeset
|
122 # Request method. |
16292bbda39c
hgweb: store and use request method on parsed request
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36853
diff
changeset
|
123 method = attr.ib() |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
124 # Full URL for this request. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
125 url = attr.ib() |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
126 # URL without any path components. Just <proto>://<host><port>. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
127 baseurl = attr.ib() |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
128 # Advertised URL. Like ``url`` and ``baseurl`` but uses SERVER_NAME instead |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
129 # of HTTP: Host header for hostname. This is likely what clients used. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
130 advertisedurl = attr.ib() |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
131 advertisedbaseurl = attr.ib() |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
132 # WSGI application path. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
133 apppath = attr.ib() |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
134 # List of path parts to be used for dispatch. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
135 dispatchparts = attr.ib() |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
136 # URL path component (no query string) used for dispatch. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
137 dispatchpath = attr.ib() |
36819
cfb9ef24968c
hgweb: use parsed request to construct query parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36817
diff
changeset
|
138 # Whether there is a path component to this request. This can be true |
cfb9ef24968c
hgweb: use parsed request to construct query parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36817
diff
changeset
|
139 # when ``dispatchpath`` is empty due to REPO_NAME muckery. |
cfb9ef24968c
hgweb: use parsed request to construct query parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36817
diff
changeset
|
140 havepathinfo = attr.ib() |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
141 # Raw query string (part after "?" in URL). |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
142 querystring = attr.ib() |
36868
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
143 # multidict of query string parameters. |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
144 qsparams = attr.ib() |
36822
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
145 # wsgiref.headers.Headers instance. Operates like a dict with case |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
146 # insensitive keys. |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
147 headers = attr.ib() |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
148 # Request body input stream. |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
149 bodyfh = attr.ib() |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
150 |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
151 def parserequestfromenv(env, bodyfh): |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
152 """Parse URL components from environment variables. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
153 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
154 WSGI defines request attributes via environment variables. This function |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
155 parses the environment variables into a data structure. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
156 """ |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
157 # PEP-0333 defines the WSGI spec and is a useful reference for this code. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
158 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
159 # We first validate that the incoming object conforms with the WSGI spec. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
160 # We only want to be dealing with spec-conforming WSGI implementations. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
161 # TODO enable this once we fix internal violations. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
162 #wsgiref.validate.check_environ(env) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
163 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
164 # PEP-0333 states that environment keys and values are native strings |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
165 # (bytes on Python 2 and str on Python 3). The code points for the Unicode |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
166 # strings on Python 3 must be between \00000-\000FF. We deal with bytes |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
167 # in Mercurial, so mass convert string keys and values to bytes. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
168 if pycompat.ispy3: |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
169 env = {k.encode('latin-1'): v for k, v in env.iteritems()} |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
170 env = {k: v.encode('latin-1') if isinstance(v, str) else v |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
171 for k, v in env.iteritems()} |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
172 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
173 # https://www.python.org/dev/peps/pep-0333/#environ-variables defines |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
174 # the environment variables. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
175 # https://www.python.org/dev/peps/pep-0333/#url-reconstruction defines |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
176 # how URLs are reconstructed. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
177 fullurl = env['wsgi.url_scheme'] + '://' |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
178 advertisedfullurl = fullurl |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
179 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
180 def addport(s): |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
181 if env['wsgi.url_scheme'] == 'https': |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
182 if env['SERVER_PORT'] != '443': |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
183 s += ':' + env['SERVER_PORT'] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
184 else: |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
185 if env['SERVER_PORT'] != '80': |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
186 s += ':' + env['SERVER_PORT'] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
187 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
188 return s |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
189 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
190 if env.get('HTTP_HOST'): |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
191 fullurl += env['HTTP_HOST'] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
192 else: |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
193 fullurl += env['SERVER_NAME'] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
194 fullurl = addport(fullurl) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
195 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
196 advertisedfullurl += env['SERVER_NAME'] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
197 advertisedfullurl = addport(advertisedfullurl) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
198 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
199 baseurl = fullurl |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
200 advertisedbaseurl = advertisedfullurl |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
201 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
202 fullurl += util.urlreq.quote(env.get('SCRIPT_NAME', '')) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
203 advertisedfullurl += util.urlreq.quote(env.get('SCRIPT_NAME', '')) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
204 fullurl += util.urlreq.quote(env.get('PATH_INFO', '')) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
205 advertisedfullurl += util.urlreq.quote(env.get('PATH_INFO', '')) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
206 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
207 if env.get('QUERY_STRING'): |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
208 fullurl += '?' + env['QUERY_STRING'] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
209 advertisedfullurl += '?' + env['QUERY_STRING'] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
210 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
211 # When dispatching requests, we look at the URL components (PATH_INFO |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
212 # and QUERY_STRING) after the application root (SCRIPT_NAME). But hgwebdir |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
213 # has the concept of "virtual" repositories. This is defined via REPO_NAME. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
214 # If REPO_NAME is defined, we append it to SCRIPT_NAME to form a new app |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
215 # root. We also exclude its path components from PATH_INFO when resolving |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
216 # the dispatch path. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
217 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
218 apppath = env['SCRIPT_NAME'] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
219 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
220 if env.get('REPO_NAME'): |
36816
0031e972ded2
hgweb: use the parsed application path directly
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36814
diff
changeset
|
221 if not apppath.endswith('/'): |
0031e972ded2
hgweb: use the parsed application path directly
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36814
diff
changeset
|
222 apppath += '/' |
0031e972ded2
hgweb: use the parsed application path directly
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36814
diff
changeset
|
223 |
0031e972ded2
hgweb: use the parsed application path directly
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36814
diff
changeset
|
224 apppath += env.get('REPO_NAME') |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
225 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
226 if 'PATH_INFO' in env: |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
227 dispatchparts = env['PATH_INFO'].strip('/').split('/') |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
228 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
229 # Strip out repo parts. |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
230 repoparts = env.get('REPO_NAME', '').split('/') |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
231 if dispatchparts[:len(repoparts)] == repoparts: |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
232 dispatchparts = dispatchparts[len(repoparts):] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
233 else: |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
234 dispatchparts = [] |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
235 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
236 dispatchpath = '/'.join(dispatchparts) |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
237 |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
238 querystring = env.get('QUERY_STRING', '') |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
239 |
36817
3c15b84ab66c
hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36816
diff
changeset
|
240 # We store as a list so we have ordering information. We also store as |
3c15b84ab66c
hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36816
diff
changeset
|
241 # a dict to facilitate fast lookup. |
36868
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
242 qsparams = multidict() |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
243 for k, v in util.urlreq.parseqsl(querystring, keep_blank_values=True): |
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
244 qsparams.add(k, v) |
36817
3c15b84ab66c
hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36816
diff
changeset
|
245 |
36822
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
246 # HTTP_* keys contain HTTP request headers. The Headers structure should |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
247 # perform case normalization for us. We just rewrite underscore to dash |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
248 # so keys match what likely went over the wire. |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
249 headers = [] |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
250 for k, v in env.iteritems(): |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
251 if k.startswith('HTTP_'): |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
252 headers.append((k[len('HTTP_'):].replace('_', '-'), v)) |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
253 |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
254 headers = wsgiheaders.Headers(headers) |
f9078c6caeb6
hgweb: parse and store HTTP request headers
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36819
diff
changeset
|
255 |
36853
ed0456fde625
hgweb: handle CONTENT_LENGTH
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36822
diff
changeset
|
256 # This is kind of a lie because the HTTP header wasn't explicitly |
ed0456fde625
hgweb: handle CONTENT_LENGTH
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36822
diff
changeset
|
257 # sent. But for all intents and purposes it should be OK to lie about |
ed0456fde625
hgweb: handle CONTENT_LENGTH
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36822
diff
changeset
|
258 # this, since a consumer will either either value to determine how many |
ed0456fde625
hgweb: handle CONTENT_LENGTH
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36822
diff
changeset
|
259 # bytes are available to read. |
ed0456fde625
hgweb: handle CONTENT_LENGTH
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36822
diff
changeset
|
260 if 'CONTENT_LENGTH' in env and 'HTTP_CONTENT_LENGTH' not in env: |
ed0456fde625
hgweb: handle CONTENT_LENGTH
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36822
diff
changeset
|
261 headers['Content-Length'] = env['CONTENT_LENGTH'] |
ed0456fde625
hgweb: handle CONTENT_LENGTH
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36822
diff
changeset
|
262 |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
263 # TODO do this once we remove wsgirequest.inp, otherwise we could have |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
264 # multiple readers from the underlying input stream. |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
265 #bodyfh = env['wsgi.input'] |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
266 #if 'Content-Length' in headers: |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
267 # bodyfh = util.cappedreader(bodyfh, int(headers['Content-Length'])) |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
268 |
36854
16292bbda39c
hgweb: store and use request method on parsed request
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36853
diff
changeset
|
269 return parsedrequest(method=env['REQUEST_METHOD'], |
16292bbda39c
hgweb: store and use request method on parsed request
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36853
diff
changeset
|
270 url=fullurl, baseurl=baseurl, |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
271 advertisedurl=advertisedfullurl, |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
272 advertisedbaseurl=advertisedbaseurl, |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
273 apppath=apppath, |
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
274 dispatchparts=dispatchparts, dispatchpath=dispatchpath, |
36819
cfb9ef24968c
hgweb: use parsed request to construct query parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36817
diff
changeset
|
275 havepathinfo='PATH_INFO' in env, |
36817
3c15b84ab66c
hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36816
diff
changeset
|
276 querystring=querystring, |
36868
ec0af9c59270
hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36867
diff
changeset
|
277 qsparams=qsparams, |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
278 headers=headers, |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
279 bodyfh=bodyfh) |
36814
69b2d0900cd7
hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36736
diff
changeset
|
280 |
36867
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
281 class wsgiresponse(object): |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
282 """Represents a response to a WSGI request. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
283 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
284 A response consists of a status line, headers, and a body. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
285 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
286 Consumers must populate the ``status`` and ``headers`` fields and |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
287 make a call to a ``setbody*()`` method before the response can be |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
288 issued. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
289 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
290 When it is time to start sending the response over the wire, |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
291 ``sendresponse()`` is called. It handles emitting the header portion |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
292 of the response message. It then yields chunks of body data to be |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
293 written to the peer. Typically, the WSGI application itself calls |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
294 and returns the value from ``sendresponse()``. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
295 """ |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
296 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
297 def __init__(self, req, startresponse): |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
298 """Create an empty response tied to a specific request. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
299 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
300 ``req`` is a ``parsedrequest``. ``startresponse`` is the |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
301 ``start_response`` function passed to the WSGI application. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
302 """ |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
303 self._req = req |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
304 self._startresponse = startresponse |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
305 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
306 self.status = None |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
307 self.headers = wsgiheaders.Headers([]) |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
308 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
309 self._bodybytes = None |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
310 self._bodygen = None |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
311 self._started = False |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
312 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
313 def setbodybytes(self, b): |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
314 """Define the response body as static bytes.""" |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
315 if self._bodybytes is not None or self._bodygen is not None: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
316 raise error.ProgrammingError('cannot define body multiple times') |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
317 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
318 self._bodybytes = b |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
319 self.headers['Content-Length'] = '%d' % len(b) |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
320 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
321 def setbodygen(self, gen): |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
322 """Define the response body as a generator of bytes.""" |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
323 if self._bodybytes is not None or self._bodygen is not None: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
324 raise error.ProgrammingError('cannot define body multiple times') |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
325 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
326 self._bodygen = gen |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
327 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
328 def sendresponse(self): |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
329 """Send the generated response to the client. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
330 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
331 Before this is called, ``status`` must be set and one of |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
332 ``setbodybytes()`` or ``setbodygen()`` must be called. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
333 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
334 Calling this method multiple times is not allowed. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
335 """ |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
336 if self._started: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
337 raise error.ProgrammingError('sendresponse() called multiple times') |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
338 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
339 self._started = True |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
340 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
341 if not self.status: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
342 raise error.ProgrammingError('status line not defined') |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
343 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
344 if self._bodybytes is None and self._bodygen is None: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
345 raise error.ProgrammingError('response body not defined') |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
346 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
347 # Various HTTP clients (notably httplib) won't read the HTTP response |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
348 # until the HTTP request has been sent in full. If servers (us) send a |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
349 # response before the HTTP request has been fully sent, the connection |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
350 # may deadlock because neither end is reading. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
351 # |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
352 # We work around this by "draining" the request data before |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
353 # sending any response in some conditions. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
354 drain = False |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
355 close = False |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
356 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
357 # If the client sent Expect: 100-continue, we assume it is smart enough |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
358 # to deal with the server sending a response before reading the request. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
359 # (httplib doesn't do this.) |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
360 if self._req.headers.get('Expect', '').lower() == '100-continue': |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
361 pass |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
362 # Only tend to request methods that have bodies. Strictly speaking, |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
363 # we should sniff for a body. But this is fine for our existing |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
364 # WSGI applications. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
365 elif self._req.method not in ('POST', 'PUT'): |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
366 pass |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
367 else: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
368 # If we don't know how much data to read, there's no guarantee |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
369 # that we can drain the request responsibly. The WSGI |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
370 # specification only says that servers *should* ensure the |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
371 # input stream doesn't overrun the actual request. So there's |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
372 # no guarantee that reading until EOF won't corrupt the stream |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
373 # state. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
374 if not isinstance(self._req.bodyfh, util.cappedreader): |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
375 close = True |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
376 else: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
377 # We /could/ only drain certain HTTP response codes. But 200 and |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
378 # non-200 wire protocol responses both require draining. Since |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
379 # we have a capped reader in place for all situations where we |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
380 # drain, it is safe to read from that stream. We'll either do |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
381 # a drain or no-op if we're already at EOF. |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
382 drain = True |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
383 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
384 if close: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
385 self.headers['Connection'] = 'Close' |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
386 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
387 if drain: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
388 assert isinstance(self._req.bodyfh, util.cappedreader) |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
389 while True: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
390 chunk = self._req.bodyfh.read(32768) |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
391 if not chunk: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
392 break |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
393 |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
394 self._startresponse(pycompat.sysstr(self.status), self.headers.items()) |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
395 if self._bodybytes: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
396 yield self._bodybytes |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
397 elif self._bodygen: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
398 for chunk in self._bodygen: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
399 yield chunk |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
400 else: |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
401 error.ProgrammingError('do not know how to send body') |
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
402 |
5566
d74fc8dec2b4
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5563
diff
changeset
|
403 class wsgirequest(object): |
26132
9df8c729e2e7
hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
404 """Higher-level API for a WSGI request. |
9df8c729e2e7
hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
405 |
9df8c729e2e7
hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
406 WSGI applications are invoked with 2 arguments. They are used to |
9df8c729e2e7
hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
407 instantiate instances of this class, which provides higher-level APIs |
9df8c729e2e7
hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
408 for obtaining request parameters, writing HTTP output, etc. |
9df8c729e2e7
hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
409 """ |
5566
d74fc8dec2b4
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5563
diff
changeset
|
410 def __init__(self, wsgienv, start_response): |
34512
482d6f6dba91
hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents:
27046
diff
changeset
|
411 version = wsgienv[r'wsgi.version'] |
3673
eb0b4a2d70a9
white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
412 if (version < (1, 0)) or (version >= (2, 0)): |
4633
ff7253a0d1da
Cleanup of whitespace, indentation and line continuation.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
4250
diff
changeset
|
413 raise RuntimeError("Unknown and unsupported WSGI version %d.%d" |
2506
d0db3462d568
This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents:
2466
diff
changeset
|
414 % version) |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
415 |
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
416 inp = wsgienv[r'wsgi.input'] |
36860
290fc4c3d1e0
hgweb: use a capped reader for WSGI input stream
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36858
diff
changeset
|
417 |
290fc4c3d1e0
hgweb: use a capped reader for WSGI input stream
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36858
diff
changeset
|
418 if r'HTTP_CONTENT_LENGTH' in wsgienv: |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
419 inp = util.cappedreader(inp, int(wsgienv[r'HTTP_CONTENT_LENGTH'])) |
36860
290fc4c3d1e0
hgweb: use a capped reader for WSGI input stream
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36858
diff
changeset
|
420 elif r'CONTENT_LENGTH' in wsgienv: |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
421 inp = util.cappedreader(inp, int(wsgienv[r'CONTENT_LENGTH'])) |
36860
290fc4c3d1e0
hgweb: use a capped reader for WSGI input stream
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36858
diff
changeset
|
422 |
34512
482d6f6dba91
hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents:
27046
diff
changeset
|
423 self.err = wsgienv[r'wsgi.errors'] |
482d6f6dba91
hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents:
27046
diff
changeset
|
424 self.threaded = wsgienv[r'wsgi.multithread'] |
482d6f6dba91
hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents:
27046
diff
changeset
|
425 self.multiprocess = wsgienv[r'wsgi.multiprocess'] |
482d6f6dba91
hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents:
27046
diff
changeset
|
426 self.run_once = wsgienv[r'wsgi.run_once'] |
2506
d0db3462d568
This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents:
2466
diff
changeset
|
427 self.env = wsgienv |
36864
01f6bba64424
hgweb: remove support for POST form data (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36863
diff
changeset
|
428 self.req = parserequestfromenv(wsgienv, inp) |
36867
a88d68dc3ee8
hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36865
diff
changeset
|
429 self.res = wsgiresponse(self.req, start_response) |
5888
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
430 self._start_response = start_response |
5993
948a41e77902
hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5930
diff
changeset
|
431 self.server_write = None |
2506
d0db3462d568
This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents:
2466
diff
changeset
|
432 self.headers = [] |
d0db3462d568
This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents:
2466
diff
changeset
|
433 |
18352
e33b9b92a200
hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents:
18351
diff
changeset
|
434 def respond(self, status, type, filename=None, body=None): |
34514
528b21b853aa
request: coerce content-type to native str
Augie Fackler <augie@google.com>
parents:
34513
diff
changeset
|
435 if not isinstance(type, str): |
528b21b853aa
request: coerce content-type to native str
Augie Fackler <augie@google.com>
parents:
34513
diff
changeset
|
436 type = pycompat.sysstr(type) |
5888
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
437 if self._start_response is not None: |
34722
95be8928d6b2
hgweb: fill in content-type and content-length as native strings
Augie Fackler <augie@google.com>
parents:
34514
diff
changeset
|
438 self.headers.append((r'Content-Type', type)) |
18348
764a758780b6
hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents:
18347
diff
changeset
|
439 if filename: |
26846
7c1b4840c2cd
hgweb: replace some str.split() calls by str.partition() or str.rpartition()
Anton Shestakov <av6@dwimlabs.net>
parents:
26200
diff
changeset
|
440 filename = (filename.rpartition('/')[-1] |
18348
764a758780b6
hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents:
18347
diff
changeset
|
441 .replace('\\', '\\\\').replace('"', '\\"')) |
764a758780b6
hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents:
18347
diff
changeset
|
442 self.headers.append(('Content-Disposition', |
764a758780b6
hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents:
18347
diff
changeset
|
443 'inline; filename="%s"' % filename)) |
18352
e33b9b92a200
hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents:
18351
diff
changeset
|
444 if body is not None: |
34722
95be8928d6b2
hgweb: fill in content-type and content-length as native strings
Augie Fackler <augie@google.com>
parents:
34514
diff
changeset
|
445 self.headers.append((r'Content-Length', str(len(body)))) |
5888
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
446 |
5926
15ef6b9c1f2f
hgweb: be sure to send a valid content-type for raw files
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5922
diff
changeset
|
447 for k, v in self.headers: |
15ef6b9c1f2f
hgweb: be sure to send a valid content-type for raw files
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5922
diff
changeset
|
448 if not isinstance(v, str): |
18348
764a758780b6
hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents:
18347
diff
changeset
|
449 raise TypeError('header value must be string: %r' % (v,)) |
5926
15ef6b9c1f2f
hgweb: be sure to send a valid content-type for raw files
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5922
diff
changeset
|
450 |
5888
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
451 if isinstance(status, ErrorResponse): |
18348
764a758780b6
hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents:
18347
diff
changeset
|
452 self.headers.extend(status.headers) |
12739
8dcd3203a261
hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents:
10263
diff
changeset
|
453 if status.code == HTTP_NOT_MODIFIED: |
8dcd3203a261
hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents:
10263
diff
changeset
|
454 # RFC 2616 Section 10.3.5: 304 Not Modified has cases where |
8dcd3203a261
hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents:
10263
diff
changeset
|
455 # it MUST NOT include any headers other than these and no |
8dcd3203a261
hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents:
10263
diff
changeset
|
456 # body |
8dcd3203a261
hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents:
10263
diff
changeset
|
457 self.headers = [(k, v) for (k, v) in self.headers if |
8dcd3203a261
hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents:
10263
diff
changeset
|
458 k in ('Date', 'ETag', 'Expires', |
8dcd3203a261
hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents:
10263
diff
changeset
|
459 'Cache-Control', 'Vary')] |
36288
a0a004b29a51
hgweb: correctly bytes-ify status, not string-ify
Augie Fackler <augie@google.com>
parents:
34722
diff
changeset
|
460 status = statusmessage(status.code, pycompat.bytestr(status)) |
5993
948a41e77902
hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5930
diff
changeset
|
461 elif status == 200: |
948a41e77902
hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5930
diff
changeset
|
462 status = '200 Script output follows' |
5888
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
463 elif isinstance(status, int): |
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
464 status = statusmessage(status) |
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
465 |
36861
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
466 # Various HTTP clients (notably httplib) won't read the HTTP |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
467 # response until the HTTP request has been sent in full. If servers |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
468 # (us) send a response before the HTTP request has been fully sent, |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
469 # the connection may deadlock because neither end is reading. |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
470 # |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
471 # We work around this by "draining" the request data before |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
472 # sending any response in some conditions. |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
473 drain = False |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
474 close = False |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
475 |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
476 # If the client sent Expect: 100-continue, we assume it is smart |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
477 # enough to deal with the server sending a response before reading |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
478 # the request. (httplib doesn't do this.) |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
479 if self.env.get(r'HTTP_EXPECT', r'').lower() == r'100-continue': |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
480 pass |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
481 # Only tend to request methods that have bodies. Strictly speaking, |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
482 # we should sniff for a body. But this is fine for our existing |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
483 # WSGI applications. |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
484 elif self.env[r'REQUEST_METHOD'] not in (r'POST', r'PUT'): |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
485 pass |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
486 else: |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
487 # If we don't know how much data to read, there's no guarantee |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
488 # that we can drain the request responsibly. The WSGI |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
489 # specification only says that servers *should* ensure the |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
490 # input stream doesn't overrun the actual request. So there's |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
491 # no guarantee that reading until EOF won't corrupt the stream |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
492 # state. |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
493 if not isinstance(self.req.bodyfh, util.cappedreader): |
36861
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
494 close = True |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
495 else: |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
496 # We /could/ only drain certain HTTP response codes. But 200 |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
497 # and non-200 wire protocol responses both require draining. |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
498 # Since we have a capped reader in place for all situations |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
499 # where we drain, it is safe to read from that stream. We'll |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
500 # either do a drain or no-op if we're already at EOF. |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
501 drain = True |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
502 |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
503 if close: |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
504 self.headers.append((r'Connection', r'Close')) |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
505 |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
506 if drain: |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
507 assert isinstance(self.req.bodyfh, util.cappedreader) |
36861
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
508 while True: |
36863
da4e2f87167d
hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36862
diff
changeset
|
509 chunk = self.req.bodyfh.read(32768) |
36861
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
510 if not chunk: |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
511 break |
2cdf47e14c30
hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36860
diff
changeset
|
512 |
36291
af0a19d8812b
py3: get bytes-repr of network errors portably
Augie Fackler <augie@google.com>
parents:
36288
diff
changeset
|
513 self.server_write = self._start_response( |
af0a19d8812b
py3: get bytes-repr of network errors portably
Augie Fackler <augie@google.com>
parents:
36288
diff
changeset
|
514 pycompat.sysstr(status), self.headers) |
5888
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
515 self._start_response = None |
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
516 self.headers = [] |
18352
e33b9b92a200
hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents:
18351
diff
changeset
|
517 if body is not None: |
e33b9b92a200
hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents:
18351
diff
changeset
|
518 self.write(body) |
e33b9b92a200
hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents:
18351
diff
changeset
|
519 self.server_write = None |
5888
956afc025c0f
hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5887
diff
changeset
|
520 |
5993
948a41e77902
hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5930
diff
changeset
|
521 def write(self, thing): |
18351
3fbdbeab38cc
hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents:
18350
diff
changeset
|
522 if thing: |
3fbdbeab38cc
hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents:
18350
diff
changeset
|
523 try: |
3fbdbeab38cc
hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents:
18350
diff
changeset
|
524 self.server_write(thing) |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
18352
diff
changeset
|
525 except socket.error as inst: |
18351
3fbdbeab38cc
hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents:
18350
diff
changeset
|
526 if inst[0] != errno.ECONNRESET: |
3fbdbeab38cc
hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents:
18350
diff
changeset
|
527 raise |
1159
b6f5a947e62e
Change use of global sys.stdout, sys.stdin os.environ to a hgrequest object.
Vincent Wagelaar <vincent@ricardis.tudelft.nl>
parents:
1143
diff
changeset
|
528 |
4246
cc81c512a531
avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
3673
diff
changeset
|
529 def flush(self): |
cc81c512a531
avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
3673
diff
changeset
|
530 return None |
cc81c512a531
avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
3673
diff
changeset
|
531 |
5566
d74fc8dec2b4
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5563
diff
changeset
|
532 def wsgiapplication(app_maker): |
5887
41a3fce17625
hgweb: return iterable, add deprecation note
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5886
diff
changeset
|
533 '''For compatibility with old CGI scripts. A plain hgweb() or hgwebdir() |
41a3fce17625
hgweb: return iterable, add deprecation note
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5886
diff
changeset
|
534 can and should now be used as a WSGI application.''' |
5760
0145f9afb0e7
Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents:
5566
diff
changeset
|
535 application = app_maker() |
0145f9afb0e7
Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents:
5566
diff
changeset
|
536 def run_wsgi(env, respond): |
5887
41a3fce17625
hgweb: return iterable, add deprecation note
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
5886
diff
changeset
|
537 return application(env, respond) |
5760
0145f9afb0e7
Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents:
5566
diff
changeset
|
538 return run_wsgi |