##// END OF EJS Templates
configitems: register the 'web.accesslog' config
Boris Feld -
r34224:ac96ff47 default
parent child Browse files
Show More
@@ -1,601 +1,604
1 1 # configitems.py - centralized declaration of configuration option
2 2 #
3 3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import functools
11 11
12 12 from . import (
13 13 error,
14 14 )
15 15
16 16 def loadconfigtable(ui, extname, configtable):
17 17 """update config item known to the ui with the extension ones"""
18 18 for section, items in configtable.items():
19 19 knownitems = ui._knownconfig.setdefault(section, {})
20 20 knownkeys = set(knownitems)
21 21 newkeys = set(items)
22 22 for key in sorted(knownkeys & newkeys):
23 23 msg = "extension '%s' overwrite config item '%s.%s'"
24 24 msg %= (extname, section, key)
25 25 ui.develwarn(msg, config='warn-config')
26 26
27 27 knownitems.update(items)
28 28
29 29 class configitem(object):
30 30 """represent a known config item
31 31
32 32 :section: the official config section where to find this item,
33 33 :name: the official name within the section,
34 34 :default: default value for this item,
35 35 :alias: optional list of tuples as alternatives.
36 36 """
37 37
38 38 def __init__(self, section, name, default=None, alias=()):
39 39 self.section = section
40 40 self.name = name
41 41 self.default = default
42 42 self.alias = list(alias)
43 43
44 44 coreitems = {}
45 45
46 46 def _register(configtable, *args, **kwargs):
47 47 item = configitem(*args, **kwargs)
48 48 section = configtable.setdefault(item.section, {})
49 49 if item.name in section:
50 50 msg = "duplicated config item registration for '%s.%s'"
51 51 raise error.ProgrammingError(msg % (item.section, item.name))
52 52 section[item.name] = item
53 53
54 54 # special value for case where the default is derived from other values
55 55 dynamicdefault = object()
56 56
57 57 # Registering actual config items
58 58
59 59 def getitemregister(configtable):
60 60 return functools.partial(_register, configtable)
61 61
62 62 coreconfigitem = getitemregister(coreitems)
63 63
64 64 coreconfigitem('auth', 'cookiefile',
65 65 default=None,
66 66 )
67 67 # bookmarks.pushing: internal hack for discovery
68 68 coreconfigitem('bookmarks', 'pushing',
69 69 default=list,
70 70 )
71 71 # bundle.mainreporoot: internal hack for bundlerepo
72 72 coreconfigitem('bundle', 'mainreporoot',
73 73 default='',
74 74 )
75 75 # bundle.reorder: experimental config
76 76 coreconfigitem('bundle', 'reorder',
77 77 default='auto',
78 78 )
79 79 coreconfigitem('censor', 'policy',
80 80 default='abort',
81 81 )
82 82 coreconfigitem('chgserver', 'idletimeout',
83 83 default=3600,
84 84 )
85 85 coreconfigitem('chgserver', 'skiphash',
86 86 default=False,
87 87 )
88 88 coreconfigitem('cmdserver', 'log',
89 89 default=None,
90 90 )
91 91 coreconfigitem('color', 'mode',
92 92 default='auto',
93 93 )
94 94 coreconfigitem('color', 'pagermode',
95 95 default=dynamicdefault,
96 96 )
97 97 coreconfigitem('commands', 'status.relative',
98 98 default=False,
99 99 )
100 100 coreconfigitem('commands', 'status.skipstates',
101 101 default=[],
102 102 )
103 103 coreconfigitem('commands', 'status.verbose',
104 104 default=False,
105 105 )
106 106 coreconfigitem('commands', 'update.requiredest',
107 107 default=False,
108 108 )
109 109 coreconfigitem('devel', 'all-warnings',
110 110 default=False,
111 111 )
112 112 coreconfigitem('devel', 'bundle2.debug',
113 113 default=False,
114 114 )
115 115 coreconfigitem('devel', 'check-locks',
116 116 default=False,
117 117 )
118 118 coreconfigitem('devel', 'check-relroot',
119 119 default=False,
120 120 )
121 121 coreconfigitem('devel', 'default-date',
122 122 default=None,
123 123 )
124 124 coreconfigitem('devel', 'deprec-warn',
125 125 default=False,
126 126 )
127 127 coreconfigitem('devel', 'disableloaddefaultcerts',
128 128 default=False,
129 129 )
130 130 coreconfigitem('devel', 'legacy.exchange',
131 131 default=list,
132 132 )
133 133 coreconfigitem('devel', 'servercafile',
134 134 default='',
135 135 )
136 136 coreconfigitem('devel', 'serverexactprotocol',
137 137 default='',
138 138 )
139 139 coreconfigitem('devel', 'serverrequirecert',
140 140 default=False,
141 141 )
142 142 coreconfigitem('devel', 'strip-obsmarkers',
143 143 default=True,
144 144 )
145 145 coreconfigitem('email', 'charsets',
146 146 default=list,
147 147 )
148 148 coreconfigitem('email', 'method',
149 149 default='smtp',
150 150 )
151 151 coreconfigitem('experimental', 'bundle-phases',
152 152 default=False,
153 153 )
154 154 coreconfigitem('experimental', 'bundle2-advertise',
155 155 default=True,
156 156 )
157 157 coreconfigitem('experimental', 'bundle2-output-capture',
158 158 default=False,
159 159 )
160 160 coreconfigitem('experimental', 'bundle2.pushback',
161 161 default=False,
162 162 )
163 163 coreconfigitem('experimental', 'bundle2lazylocking',
164 164 default=False,
165 165 )
166 166 coreconfigitem('experimental', 'bundlecomplevel',
167 167 default=None,
168 168 )
169 169 coreconfigitem('experimental', 'changegroup3',
170 170 default=False,
171 171 )
172 172 coreconfigitem('experimental', 'clientcompressionengines',
173 173 default=list,
174 174 )
175 175 coreconfigitem('experimental', 'copytrace',
176 176 default='on',
177 177 )
178 178 coreconfigitem('experimental', 'crecordtest',
179 179 default=None,
180 180 )
181 181 coreconfigitem('experimental', 'editortmpinhg',
182 182 default=False,
183 183 )
184 184 coreconfigitem('experimental', 'stabilization',
185 185 default=list,
186 186 alias=[('experimental', 'evolution')],
187 187 )
188 188 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
189 189 default=False,
190 190 alias=[('experimental', 'evolution.bundle-obsmarker')],
191 191 )
192 192 coreconfigitem('experimental', 'stabilization.track-operation',
193 193 default=False,
194 194 alias=[('experimental', 'evolution.track-operation')]
195 195 )
196 196 coreconfigitem('experimental', 'exportableenviron',
197 197 default=list,
198 198 )
199 199 coreconfigitem('experimental', 'extendedheader.index',
200 200 default=None,
201 201 )
202 202 coreconfigitem('experimental', 'extendedheader.similarity',
203 203 default=False,
204 204 )
205 205 coreconfigitem('experimental', 'format.compression',
206 206 default='zlib',
207 207 )
208 208 coreconfigitem('experimental', 'graphshorten',
209 209 default=False,
210 210 )
211 211 coreconfigitem('experimental', 'hook-track-tags',
212 212 default=False,
213 213 )
214 214 coreconfigitem('experimental', 'httppostargs',
215 215 default=False,
216 216 )
217 217 coreconfigitem('experimental', 'manifestv2',
218 218 default=False,
219 219 )
220 220 coreconfigitem('experimental', 'mergedriver',
221 221 default=None,
222 222 )
223 223 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
224 224 default=False,
225 225 )
226 226 coreconfigitem('experimental', 'rebase.multidest',
227 227 default=False,
228 228 )
229 229 coreconfigitem('experimental', 'revertalternateinteractivemode',
230 230 default=True,
231 231 )
232 232 coreconfigitem('experimental', 'revlogv2',
233 233 default=None,
234 234 )
235 235 coreconfigitem('experimental', 'spacemovesdown',
236 236 default=False,
237 237 )
238 238 coreconfigitem('experimental', 'treemanifest',
239 239 default=False,
240 240 )
241 241 coreconfigitem('experimental', 'updatecheck',
242 242 default=None,
243 243 )
244 244 coreconfigitem('format', 'aggressivemergedeltas',
245 245 default=False,
246 246 )
247 247 coreconfigitem('format', 'chunkcachesize',
248 248 default=None,
249 249 )
250 250 coreconfigitem('format', 'dotencode',
251 251 default=True,
252 252 )
253 253 coreconfigitem('format', 'generaldelta',
254 254 default=False,
255 255 )
256 256 coreconfigitem('format', 'manifestcachesize',
257 257 default=None,
258 258 )
259 259 coreconfigitem('format', 'maxchainlen',
260 260 default=None,
261 261 )
262 262 coreconfigitem('format', 'obsstore-version',
263 263 default=None,
264 264 )
265 265 coreconfigitem('format', 'usefncache',
266 266 default=True,
267 267 )
268 268 coreconfigitem('format', 'usegeneraldelta',
269 269 default=True,
270 270 )
271 271 coreconfigitem('format', 'usestore',
272 272 default=True,
273 273 )
274 274 coreconfigitem('hostsecurity', 'ciphers',
275 275 default=None,
276 276 )
277 277 coreconfigitem('hostsecurity', 'disabletls10warning',
278 278 default=False,
279 279 )
280 280 coreconfigitem('http_proxy', 'always',
281 281 default=False,
282 282 )
283 283 coreconfigitem('http_proxy', 'host',
284 284 default=None,
285 285 )
286 286 coreconfigitem('http_proxy', 'no',
287 287 default=list,
288 288 )
289 289 coreconfigitem('http_proxy', 'passwd',
290 290 default=None,
291 291 )
292 292 coreconfigitem('http_proxy', 'user',
293 293 default=None,
294 294 )
295 295 coreconfigitem('merge', 'followcopies',
296 296 default=True,
297 297 )
298 298 coreconfigitem('pager', 'ignore',
299 299 default=list,
300 300 )
301 301 coreconfigitem('patch', 'eol',
302 302 default='strict',
303 303 )
304 304 coreconfigitem('patch', 'fuzz',
305 305 default=2,
306 306 )
307 307 coreconfigitem('paths', 'default',
308 308 default=None,
309 309 )
310 310 coreconfigitem('paths', 'default-push',
311 311 default=None,
312 312 )
313 313 coreconfigitem('phases', 'checksubrepos',
314 314 default='follow',
315 315 )
316 316 coreconfigitem('phases', 'publish',
317 317 default=True,
318 318 )
319 319 coreconfigitem('profiling', 'enabled',
320 320 default=False,
321 321 )
322 322 coreconfigitem('profiling', 'format',
323 323 default='text',
324 324 )
325 325 coreconfigitem('profiling', 'freq',
326 326 default=1000,
327 327 )
328 328 coreconfigitem('profiling', 'limit',
329 329 default=30,
330 330 )
331 331 coreconfigitem('profiling', 'nested',
332 332 default=0,
333 333 )
334 334 coreconfigitem('profiling', 'sort',
335 335 default='inlinetime',
336 336 )
337 337 coreconfigitem('profiling', 'statformat',
338 338 default='hotpath',
339 339 )
340 340 coreconfigitem('progress', 'assume-tty',
341 341 default=False,
342 342 )
343 343 coreconfigitem('progress', 'changedelay',
344 344 default=1,
345 345 )
346 346 coreconfigitem('progress', 'clear-complete',
347 347 default=True,
348 348 )
349 349 coreconfigitem('progress', 'debug',
350 350 default=False,
351 351 )
352 352 coreconfigitem('progress', 'delay',
353 353 default=3,
354 354 )
355 355 coreconfigitem('progress', 'disable',
356 356 default=False,
357 357 )
358 358 coreconfigitem('progress', 'estimate',
359 359 default=2,
360 360 )
361 361 coreconfigitem('progress', 'refresh',
362 362 default=0.1,
363 363 )
364 364 coreconfigitem('progress', 'width',
365 365 default=dynamicdefault,
366 366 )
367 367 coreconfigitem('push', 'pushvars.server',
368 368 default=False,
369 369 )
370 370 coreconfigitem('server', 'bundle1',
371 371 default=True,
372 372 )
373 373 coreconfigitem('server', 'bundle1gd',
374 374 default=None,
375 375 )
376 376 coreconfigitem('server', 'compressionengines',
377 377 default=list,
378 378 )
379 379 coreconfigitem('server', 'concurrent-push-mode',
380 380 default='strict',
381 381 )
382 382 coreconfigitem('server', 'disablefullbundle',
383 383 default=False,
384 384 )
385 385 coreconfigitem('server', 'maxhttpheaderlen',
386 386 default=1024,
387 387 )
388 388 coreconfigitem('server', 'preferuncompressed',
389 389 default=False,
390 390 )
391 391 coreconfigitem('server', 'uncompressed',
392 392 default=True,
393 393 )
394 394 coreconfigitem('server', 'uncompressedallowsecret',
395 395 default=False,
396 396 )
397 397 coreconfigitem('server', 'validate',
398 398 default=False,
399 399 )
400 400 coreconfigitem('server', 'zliblevel',
401 401 default=-1,
402 402 )
403 403 coreconfigitem('smtp', 'host',
404 404 default=None,
405 405 )
406 406 coreconfigitem('smtp', 'local_hostname',
407 407 default=None,
408 408 )
409 409 coreconfigitem('smtp', 'password',
410 410 default=None,
411 411 )
412 412 coreconfigitem('smtp', 'tls',
413 413 default='none',
414 414 )
415 415 coreconfigitem('smtp', 'username',
416 416 default=None,
417 417 )
418 418 coreconfigitem('sparse', 'missingwarning',
419 419 default=True,
420 420 )
421 421 coreconfigitem('trusted', 'groups',
422 422 default=list,
423 423 )
424 424 coreconfigitem('trusted', 'users',
425 425 default=list,
426 426 )
427 427 coreconfigitem('ui', '_usedassubrepo',
428 428 default=False,
429 429 )
430 430 coreconfigitem('ui', 'allowemptycommit',
431 431 default=False,
432 432 )
433 433 coreconfigitem('ui', 'archivemeta',
434 434 default=True,
435 435 )
436 436 coreconfigitem('ui', 'askusername',
437 437 default=False,
438 438 )
439 439 coreconfigitem('ui', 'clonebundlefallback',
440 440 default=False,
441 441 )
442 442 coreconfigitem('ui', 'clonebundleprefers',
443 443 default=list,
444 444 )
445 445 coreconfigitem('ui', 'clonebundles',
446 446 default=True,
447 447 )
448 448 coreconfigitem('ui', 'color',
449 449 default='auto',
450 450 )
451 451 coreconfigitem('ui', 'commitsubrepos',
452 452 default=False,
453 453 )
454 454 coreconfigitem('ui', 'debug',
455 455 default=False,
456 456 )
457 457 coreconfigitem('ui', 'debugger',
458 458 default=None,
459 459 )
460 460 coreconfigitem('ui', 'fallbackencoding',
461 461 default=None,
462 462 )
463 463 coreconfigitem('ui', 'forcecwd',
464 464 default=None,
465 465 )
466 466 coreconfigitem('ui', 'forcemerge',
467 467 default=None,
468 468 )
469 469 coreconfigitem('ui', 'formatdebug',
470 470 default=False,
471 471 )
472 472 coreconfigitem('ui', 'formatjson',
473 473 default=False,
474 474 )
475 475 coreconfigitem('ui', 'formatted',
476 476 default=None,
477 477 )
478 478 coreconfigitem('ui', 'graphnodetemplate',
479 479 default=None,
480 480 )
481 481 coreconfigitem('ui', 'http2debuglevel',
482 482 default=None,
483 483 )
484 484 coreconfigitem('ui', 'interactive',
485 485 default=None,
486 486 )
487 487 coreconfigitem('ui', 'interface',
488 488 default=None,
489 489 )
490 490 coreconfigitem('ui', 'logblockedtimes',
491 491 default=False,
492 492 )
493 493 coreconfigitem('ui', 'logtemplate',
494 494 default=None,
495 495 )
496 496 coreconfigitem('ui', 'merge',
497 497 default=None,
498 498 )
499 499 coreconfigitem('ui', 'mergemarkers',
500 500 default='basic',
501 501 )
502 502 coreconfigitem('ui', 'mergemarkertemplate',
503 503 default=('{node|short} '
504 504 '{ifeq(tags, "tip", "", '
505 505 'ifeq(tags, "", "", "{tags} "))}'
506 506 '{if(bookmarks, "{bookmarks} ")}'
507 507 '{ifeq(branch, "default", "", "{branch} ")}'
508 508 '- {author|user}: {desc|firstline}')
509 509 )
510 510 coreconfigitem('ui', 'nontty',
511 511 default=False,
512 512 )
513 513 coreconfigitem('ui', 'origbackuppath',
514 514 default=None,
515 515 )
516 516 coreconfigitem('ui', 'paginate',
517 517 default=True,
518 518 )
519 519 coreconfigitem('ui', 'patch',
520 520 default=None,
521 521 )
522 522 coreconfigitem('ui', 'portablefilenames',
523 523 default='warn',
524 524 )
525 525 coreconfigitem('ui', 'promptecho',
526 526 default=False,
527 527 )
528 528 coreconfigitem('ui', 'quiet',
529 529 default=False,
530 530 )
531 531 coreconfigitem('ui', 'quietbookmarkmove',
532 532 default=False,
533 533 )
534 534 coreconfigitem('ui', 'remotecmd',
535 535 default='hg',
536 536 )
537 537 coreconfigitem('ui', 'report_untrusted',
538 538 default=True,
539 539 )
540 540 coreconfigitem('ui', 'rollback',
541 541 default=True,
542 542 )
543 543 coreconfigitem('ui', 'slash',
544 544 default=False,
545 545 )
546 546 coreconfigitem('ui', 'ssh',
547 547 default='ssh',
548 548 )
549 549 coreconfigitem('ui', 'statuscopies',
550 550 default=False,
551 551 )
552 552 coreconfigitem('ui', 'strict',
553 553 default=False,
554 554 )
555 555 coreconfigitem('ui', 'style',
556 556 default='',
557 557 )
558 558 coreconfigitem('ui', 'supportcontact',
559 559 default=None,
560 560 )
561 561 coreconfigitem('ui', 'textwidth',
562 562 default=78,
563 563 )
564 564 coreconfigitem('ui', 'timeout',
565 565 default='600',
566 566 )
567 567 coreconfigitem('ui', 'traceback',
568 568 default=False,
569 569 )
570 570 coreconfigitem('ui', 'tweakdefaults',
571 571 default=False,
572 572 )
573 573 coreconfigitem('ui', 'usehttp2',
574 574 default=False,
575 575 )
576 576 coreconfigitem('ui', 'username',
577 577 alias=[('ui', 'user')]
578 578 )
579 579 coreconfigitem('ui', 'verbose',
580 580 default=False,
581 581 )
582 582 coreconfigitem('verify', 'skipflags',
583 583 default=None,
584 584 )
585 coreconfigitem('web', 'accesslog',
586 default='-',
587 )
585 588 coreconfigitem('worker', 'backgroundclose',
586 589 default=dynamicdefault,
587 590 )
588 591 # Windows defaults to a limit of 512 open files. A buffer of 128
589 592 # should give us enough headway.
590 593 coreconfigitem('worker', 'backgroundclosemaxqueue',
591 594 default=384,
592 595 )
593 596 coreconfigitem('worker', 'backgroundcloseminfilecount',
594 597 default=2048,
595 598 )
596 599 coreconfigitem('worker', 'backgroundclosethreadcount',
597 600 default=4,
598 601 )
599 602 coreconfigitem('worker', 'numcpus',
600 603 default=None,
601 604 )
@@ -1,335 +1,335
1 1 # hgweb/server.py - The standalone hg web server.
2 2 #
3 3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from __future__ import absolute_import
10 10
11 11 import errno
12 12 import os
13 13 import socket
14 14 import sys
15 15 import traceback
16 16
17 17 from ..i18n import _
18 18
19 19 from .. import (
20 20 error,
21 21 pycompat,
22 22 util,
23 23 )
24 24
25 25 httpservermod = util.httpserver
26 26 socketserver = util.socketserver
27 27 urlerr = util.urlerr
28 28 urlreq = util.urlreq
29 29
30 30 from . import (
31 31 common,
32 32 )
33 33
34 34 def _splitURI(uri):
35 35 """Return path and query that has been split from uri
36 36
37 37 Just like CGI environment, the path is unquoted, the query is
38 38 not.
39 39 """
40 40 if '?' in uri:
41 41 path, query = uri.split('?', 1)
42 42 else:
43 43 path, query = uri, ''
44 44 return urlreq.unquote(path), query
45 45
46 46 class _error_logger(object):
47 47 def __init__(self, handler):
48 48 self.handler = handler
49 49 def flush(self):
50 50 pass
51 51 def write(self, str):
52 52 self.writelines(str.split('\n'))
53 53 def writelines(self, seq):
54 54 for msg in seq:
55 55 self.handler.log_error("HG error: %s", msg)
56 56
57 57 class _httprequesthandler(httpservermod.basehttprequesthandler):
58 58
59 59 url_scheme = 'http'
60 60
61 61 @staticmethod
62 62 def preparehttpserver(httpserver, ui):
63 63 """Prepare .socket of new HTTPServer instance"""
64 64 pass
65 65
66 66 def __init__(self, *args, **kargs):
67 67 self.protocol_version = 'HTTP/1.1'
68 68 httpservermod.basehttprequesthandler.__init__(self, *args, **kargs)
69 69
70 70 def _log_any(self, fp, format, *args):
71 71 fp.write("%s - - [%s] %s\n" % (self.client_address[0],
72 72 self.log_date_time_string(),
73 73 format % args))
74 74 fp.flush()
75 75
76 76 def log_error(self, format, *args):
77 77 self._log_any(self.server.errorlog, format, *args)
78 78
79 79 def log_message(self, format, *args):
80 80 self._log_any(self.server.accesslog, format, *args)
81 81
82 82 def log_request(self, code='-', size='-'):
83 83 xheaders = []
84 84 if util.safehasattr(self, 'headers'):
85 85 xheaders = [h for h in self.headers.items()
86 86 if h[0].startswith('x-')]
87 87 self.log_message('"%s" %s %s%s',
88 88 self.requestline, str(code), str(size),
89 89 ''.join([' %s:%s' % h for h in sorted(xheaders)]))
90 90
91 91 def do_write(self):
92 92 try:
93 93 self.do_hgweb()
94 94 except socket.error as inst:
95 95 if inst[0] != errno.EPIPE:
96 96 raise
97 97
98 98 def do_POST(self):
99 99 try:
100 100 self.do_write()
101 101 except Exception:
102 102 self._start_response("500 Internal Server Error", [])
103 103 self._write("Internal Server Error")
104 104 self._done()
105 105 tb = "".join(traceback.format_exception(*sys.exc_info()))
106 106 self.log_error("Exception happened during processing "
107 107 "request '%s':\n%s", self.path, tb)
108 108
109 109 def do_GET(self):
110 110 self.do_POST()
111 111
112 112 def do_hgweb(self):
113 113 path, query = _splitURI(self.path)
114 114
115 115 env = {}
116 116 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
117 117 env['REQUEST_METHOD'] = self.command
118 118 env['SERVER_NAME'] = self.server.server_name
119 119 env['SERVER_PORT'] = str(self.server.server_port)
120 120 env['REQUEST_URI'] = self.path
121 121 env['SCRIPT_NAME'] = self.server.prefix
122 122 env['PATH_INFO'] = path[len(self.server.prefix):]
123 123 env['REMOTE_HOST'] = self.client_address[0]
124 124 env['REMOTE_ADDR'] = self.client_address[0]
125 125 if query:
126 126 env['QUERY_STRING'] = query
127 127
128 128 if self.headers.typeheader is None:
129 129 env['CONTENT_TYPE'] = self.headers.type
130 130 else:
131 131 env['CONTENT_TYPE'] = self.headers.typeheader
132 132 length = self.headers.getheader('content-length')
133 133 if length:
134 134 env['CONTENT_LENGTH'] = length
135 135 for header in [h for h in self.headers.keys()
136 136 if h not in ('content-type', 'content-length')]:
137 137 hkey = 'HTTP_' + header.replace('-', '_').upper()
138 138 hval = self.headers.getheader(header)
139 139 hval = hval.replace('\n', '').strip()
140 140 if hval:
141 141 env[hkey] = hval
142 142 env['SERVER_PROTOCOL'] = self.request_version
143 143 env['wsgi.version'] = (1, 0)
144 144 env['wsgi.url_scheme'] = self.url_scheme
145 145 if env.get('HTTP_EXPECT', '').lower() == '100-continue':
146 146 self.rfile = common.continuereader(self.rfile, self.wfile.write)
147 147
148 148 env['wsgi.input'] = self.rfile
149 149 env['wsgi.errors'] = _error_logger(self)
150 150 env['wsgi.multithread'] = isinstance(self.server,
151 151 socketserver.ThreadingMixIn)
152 152 env['wsgi.multiprocess'] = isinstance(self.server,
153 153 socketserver.ForkingMixIn)
154 154 env['wsgi.run_once'] = 0
155 155
156 156 self.saved_status = None
157 157 self.saved_headers = []
158 158 self.sent_headers = False
159 159 self.length = None
160 160 self._chunked = None
161 161 for chunk in self.server.application(env, self._start_response):
162 162 self._write(chunk)
163 163 if not self.sent_headers:
164 164 self.send_headers()
165 165 self._done()
166 166
167 167 def send_headers(self):
168 168 if not self.saved_status:
169 169 raise AssertionError("Sending headers before "
170 170 "start_response() called")
171 171 saved_status = self.saved_status.split(None, 1)
172 172 saved_status[0] = int(saved_status[0])
173 173 self.send_response(*saved_status)
174 174 self.length = None
175 175 self._chunked = False
176 176 for h in self.saved_headers:
177 177 self.send_header(*h)
178 178 if h[0].lower() == 'content-length':
179 179 self.length = int(h[1])
180 180 if (self.length is None and
181 181 saved_status[0] != common.HTTP_NOT_MODIFIED):
182 182 self._chunked = (not self.close_connection and
183 183 self.request_version == "HTTP/1.1")
184 184 if self._chunked:
185 185 self.send_header('Transfer-Encoding', 'chunked')
186 186 else:
187 187 self.send_header('Connection', 'close')
188 188 self.end_headers()
189 189 self.sent_headers = True
190 190
191 191 def _start_response(self, http_status, headers, exc_info=None):
192 192 code, msg = http_status.split(None, 1)
193 193 code = int(code)
194 194 self.saved_status = http_status
195 195 bad_headers = ('connection', 'transfer-encoding')
196 196 self.saved_headers = [h for h in headers
197 197 if h[0].lower() not in bad_headers]
198 198 return self._write
199 199
200 200 def _write(self, data):
201 201 if not self.saved_status:
202 202 raise AssertionError("data written before start_response() called")
203 203 elif not self.sent_headers:
204 204 self.send_headers()
205 205 if self.length is not None:
206 206 if len(data) > self.length:
207 207 raise AssertionError("Content-length header sent, but more "
208 208 "bytes than specified are being written.")
209 209 self.length = self.length - len(data)
210 210 elif self._chunked and data:
211 211 data = '%x\r\n%s\r\n' % (len(data), data)
212 212 self.wfile.write(data)
213 213 self.wfile.flush()
214 214
215 215 def _done(self):
216 216 if self._chunked:
217 217 self.wfile.write('0\r\n\r\n')
218 218 self.wfile.flush()
219 219
220 220 class _httprequesthandlerssl(_httprequesthandler):
221 221 """HTTPS handler based on Python's ssl module"""
222 222
223 223 url_scheme = 'https'
224 224
225 225 @staticmethod
226 226 def preparehttpserver(httpserver, ui):
227 227 try:
228 228 from .. import sslutil
229 229 sslutil.modernssl
230 230 except ImportError:
231 231 raise error.Abort(_("SSL support is unavailable"))
232 232
233 233 certfile = ui.config('web', 'certificate')
234 234
235 235 # These config options are currently only meant for testing. Use
236 236 # at your own risk.
237 237 cafile = ui.config('devel', 'servercafile')
238 238 reqcert = ui.configbool('devel', 'serverrequirecert')
239 239
240 240 httpserver.socket = sslutil.wrapserversocket(httpserver.socket,
241 241 ui,
242 242 certfile=certfile,
243 243 cafile=cafile,
244 244 requireclientcert=reqcert)
245 245
246 246 def setup(self):
247 247 self.connection = self.request
248 248 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
249 249 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
250 250
251 251 try:
252 252 import threading
253 253 threading.activeCount() # silence pyflakes and bypass demandimport
254 254 _mixin = socketserver.ThreadingMixIn
255 255 except ImportError:
256 256 if util.safehasattr(os, "fork"):
257 257 _mixin = socketserver.ForkingMixIn
258 258 else:
259 259 class _mixin(object):
260 260 pass
261 261
262 262 def openlog(opt, default):
263 263 if opt and opt != '-':
264 264 return open(opt, 'a')
265 265 return default
266 266
267 267 class MercurialHTTPServer(_mixin, httpservermod.httpserver, object):
268 268
269 269 # SO_REUSEADDR has broken semantics on windows
270 270 if pycompat.osname == 'nt':
271 271 allow_reuse_address = 0
272 272
273 273 def __init__(self, ui, app, addr, handler, **kwargs):
274 274 httpservermod.httpserver.__init__(self, addr, handler, **kwargs)
275 275 self.daemon_threads = True
276 276 self.application = app
277 277
278 278 handler.preparehttpserver(self, ui)
279 279
280 280 prefix = ui.config('web', 'prefix', '')
281 281 if prefix:
282 282 prefix = '/' + prefix.strip('/')
283 283 self.prefix = prefix
284 284
285 alog = openlog(ui.config('web', 'accesslog', '-'), ui.fout)
285 alog = openlog(ui.config('web', 'accesslog'), ui.fout)
286 286 elog = openlog(ui.config('web', 'errorlog', '-'), ui.ferr)
287 287 self.accesslog = alog
288 288 self.errorlog = elog
289 289
290 290 self.addr, self.port = self.socket.getsockname()[0:2]
291 291 self.fqaddr = socket.getfqdn(addr[0])
292 292
293 293 class IPv6HTTPServer(MercurialHTTPServer):
294 294 address_family = getattr(socket, 'AF_INET6', None)
295 295 def __init__(self, *args, **kwargs):
296 296 if self.address_family is None:
297 297 raise error.RepoError(_('IPv6 is not available on this system'))
298 298 super(IPv6HTTPServer, self).__init__(*args, **kwargs)
299 299
300 300 def create_server(ui, app):
301 301
302 302 if ui.config('web', 'certificate'):
303 303 handler = _httprequesthandlerssl
304 304 else:
305 305 handler = _httprequesthandler
306 306
307 307 if ui.configbool('web', 'ipv6'):
308 308 cls = IPv6HTTPServer
309 309 else:
310 310 cls = MercurialHTTPServer
311 311
312 312 # ugly hack due to python issue5853 (for threaded use)
313 313 try:
314 314 import mimetypes
315 315 mimetypes.init()
316 316 except UnicodeDecodeError:
317 317 # Python 2.x's mimetypes module attempts to decode strings
318 318 # from Windows' ANSI APIs as ascii (fail), then re-encode them
319 319 # as ascii (clown fail), because the default Python Unicode
320 320 # codec is hardcoded as ascii.
321 321
322 322 sys.argv # unwrap demand-loader so that reload() works
323 323 reload(sys) # resurrect sys.setdefaultencoding()
324 324 oldenc = sys.getdefaultencoding()
325 325 sys.setdefaultencoding("latin1") # or any full 8-bit encoding
326 326 mimetypes.init()
327 327 sys.setdefaultencoding(oldenc)
328 328
329 329 address = ui.config('web', 'address', '')
330 330 port = util.getport(ui.config('web', 'port', 8000))
331 331 try:
332 332 return cls(ui, app, (address, port), handler)
333 333 except socket.error as inst:
334 334 raise error.Abort(_("cannot start server at '%s:%d': %s")
335 335 % (address, port, inst.args[1]))
General Comments 0
You need to be logged in to leave comments. Login now