Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/hgweb/common.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 8d9322b6e687 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
42 Can be overridden by extensions to provide more complex authorization | 42 Can be overridden by extensions to provide more complex authorization |
43 schemes. | 43 schemes. |
44 """ | 44 """ |
45 return userlist == ['*'] or username in userlist | 45 return userlist == ['*'] or username in userlist |
46 | 46 |
47 | |
47 def checkauthz(hgweb, req, op): | 48 def checkauthz(hgweb, req, op): |
48 '''Check permission for operation based on request data (including | 49 '''Check permission for operation based on request data (including |
49 authentication info). Return if op allowed, else raise an ErrorResponse | 50 authentication info). Return if op allowed, else raise an ErrorResponse |
50 exception.''' | 51 exception.''' |
51 | 52 |
59 if allow_read and (not ismember(hgweb.repo.ui, user, allow_read)): | 60 if allow_read and (not ismember(hgweb.repo.ui, user, allow_read)): |
60 raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized') | 61 raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized') |
61 | 62 |
62 if op == 'pull' and not hgweb.allowpull: | 63 if op == 'pull' and not hgweb.allowpull: |
63 raise ErrorResponse(HTTP_UNAUTHORIZED, 'pull not authorized') | 64 raise ErrorResponse(HTTP_UNAUTHORIZED, 'pull not authorized') |
64 elif op == 'pull' or op is None: # op is None for interface requests | 65 elif op == 'pull' or op is None: # op is None for interface requests |
65 return | 66 return |
66 | 67 |
67 # Allow LFS uploading via PUT requests | 68 # Allow LFS uploading via PUT requests |
68 if op == 'upload': | 69 if op == 'upload': |
69 if req.method != 'PUT': | 70 if req.method != 'PUT': |
84 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized') | 85 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized') |
85 | 86 |
86 allow = hgweb.configlist('web', 'allow-push') | 87 allow = hgweb.configlist('web', 'allow-push') |
87 if not (allow and ismember(hgweb.repo.ui, user, allow)): | 88 if not (allow and ismember(hgweb.repo.ui, user, allow)): |
88 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized') | 89 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized') |
90 | |
89 | 91 |
90 # Hooks for hgweb permission checks; extensions can add hooks here. | 92 # Hooks for hgweb permission checks; extensions can add hooks here. |
91 # Each hook is invoked like this: hook(hgweb, request, operation), | 93 # Each hook is invoked like this: hook(hgweb, request, operation), |
92 # where operation is either read, pull, push or upload. Hooks should either | 94 # where operation is either read, pull, push or upload. Hooks should either |
93 # raise an ErrorResponse exception, or just return. | 95 # raise an ErrorResponse exception, or just return. |
106 if headers is None: | 108 if headers is None: |
107 headers = [] | 109 headers = [] |
108 self.headers = headers | 110 self.headers = headers |
109 self.message = message | 111 self.message = message |
110 | 112 |
113 | |
111 class continuereader(object): | 114 class continuereader(object): |
112 """File object wrapper to handle HTTP 100-continue. | 115 """File object wrapper to handle HTTP 100-continue. |
113 | 116 |
114 This is used by servers so they automatically handle Expect: 100-continue | 117 This is used by servers so they automatically handle Expect: 100-continue |
115 request headers. On first read of the request body, the 100 Continue | 118 request headers. On first read of the request body, the 100 Continue |
116 response is sent. This should trigger the client into actually sending | 119 response is sent. This should trigger the client into actually sending |
117 the request body. | 120 the request body. |
118 """ | 121 """ |
122 | |
119 def __init__(self, f, write): | 123 def __init__(self, f, write): |
120 self.f = f | 124 self.f = f |
121 self._write = write | 125 self._write = write |
122 self.continued = False | 126 self.continued = False |
123 | 127 |
130 def __getattr__(self, attr): | 134 def __getattr__(self, attr): |
131 if attr in ('close', 'readline', 'readlines', '__iter__'): | 135 if attr in ('close', 'readline', 'readlines', '__iter__'): |
132 return getattr(self.f, attr) | 136 return getattr(self.f, attr) |
133 raise AttributeError | 137 raise AttributeError |
134 | 138 |
139 | |
135 def _statusmessage(code): | 140 def _statusmessage(code): |
136 responses = httpserver.basehttprequesthandler.responses | 141 responses = httpserver.basehttprequesthandler.responses |
137 return pycompat.bytesurl( | 142 return pycompat.bytesurl( |
138 responses.get(code, (r'Error', r'Unknown error'))[0]) | 143 responses.get(code, (r'Error', r'Unknown error'))[0] |
144 ) | |
145 | |
139 | 146 |
140 def statusmessage(code, message=None): | 147 def statusmessage(code, message=None): |
141 return '%d %s' % (code, message or _statusmessage(code)) | 148 return '%d %s' % (code, message or _statusmessage(code)) |
149 | |
142 | 150 |
143 def get_stat(spath, fn): | 151 def get_stat(spath, fn): |
144 """stat fn if it exists, spath otherwise""" | 152 """stat fn if it exists, spath otherwise""" |
145 cl_path = os.path.join(spath, fn) | 153 cl_path = os.path.join(spath, fn) |
146 if os.path.exists(cl_path): | 154 if os.path.exists(cl_path): |
147 return os.stat(cl_path) | 155 return os.stat(cl_path) |
148 else: | 156 else: |
149 return os.stat(spath) | 157 return os.stat(spath) |
150 | 158 |
159 | |
151 def get_mtime(spath): | 160 def get_mtime(spath): |
152 return get_stat(spath, "00changelog.i")[stat.ST_MTIME] | 161 return get_stat(spath, "00changelog.i")[stat.ST_MTIME] |
162 | |
153 | 163 |
154 def ispathsafe(path): | 164 def ispathsafe(path): |
155 """Determine if a path is safe to use for filesystem access.""" | 165 """Determine if a path is safe to use for filesystem access.""" |
156 parts = path.split('/') | 166 parts = path.split('/') |
157 for part in parts: | 167 for part in parts: |
158 if (part in ('', pycompat.oscurdir, pycompat.ospardir) or | 168 if ( |
159 pycompat.ossep in part or | 169 part in ('', pycompat.oscurdir, pycompat.ospardir) |
160 pycompat.osaltsep is not None and pycompat.osaltsep in part): | 170 or pycompat.ossep in part |
171 or pycompat.osaltsep is not None | |
172 and pycompat.osaltsep in part | |
173 ): | |
161 return False | 174 return False |
162 | 175 |
163 return True | 176 return True |
177 | |
164 | 178 |
165 def staticfile(directory, fname, res): | 179 def staticfile(directory, fname, res): |
166 """return a file inside directory with guessed Content-Type header | 180 """return a file inside directory with guessed Content-Type header |
167 | 181 |
168 fname always uses '/' as directory separator and isn't allowed to | 182 fname always uses '/' as directory separator and isn't allowed to |
182 if os.path.exists(path): | 196 if os.path.exists(path): |
183 break | 197 break |
184 try: | 198 try: |
185 os.stat(path) | 199 os.stat(path) |
186 ct = pycompat.sysbytes( | 200 ct = pycompat.sysbytes( |
187 mimetypes.guess_type(pycompat.fsdecode(path))[0] or r"text/plain") | 201 mimetypes.guess_type(pycompat.fsdecode(path))[0] or r"text/plain" |
202 ) | |
188 with open(path, 'rb') as fh: | 203 with open(path, 'rb') as fh: |
189 data = fh.read() | 204 data = fh.read() |
190 | 205 |
191 res.headers['Content-Type'] = ct | 206 res.headers['Content-Type'] = ct |
192 res.setbodybytes(data) | 207 res.setbodybytes(data) |
195 raise ErrorResponse(HTTP_SERVER_ERROR, 'illegal filename') | 210 raise ErrorResponse(HTTP_SERVER_ERROR, 'illegal filename') |
196 except OSError as err: | 211 except OSError as err: |
197 if err.errno == errno.ENOENT: | 212 if err.errno == errno.ENOENT: |
198 raise ErrorResponse(HTTP_NOT_FOUND) | 213 raise ErrorResponse(HTTP_NOT_FOUND) |
199 else: | 214 else: |
200 raise ErrorResponse(HTTP_SERVER_ERROR, | 215 raise ErrorResponse( |
201 encoding.strtolocal(err.strerror)) | 216 HTTP_SERVER_ERROR, encoding.strtolocal(err.strerror) |
217 ) | |
218 | |
202 | 219 |
203 def paritygen(stripecount, offset=0): | 220 def paritygen(stripecount, offset=0): |
204 """count parity of horizontal stripes for easier reading""" | 221 """count parity of horizontal stripes for easier reading""" |
205 if stripecount and offset: | 222 if stripecount and offset: |
206 # account for offset, e.g. due to building the list in reverse | 223 # account for offset, e.g. due to building the list in reverse |
214 count += 1 | 231 count += 1 |
215 if stripecount and count >= stripecount: | 232 if stripecount and count >= stripecount: |
216 parity = 1 - parity | 233 parity = 1 - parity |
217 count = 0 | 234 count = 0 |
218 | 235 |
236 | |
219 def get_contact(config): | 237 def get_contact(config): |
220 """Return repo contact information or empty string. | 238 """Return repo contact information or empty string. |
221 | 239 |
222 web.contact is the primary source, but if that is not set, try | 240 web.contact is the primary source, but if that is not set, try |
223 ui.username or $EMAIL as a fallback to display something useful. | 241 ui.username or $EMAIL as a fallback to display something useful. |
224 """ | 242 """ |
225 return (config("web", "contact") or | 243 return ( |
226 config("ui", "username") or | 244 config("web", "contact") |
227 encoding.environ.get("EMAIL") or "") | 245 or config("ui", "username") |
246 or encoding.environ.get("EMAIL") | |
247 or "" | |
248 ) | |
249 | |
228 | 250 |
229 def cspvalues(ui): | 251 def cspvalues(ui): |
230 """Obtain the Content-Security-Policy header and nonce value. | 252 """Obtain the Content-Security-Policy header and nonce value. |
231 | 253 |
232 Returns a 2-tuple of the CSP header value and the nonce value. | 254 Returns a 2-tuple of the CSP header value and the nonce value. |