comparison roundup/scripts/roundup_server.py @ 5432:fec18298ae02

Python 3 preparation: HTTP headers handling in roundup_server.py. HTTP headers are handled differently in Python 3 (where they use email.message.Message) compared to Python 2 (where they use mimetools.Message). In some places the code needs to check which version of the interface is available. For the common case of getting a single header, ".get" is available in both versions, and is an alias of ".getheader" in Python 2. (Note that the Python 3 semantics of ".get" are slightly different from those in Python 2 if there is more than one of a given header - it returns an arbitrary one, when in Python 2 it's specified to return the last one. Hopefully the places using this interface rather than explicitly allowing for multiple headers with the same name are OK with that and it shouldn't actually occur with well-behaved clients.)
author Joseph Myers <jsm@polyomino.org.uk>
date Wed, 25 Jul 2018 10:41:32 +0000
parents 4c724ad7b849
children fb9abb842f36
comparison
equal deleted inserted replaced
5431:4c724ad7b849 5432:fec18298ae02
373 env['TRACKER_NAME'] = tracker_name 373 env['TRACKER_NAME'] = tracker_name
374 env['REQUEST_METHOD'] = self.command 374 env['REQUEST_METHOD'] = self.command
375 env['PATH_INFO'] = urllib_.unquote(rest) 375 env['PATH_INFO'] = urllib_.unquote(rest)
376 if query: 376 if query:
377 env['QUERY_STRING'] = query 377 env['QUERY_STRING'] = query
378 if self.headers.typeheader is None: 378 if hasattr(self.headers, 'get_content_type'):
379 # Python 3. We need the raw header contents.
380 env['CONTENT_TYPE'] = self.headers.get('content-type')
381 elif self.headers.typeheader is None:
382 # Python 2.
379 env['CONTENT_TYPE'] = self.headers.type 383 env['CONTENT_TYPE'] = self.headers.type
380 else: 384 else:
385 # Python 2.
381 env['CONTENT_TYPE'] = self.headers.typeheader 386 env['CONTENT_TYPE'] = self.headers.typeheader
382 length = self.headers.getheader('content-length') 387 length = self.headers.get('content-length')
383 if length: 388 if length:
384 env['CONTENT_LENGTH'] = length 389 env['CONTENT_LENGTH'] = length
385 co = list(filter(None, self.headers.getheaders('cookie'))) 390 if hasattr(self.headers, 'get_all'):
391 # Python 3.
392 ch = self.headers.get_all('cookie', [])
393 else:
394 # Python 2.
395 ch = self.headers.getheaders('cookie')
396 co = list(filter(None, ch))
386 if co: 397 if co:
387 env['HTTP_COOKIE'] = ', '.join(co) 398 env['HTTP_COOKIE'] = ', '.join(co)
388 env['HTTP_AUTHORIZATION'] = self.headers.getheader('authorization') 399 env['HTTP_AUTHORIZATION'] = self.headers.get('authorization')
389 env['SCRIPT_NAME'] = '' 400 env['SCRIPT_NAME'] = ''
390 env['SERVER_NAME'] = self.server.server_name 401 env['SERVER_NAME'] = self.server.server_name
391 env['SERVER_PORT'] = str(self.server.server_port) 402 env['SERVER_PORT'] = str(self.server.server_port)
392 try: 403 try:
393 env['HTTP_HOST'] = self.headers ['host'] 404 env['HTTP_HOST'] = self.headers ['host']
394 except KeyError: 405 except KeyError:
395 env['HTTP_HOST'] = '' 406 env['HTTP_HOST'] = ''
396 # https://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10 407 # https://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10
397 # headers. 408 # headers.
398 xfh = self.headers.getheader('X-Forwarded-Host', None) 409 xfh = self.headers.get('X-Forwarded-Host', None)
399 if xfh: 410 if xfh:
400 # If behind a proxy, this is the hostname supplied 411 # If behind a proxy, this is the hostname supplied
401 # via the Host header to the proxy. Used by core code. 412 # via the Host header to the proxy. Used by core code.
402 # Controlled by the CSRF settings. 413 # Controlled by the CSRF settings.
403 env['HTTP_X-FORWARDED-HOST'] = xfh 414 env['HTTP_X-FORWARDED-HOST'] = xfh
404 xff = self.headers.getheader('X-Forwarded-For', None) 415 xff = self.headers.get('X-Forwarded-For', None)
405 if xff: 416 if xff:
406 # xff is a list of ip addresses for original client/proxies: 417 # xff is a list of ip addresses for original client/proxies:
407 # X-Forwarded-For: clientIP, proxy1IP, proxy2IP 418 # X-Forwarded-For: clientIP, proxy1IP, proxy2IP
408 # May not be trustworthy. Do not use in core without 419 # May not be trustworthy. Do not use in core without
409 # config option to control its use. 420 # config option to control its use.
410 # Made available for extensions if the user trusts it. 421 # Made available for extensions if the user trusts it.
411 # E.g. you may wish to disable recaptcha validation extension 422 # E.g. you may wish to disable recaptcha validation extension
412 # if the ip of the client matches 172.16.0.0. 423 # if the ip of the client matches 172.16.0.0.
413 env['HTTP_X-FORWARDED-FOR'] = xff 424 env['HTTP_X-FORWARDED-FOR'] = xff
414 xfp = self.headers.getheader('X-Forwarded-Proto', None) 425 xfp = self.headers.get('X-Forwarded-Proto', None)
415 if xfp: 426 if xfp:
416 # xfp is the protocol (http/https) seen by proxies in the 427 # xfp is the protocol (http/https) seen by proxies in the
417 # path of the request. I am not sure if there is only 428 # path of the request. I am not sure if there is only
418 # one value or multiple, but I suspect multiple 429 # one value or multiple, but I suspect multiple
419 # is possible so: 430 # is possible so:
435 if origin: 446 if origin:
436 env['HTTP_ORIGIN'] = origin 447 env['HTTP_ORIGIN'] = origin
437 xrw = self.headers.get('x-requested-with') 448 xrw = self.headers.get('x-requested-with')
438 if xrw: 449 if xrw:
439 env['HTTP_X-REQUESTED-WITH'] = xrw 450 env['HTTP_X-REQUESTED-WITH'] = xrw
440 range = self.headers.getheader('range') 451 range = self.headers.get('range')
441 if range: 452 if range:
442 env['HTTP_RANGE'] = range 453 env['HTTP_RANGE'] = range
443 454
444 # do the roundup thing 455 # do the roundup thing
445 tracker = self.get_tracker(tracker_name) 456 tracker = self.get_tracker(tracker_name)

Roundup Issue Tracker: http://roundup-tracker.org/