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
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.
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.
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
51 """Get the setting for the HTTP server's public FQDN from the global
52 :data:`SERVER_PUBLIC_FQDN variable.
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.
74 if useForwardedHeader
:
75 header
= request
.getHeader("X-Forwarded-For")
78 ip
= header
.split(",")[index
].strip()
80 logging
.info(("Parsing X-Forwarded-For again, ignoring "
81 "loopback addresses..."))
84 ip
= header
.split(",")[index
].strip()
85 if not skipLoopback
and isLoopback(ip
):
86 logging
.warn("Accepting loopback address: %s" % ip
)
88 if not isIPAddress(ip
):
89 logging
.warn("Got weird X-Forwarded-For value %r" % header
)
92 ip
= request
.getClientIP()