comparison mercurial/hgweb/hgweb_mod.py @ 43077:687b865b95ad

formatting: byteify all mercurial/ and hgext/ string literals Done with python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py') black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**') # skip-blame mass-reformatting only Differential Revision: https://phab.mercurial-scm.org/D6972
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:48:39 -0400
parents 2372284d9457
children c59eb1560c44
comparison
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
46 ) 46 )
47 47
48 48
49 def getstyle(req, configfn, templatepath): 49 def getstyle(req, configfn, templatepath):
50 styles = ( 50 styles = (
51 req.qsparams.get('style', None), 51 req.qsparams.get(b'style', None),
52 configfn('web', 'style'), 52 configfn(b'web', b'style'),
53 'paper', 53 b'paper',
54 ) 54 )
55 return styles, templater.stylemap(styles, templatepath) 55 return styles, templater.stylemap(styles, templatepath)
56 56
57 57
58 def makebreadcrumb(url, prefix=''): 58 def makebreadcrumb(url, prefix=b''):
59 '''Return a 'URL breadcrumb' list 59 '''Return a 'URL breadcrumb' list
60 60
61 A 'URL breadcrumb' is a list of URL-name pairs, 61 A 'URL breadcrumb' is a list of URL-name pairs,
62 corresponding to each of the path items on a URL. 62 corresponding to each of the path items on a URL.
63 This can be used to create path navigation entries. 63 This can be used to create path navigation entries.
64 ''' 64 '''
65 if url.endswith('/'): 65 if url.endswith(b'/'):
66 url = url[:-1] 66 url = url[:-1]
67 if prefix: 67 if prefix:
68 url = '/' + prefix + url 68 url = b'/' + prefix + url
69 relpath = url 69 relpath = url
70 if relpath.startswith('/'): 70 if relpath.startswith(b'/'):
71 relpath = relpath[1:] 71 relpath = relpath[1:]
72 72
73 breadcrumb = [] 73 breadcrumb = []
74 urlel = url 74 urlel = url
75 pathitems = [''] + relpath.split('/') 75 pathitems = [b''] + relpath.split(b'/')
76 for pathel in reversed(pathitems): 76 for pathel in reversed(pathitems):
77 if not pathel or not urlel: 77 if not pathel or not urlel:
78 break 78 break
79 breadcrumb.append({'url': urlel, 'name': pathel}) 79 breadcrumb.append({b'url': urlel, b'name': pathel})
80 urlel = os.path.dirname(urlel) 80 urlel = os.path.dirname(urlel)
81 return templateutil.mappinglist(reversed(breadcrumb)) 81 return templateutil.mappinglist(reversed(breadcrumb))
82 82
83 83
84 class requestcontext(object): 84 class requestcontext(object):
93 self.repo = repo 93 self.repo = repo
94 self.reponame = app.reponame 94 self.reponame = app.reponame
95 self.req = req 95 self.req = req
96 self.res = res 96 self.res = res
97 97
98 self.maxchanges = self.configint('web', 'maxchanges') 98 self.maxchanges = self.configint(b'web', b'maxchanges')
99 self.stripecount = self.configint('web', 'stripes') 99 self.stripecount = self.configint(b'web', b'stripes')
100 self.maxshortchanges = self.configint('web', 'maxshortchanges') 100 self.maxshortchanges = self.configint(b'web', b'maxshortchanges')
101 self.maxfiles = self.configint('web', 'maxfiles') 101 self.maxfiles = self.configint(b'web', b'maxfiles')
102 self.allowpull = self.configbool('web', 'allow-pull') 102 self.allowpull = self.configbool(b'web', b'allow-pull')
103 103
104 # we use untrusted=False to prevent a repo owner from using 104 # we use untrusted=False to prevent a repo owner from using
105 # web.templates in .hg/hgrc to get access to any file readable 105 # web.templates in .hg/hgrc to get access to any file readable
106 # by the user running the CGI script 106 # by the user running the CGI script
107 self.templatepath = self.config('web', 'templates', untrusted=False) 107 self.templatepath = self.config(b'web', b'templates', untrusted=False)
108 108
109 # This object is more expensive to build than simple config values. 109 # This object is more expensive to build than simple config values.
110 # It is shared across requests. The app will replace the object 110 # It is shared across requests. The app will replace the object
111 # if it is updated. Since this is a reference and nothing should 111 # if it is updated. Since this is a reference and nothing should
112 # modify the underlying object, it should be constant for the lifetime 112 # modify the underlying object, it should be constant for the lifetime
138 return webutil.archivelist(self.repo.ui, nodeid) 138 return webutil.archivelist(self.repo.ui, nodeid)
139 139
140 def templater(self, req): 140 def templater(self, req):
141 # determine scheme, port and server name 141 # determine scheme, port and server name
142 # this is needed to create absolute urls 142 # this is needed to create absolute urls
143 logourl = self.config('web', 'logourl') 143 logourl = self.config(b'web', b'logourl')
144 logoimg = self.config('web', 'logoimg') 144 logoimg = self.config(b'web', b'logoimg')
145 staticurl = ( 145 staticurl = (
146 self.config('web', 'staticurl') 146 self.config(b'web', b'staticurl')
147 or req.apppath.rstrip('/') + '/static/' 147 or req.apppath.rstrip(b'/') + b'/static/'
148 ) 148 )
149 if not staticurl.endswith('/'): 149 if not staticurl.endswith(b'/'):
150 staticurl += '/' 150 staticurl += b'/'
151 151
152 # figure out which style to use 152 # figure out which style to use
153 153
154 vars = {} 154 vars = {}
155 styles, (style, mapfile) = getstyle(req, self.config, self.templatepath) 155 styles, (style, mapfile) = getstyle(req, self.config, self.templatepath)
156 if style == styles[0]: 156 if style == styles[0]:
157 vars['style'] = style 157 vars[b'style'] = style
158 158
159 sessionvars = webutil.sessionvars(vars, '?') 159 sessionvars = webutil.sessionvars(vars, b'?')
160 160
161 if not self.reponame: 161 if not self.reponame:
162 self.reponame = ( 162 self.reponame = (
163 self.config('web', 'name', '') 163 self.config(b'web', b'name', b'')
164 or req.reponame 164 or req.reponame
165 or req.apppath 165 or req.apppath
166 or self.repo.root 166 or self.repo.root
167 ) 167 )
168 168
169 filters = {} 169 filters = {}
170 templatefilter = registrar.templatefilter(filters) 170 templatefilter = registrar.templatefilter(filters)
171 171
172 @templatefilter('websub', intype=bytes) 172 @templatefilter(b'websub', intype=bytes)
173 def websubfilter(text): 173 def websubfilter(text):
174 return templatefilters.websub(text, self.websubtable) 174 return templatefilters.websub(text, self.websubtable)
175 175
176 # create the templater 176 # create the templater
177 # TODO: export all keywords: defaults = templatekw.keywords.copy() 177 # TODO: export all keywords: defaults = templatekw.keywords.copy()
178 defaults = { 178 defaults = {
179 'url': req.apppath + '/', 179 b'url': req.apppath + b'/',
180 'logourl': logourl, 180 b'logourl': logourl,
181 'logoimg': logoimg, 181 b'logoimg': logoimg,
182 'staticurl': staticurl, 182 b'staticurl': staticurl,
183 'urlbase': req.advertisedbaseurl, 183 b'urlbase': req.advertisedbaseurl,
184 'repo': self.reponame, 184 b'repo': self.reponame,
185 'encoding': encoding.encoding, 185 b'encoding': encoding.encoding,
186 'sessionvars': sessionvars, 186 b'sessionvars': sessionvars,
187 'pathdef': makebreadcrumb(req.apppath), 187 b'pathdef': makebreadcrumb(req.apppath),
188 'style': style, 188 b'style': style,
189 'nonce': self.nonce, 189 b'nonce': self.nonce,
190 } 190 }
191 templatekeyword = registrar.templatekeyword(defaults) 191 templatekeyword = registrar.templatekeyword(defaults)
192 192
193 @templatekeyword('motd', requires=()) 193 @templatekeyword(b'motd', requires=())
194 def motd(context, mapping): 194 def motd(context, mapping):
195 yield self.config('web', 'motd') 195 yield self.config(b'web', b'motd')
196 196
197 tres = formatter.templateresources(self.repo.ui, self.repo) 197 tres = formatter.templateresources(self.repo.ui, self.repo)
198 tmpl = templater.templater.frommapfile( 198 tmpl = templater.templater.frommapfile(
199 mapfile, filters=filters, defaults=defaults, resources=tres 199 mapfile, filters=filters, defaults=defaults, resources=tres
200 ) 200 )
230 r = hg.repository(u, repo) 230 r = hg.repository(u, repo)
231 else: 231 else:
232 # we trust caller to give us a private copy 232 # we trust caller to give us a private copy
233 r = repo 233 r = repo
234 234
235 r.ui.setconfig('ui', 'report_untrusted', 'off', 'hgweb') 235 r.ui.setconfig(b'ui', b'report_untrusted', b'off', b'hgweb')
236 r.baseui.setconfig('ui', 'report_untrusted', 'off', 'hgweb') 236 r.baseui.setconfig(b'ui', b'report_untrusted', b'off', b'hgweb')
237 r.ui.setconfig('ui', 'nontty', 'true', 'hgweb') 237 r.ui.setconfig(b'ui', b'nontty', b'true', b'hgweb')
238 r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb') 238 r.baseui.setconfig(b'ui', b'nontty', b'true', b'hgweb')
239 # resolve file patterns relative to repo root 239 # resolve file patterns relative to repo root
240 r.ui.setconfig('ui', 'forcecwd', r.root, 'hgweb') 240 r.ui.setconfig(b'ui', b'forcecwd', r.root, b'hgweb')
241 r.baseui.setconfig('ui', 'forcecwd', r.root, 'hgweb') 241 r.baseui.setconfig(b'ui', b'forcecwd', r.root, b'hgweb')
242 # it's unlikely that we can replace signal handlers in WSGI server, 242 # it's unlikely that we can replace signal handlers in WSGI server,
243 # and mod_wsgi issues a big warning. a plain hgweb process (with no 243 # and mod_wsgi issues a big warning. a plain hgweb process (with no
244 # threading) could replace signal handlers, but we don't bother 244 # threading) could replace signal handlers, but we don't bother
245 # conditionally enabling it. 245 # conditionally enabling it.
246 r.ui.setconfig('ui', 'signal-safe-lock', 'false', 'hgweb') 246 r.ui.setconfig(b'ui', b'signal-safe-lock', b'false', b'hgweb')
247 r.baseui.setconfig('ui', 'signal-safe-lock', 'false', 'hgweb') 247 r.baseui.setconfig(b'ui', b'signal-safe-lock', b'false', b'hgweb')
248 # displaying bundling progress bar while serving feel wrong and may 248 # displaying bundling progress bar while serving feel wrong and may
249 # break some wsgi implementation. 249 # break some wsgi implementation.
250 r.ui.setconfig('progress', 'disable', 'true', 'hgweb') 250 r.ui.setconfig(b'progress', b'disable', b'true', b'hgweb')
251 r.baseui.setconfig('progress', 'disable', 'true', 'hgweb') 251 r.baseui.setconfig(b'progress', b'disable', b'true', b'hgweb')
252 self._repos = [hg.cachedlocalrepo(self._webifyrepo(r))] 252 self._repos = [hg.cachedlocalrepo(self._webifyrepo(r))]
253 self._lastrepo = self._repos[0] 253 self._lastrepo = self._repos[0]
254 hook.redirect(True) 254 hook.redirect(True)
255 self.reponame = name 255 self.reponame = name
256 256
292 """Start a server from CGI environment. 292 """Start a server from CGI environment.
293 293
294 Modern servers should be using WSGI and should avoid this 294 Modern servers should be using WSGI and should avoid this
295 method, if possible. 295 method, if possible.
296 """ 296 """
297 if not encoding.environ.get('GATEWAY_INTERFACE', '').startswith( 297 if not encoding.environ.get(b'GATEWAY_INTERFACE', b'').startswith(
298 "CGI/1." 298 b"CGI/1."
299 ): 299 ):
300 raise RuntimeError( 300 raise RuntimeError(
301 "This function is only intended to be " 301 b"This function is only intended to be "
302 "called while running as a CGI script." 302 b"called while running as a CGI script."
303 ) 303 )
304 wsgicgi.launch(self) 304 wsgicgi.launch(self)
305 305
306 def __call__(self, env, respond): 306 def __call__(self, env, respond):
307 """Run the WSGI application. 307 """Run the WSGI application.
318 318
319 This is typically only called by Mercurial. External consumers 319 This is typically only called by Mercurial. External consumers
320 should be using instances of this class as the WSGI application. 320 should be using instances of this class as the WSGI application.
321 """ 321 """
322 with self._obtainrepo() as repo: 322 with self._obtainrepo() as repo:
323 profile = repo.ui.configbool('profiling', 'enabled') 323 profile = repo.ui.configbool(b'profiling', b'enabled')
324 with profiling.profile(repo.ui, enabled=profile): 324 with profiling.profile(repo.ui, enabled=profile):
325 for r in self._runwsgi(req, res, repo): 325 for r in self._runwsgi(req, res, repo):
326 yield r 326 yield r
327 327
328 def _runwsgi(self, req, res, repo): 328 def _runwsgi(self, req, res, repo):
329 rctx = requestcontext(self, repo, req, res) 329 rctx = requestcontext(self, repo, req, res)
330 330
331 # This state is global across all threads. 331 # This state is global across all threads.
332 encoding.encoding = rctx.config('web', 'encoding') 332 encoding.encoding = rctx.config(b'web', b'encoding')
333 rctx.repo.ui.environ = req.rawenv 333 rctx.repo.ui.environ = req.rawenv
334 334
335 if rctx.csp: 335 if rctx.csp:
336 # hgwebdir may have added CSP header. Since we generate our own, 336 # hgwebdir may have added CSP header. Since we generate our own,
337 # replace it. 337 # replace it.
338 res.headers['Content-Security-Policy'] = rctx.csp 338 res.headers[b'Content-Security-Policy'] = rctx.csp
339 339
340 # /api/* is reserved for various API implementations. Dispatch 340 # /api/* is reserved for various API implementations. Dispatch
341 # accordingly. But URL paths can conflict with subrepos and virtual 341 # accordingly. But URL paths can conflict with subrepos and virtual
342 # repos in hgwebdir. So until we have a workaround for this, only 342 # repos in hgwebdir. So until we have a workaround for this, only
343 # expose the URLs if the feature is enabled. 343 # expose the URLs if the feature is enabled.
344 apienabled = rctx.repo.ui.configbool('experimental', 'web.apiserver') 344 apienabled = rctx.repo.ui.configbool(b'experimental', b'web.apiserver')
345 if apienabled and req.dispatchparts and req.dispatchparts[0] == b'api': 345 if apienabled and req.dispatchparts and req.dispatchparts[0] == b'api':
346 wireprotoserver.handlewsgiapirequest( 346 wireprotoserver.handlewsgiapirequest(
347 rctx, req, res, self.check_perm 347 rctx, req, res, self.check_perm
348 ) 348 )
349 return res.sendresponse() 349 return res.sendresponse()
359 # If PATH_INFO is present (signaled by ``req.dispatchpath`` having 359 # If PATH_INFO is present (signaled by ``req.dispatchpath`` having
360 # a value), we use it. Otherwise fall back to the query string. 360 # a value), we use it. Otherwise fall back to the query string.
361 if req.dispatchpath is not None: 361 if req.dispatchpath is not None:
362 query = req.dispatchpath 362 query = req.dispatchpath
363 else: 363 else:
364 query = req.querystring.partition('&')[0].partition(';')[0] 364 query = req.querystring.partition(b'&')[0].partition(b';')[0]
365 365
366 # translate user-visible url structure to internal structure 366 # translate user-visible url structure to internal structure
367 367
368 args = query.split('/', 2) 368 args = query.split(b'/', 2)
369 if 'cmd' not in req.qsparams and args and args[0]: 369 if b'cmd' not in req.qsparams and args and args[0]:
370 cmd = args.pop(0) 370 cmd = args.pop(0)
371 style = cmd.rfind('-') 371 style = cmd.rfind(b'-')
372 if style != -1: 372 if style != -1:
373 req.qsparams['style'] = cmd[:style] 373 req.qsparams[b'style'] = cmd[:style]
374 cmd = cmd[style + 1 :] 374 cmd = cmd[style + 1 :]
375 375
376 # avoid accepting e.g. style parameter as command 376 # avoid accepting e.g. style parameter as command
377 if util.safehasattr(webcommands, cmd): 377 if util.safehasattr(webcommands, cmd):
378 req.qsparams['cmd'] = cmd 378 req.qsparams[b'cmd'] = cmd
379 379
380 if cmd == 'static': 380 if cmd == b'static':
381 req.qsparams['file'] = '/'.join(args) 381 req.qsparams[b'file'] = b'/'.join(args)
382 else: 382 else:
383 if args and args[0]: 383 if args and args[0]:
384 node = args.pop(0).replace('%2F', '/') 384 node = args.pop(0).replace(b'%2F', b'/')
385 req.qsparams['node'] = node 385 req.qsparams[b'node'] = node
386 if args: 386 if args:
387 if 'file' in req.qsparams: 387 if b'file' in req.qsparams:
388 del req.qsparams['file'] 388 del req.qsparams[b'file']
389 for a in args: 389 for a in args:
390 req.qsparams.add('file', a) 390 req.qsparams.add(b'file', a)
391 391
392 ua = req.headers.get('User-Agent', '') 392 ua = req.headers.get(b'User-Agent', b'')
393 if cmd == 'rev' and 'mercurial' in ua: 393 if cmd == b'rev' and b'mercurial' in ua:
394 req.qsparams['style'] = 'raw' 394 req.qsparams[b'style'] = b'raw'
395 395
396 if cmd == 'archive': 396 if cmd == b'archive':
397 fn = req.qsparams['node'] 397 fn = req.qsparams[b'node']
398 for type_, spec in webutil.archivespecs.iteritems(): 398 for type_, spec in webutil.archivespecs.iteritems():
399 ext = spec[2] 399 ext = spec[2]
400 if fn.endswith(ext): 400 if fn.endswith(ext):
401 req.qsparams['node'] = fn[: -len(ext)] 401 req.qsparams[b'node'] = fn[: -len(ext)]
402 req.qsparams['type'] = type_ 402 req.qsparams[b'type'] = type_
403 else: 403 else:
404 cmd = req.qsparams.get('cmd', '') 404 cmd = req.qsparams.get(b'cmd', b'')
405 405
406 # process the web interface request 406 # process the web interface request
407 407
408 try: 408 try:
409 rctx.tmpl = rctx.templater(req) 409 rctx.tmpl = rctx.templater(req)
410 ctype = rctx.tmpl.render( 410 ctype = rctx.tmpl.render(
411 'mimetype', {'encoding': encoding.encoding} 411 b'mimetype', {b'encoding': encoding.encoding}
412 ) 412 )
413 413
414 # check read permissions non-static content 414 # check read permissions non-static content
415 if cmd != 'static': 415 if cmd != b'static':
416 self.check_perm(rctx, req, None) 416 self.check_perm(rctx, req, None)
417 417
418 if cmd == '': 418 if cmd == b'':
419 req.qsparams['cmd'] = rctx.tmpl.render('default', {}) 419 req.qsparams[b'cmd'] = rctx.tmpl.render(b'default', {})
420 cmd = req.qsparams['cmd'] 420 cmd = req.qsparams[b'cmd']
421 421
422 # Don't enable caching if using a CSP nonce because then it wouldn't 422 # Don't enable caching if using a CSP nonce because then it wouldn't
423 # be a nonce. 423 # be a nonce.
424 if rctx.configbool('web', 'cache') and not rctx.nonce: 424 if rctx.configbool(b'web', b'cache') and not rctx.nonce:
425 tag = 'W/"%d"' % self.mtime 425 tag = b'W/"%d"' % self.mtime
426 if req.headers.get('If-None-Match') == tag: 426 if req.headers.get(b'If-None-Match') == tag:
427 res.status = '304 Not Modified' 427 res.status = b'304 Not Modified'
428 # Content-Type may be defined globally. It isn't valid on a 428 # Content-Type may be defined globally. It isn't valid on a
429 # 304, so discard it. 429 # 304, so discard it.
430 try: 430 try:
431 del res.headers[b'Content-Type'] 431 del res.headers[b'Content-Type']
432 except KeyError: 432 except KeyError:
433 pass 433 pass
434 # Response body not allowed on 304. 434 # Response body not allowed on 304.
435 res.setbodybytes('') 435 res.setbodybytes(b'')
436 return res.sendresponse() 436 return res.sendresponse()
437 437
438 res.headers['ETag'] = tag 438 res.headers[b'ETag'] = tag
439 439
440 if cmd not in webcommands.__all__: 440 if cmd not in webcommands.__all__:
441 msg = 'no such method: %s' % cmd 441 msg = b'no such method: %s' % cmd
442 raise ErrorResponse(HTTP_BAD_REQUEST, msg) 442 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
443 else: 443 else:
444 # Set some globals appropriate for web handlers. Commands can 444 # Set some globals appropriate for web handlers. Commands can
445 # override easily enough. 445 # override easily enough.
446 res.status = '200 Script output follows' 446 res.status = b'200 Script output follows'
447 res.headers['Content-Type'] = ctype 447 res.headers[b'Content-Type'] = ctype
448 return getattr(webcommands, cmd)(rctx) 448 return getattr(webcommands, cmd)(rctx)
449 449
450 except (error.LookupError, error.RepoLookupError) as err: 450 except (error.LookupError, error.RepoLookupError) as err:
451 msg = pycompat.bytestr(err) 451 msg = pycompat.bytestr(err)
452 if util.safehasattr(err, 'name') and not isinstance( 452 if util.safehasattr(err, b'name') and not isinstance(
453 err, error.ManifestLookupError 453 err, error.ManifestLookupError
454 ): 454 ):
455 msg = 'revision not found: %s' % err.name 455 msg = b'revision not found: %s' % err.name
456 456
457 res.status = '404 Not Found' 457 res.status = b'404 Not Found'
458 res.headers['Content-Type'] = ctype 458 res.headers[b'Content-Type'] = ctype
459 return rctx.sendtemplate('error', error=msg) 459 return rctx.sendtemplate(b'error', error=msg)
460 except (error.RepoError, error.StorageError) as e: 460 except (error.RepoError, error.StorageError) as e:
461 res.status = '500 Internal Server Error' 461 res.status = b'500 Internal Server Error'
462 res.headers['Content-Type'] = ctype 462 res.headers[b'Content-Type'] = ctype
463 return rctx.sendtemplate('error', error=pycompat.bytestr(e)) 463 return rctx.sendtemplate(b'error', error=pycompat.bytestr(e))
464 except error.Abort as e: 464 except error.Abort as e:
465 res.status = '403 Forbidden' 465 res.status = b'403 Forbidden'
466 res.headers['Content-Type'] = ctype 466 res.headers[b'Content-Type'] = ctype
467 return rctx.sendtemplate('error', error=pycompat.bytestr(e)) 467 return rctx.sendtemplate(b'error', error=pycompat.bytestr(e))
468 except ErrorResponse as e: 468 except ErrorResponse as e:
469 for k, v in e.headers: 469 for k, v in e.headers:
470 res.headers[k] = v 470 res.headers[k] = v
471 res.status = statusmessage(e.code, pycompat.bytestr(e)) 471 res.status = statusmessage(e.code, pycompat.bytestr(e))
472 res.headers['Content-Type'] = ctype 472 res.headers[b'Content-Type'] = ctype
473 return rctx.sendtemplate('error', error=pycompat.bytestr(e)) 473 return rctx.sendtemplate(b'error', error=pycompat.bytestr(e))
474 474
475 def check_perm(self, rctx, req, op): 475 def check_perm(self, rctx, req, op):
476 for permhook in permhooks: 476 for permhook in permhooks:
477 permhook(rctx, req, op) 477 permhook(rctx, req, op)
478 478
487 See the repoview module for details. 487 See the repoview module for details.
488 488
489 The option has been around undocumented since Mercurial 2.5, but no 489 The option has been around undocumented since Mercurial 2.5, but no
490 user ever asked about it. So we better keep it undocumented for now.""" 490 user ever asked about it. So we better keep it undocumented for now."""
491 # experimental config: web.view 491 # experimental config: web.view
492 viewconfig = repo.ui.config('web', 'view', untrusted=True) 492 viewconfig = repo.ui.config(b'web', b'view', untrusted=True)
493 if viewconfig == 'all': 493 if viewconfig == b'all':
494 return repo.unfiltered() 494 return repo.unfiltered()
495 elif viewconfig in repoview.filtertable: 495 elif viewconfig in repoview.filtertable:
496 return repo.filtered(viewconfig) 496 return repo.filtered(viewconfig)
497 else: 497 else:
498 return repo.filtered('served') 498 return repo.filtered(b'served')