Merge branch 'release-0.11.0'
[tor-bridgedb.git] / bridgedb / distributors / common / http.py
blob3bd7b412608ce98c24eb2777e58d4f18087a2ced
1 # -*- coding: utf-8 ; test-case-name: bridgedb.test.test_distributors_common_http -*-
3 # This file is part of BridgeDB, a Tor bridge distribution system.
5 # :authors: please see included AUTHORS file
6 # :copyright: (c) 2017, The Tor Project, Inc.
7 # (c) 2017, Isis Lovecruft
8 # :license: see LICENSE for licensing information
10 """
11 .. py:module:: bridgedb.distributors.common.http
12 :synopsis: Common utilities for HTTP-based distributors.
14 bridgedb.distributors.common.http
15 ==================================
17 Common utilities for HTTP-based distributors.
18 """
20 import logging
21 import os
23 from bridgedb.parse.addr import isIPAddress
24 from bridgedb.parse.addr import isLoopback
27 #: The fully-qualified domain name for any and all web servers we run.
28 SERVER_PUBLIC_FQDN = None
31 def setFQDN(fqdn, https=True):
32 """Set the global :data:`SERVER_PUBLIC_FQDN` variable.
34 :param str fqdn: The public, fully-qualified domain name of the HTTP
35 server that will serve this resource.
36 :param bool https: If ``True``, then ``'https://'`` will be prepended to
37 the FQDN. This is primarily used to create a
38 ``Content-Security-Policy`` header that will only allow resources to
39 be sourced via HTTPS, otherwise, if ``False``, it allow resources to
40 be sourced via any transport protocol.
41 """
42 if https:
43 fqdn = 'https://' + fqdn
45 logging.info("Setting HTTP server public FQDN to %r" % fqdn)
47 global SERVER_PUBLIC_FQDN
48 SERVER_PUBLIC_FQDN = fqdn
50 def getFQDN():
51 """Get the setting for the HTTP server's public FQDN from the global
52 :data:`SERVER_PUBLIC_FQDN variable.
54 :rtype: str or None
55 """
56 return SERVER_PUBLIC_FQDN
58 def getClientIP(request, useForwardedHeader=False, skipLoopback=False):
59 """Get the client's IP address from the ``'X-Forwarded-For:'``
60 header, or from the :api:`request <twisted.web.server.Request>`.
62 :type request: :api:`twisted.web.http.Request`
63 :param request: A ``Request`` for a :api:`twisted.web.resource.Resource`.
64 :param bool useForwardedHeader: If ``True``, attempt to get the client's
65 IP address from the ``'X-Forwarded-For:'`` header.
66 :param bool skipLoopback: If ``True``, and ``useForwardedHeader`` is
67 also ``True``, then skip any loopback addresses (127.0.0.1/8) when
68 parsing the X-Forwarded-For header.
69 :rtype: ``None`` or :any:`str`
70 :returns: The client's IP address, if it was obtainable.
71 """
72 ip = None
74 if useForwardedHeader:
75 header = request.getHeader("X-Forwarded-For")
76 if header:
77 index = -1
78 ip = header.split(",")[index].strip()
79 if skipLoopback:
80 logging.info(("Parsing X-Forwarded-For again, ignoring "
81 "loopback addresses..."))
82 while isLoopback(ip):
83 index -= 1
84 ip = header.split(",")[index].strip()
85 if not skipLoopback and isLoopback(ip):
86 logging.warn("Accepting loopback address: %s" % ip)
87 else:
88 if not isIPAddress(ip):
89 logging.warn("Got weird X-Forwarded-For value %r" % header)
90 ip = None
91 else:
92 ip = request.getClientIP()
94 return ip