Open Table Of Contents

Source code for bridgedb.https.request

# -*- coding: utf-8; test-case-name: bridgedb.test.test_https_request; -*-
#_____________________________________________________________________________
#
# This file is part of BridgeDB, a Tor bridge distribution system.
#
# :authors: Isis Lovecruft <isis@torproject.org> 0xA3ADB67A2CDB8B35
# :copyright: (c) 2007-2015, The Tor Project, Inc.
#             (c) 2013-2015, Isis Lovecruft
# :license: see LICENSE for licensing information
#_____________________________________________________________________________

"""
.. py:module:: bridgedb.https.request
    :synopsis: Classes for parsing and storing information about requests for
               bridges which are sent to the HTTPS distributor.

bridgedb.https.request
======================

Classes for parsing and storing information about requests for bridges
which are sent to the HTTPS distributor.

.. inheritance-diagram:: HTTPSBridgeRequest

::

  bridgedb.https.request
   |
   |_ HTTPSBridgeRequest - A request for bridges which was received through
                           the HTTPS distributor.

..
"""

from __future__ import print_function
from __future__ import unicode_literals

import ipaddr
import logging
import re

from bridgedb import bridgerequest
from bridgedb import geo
from bridgedb.parse import addr


#: A regular expression for matching the Pluggable Transport methodname in
#: HTTP GET request parameters.
TRANSPORT_REGEXP = "[_a-zA-Z][_a-zA-Z0-9]*"
TRANSPORT_PATTERN = re.compile(TRANSPORT_REGEXP)

UNBLOCKED_REGEXP = "[a-zA-Z]{2}"
UNBLOCKED_PATTERN = re.compile(UNBLOCKED_REGEXP)


[docs]class HTTPSBridgeRequest(bridgerequest.BridgeRequestBase): """We received a request for bridges through the HTTPS distributor.""" def __init__(self, addClientCountryCode=True): """Process a new bridge request received through the :class:`~bridgedb.https.distributor.HTTPSDistributor`. :param bool addClientCountryCode: If ``True``, then calling :meth:`withoutBlockInCountry` will attempt to add the client's own country code, geolocated from her IP, to the ``notBlockedIn`` countries list. """ super(HTTPSBridgeRequest, self).__init__() self.addClientCountryCode = addClientCountryCode
[docs] def withIPversion(self, parameters): """Determine if the request **parameters** were for bridges with IPv6 addresses or not. .. note:: If there is an ``ipv6=`` parameter with anything non-zero after it, then we assume the client wanted IPv6 bridges. :param parameters: The :api:`twisted.web.http.Request.args`. """ if parameters.get("ipv6", False): logging.info("HTTPS request for bridges with IPv6 addresses.") self.withIPv6()
[docs] def withoutBlockInCountry(self, request): """Determine which countries the bridges for this **request** should not be blocked in. .. note:: Currently, a **request** for unblocked bridges is recognized if it contains an HTTP GET parameter ``unblocked=`` whose value is a comma-separater list of two-letter country codes. Any two-letter country code found in the :api:`request <twisted.web.http.Request>` ``unblocked=`` HTTP GET parameter will be added to the :data:`notBlockedIn` list. If :data:`addClientCountryCode` is ``True``, the the client's own geolocated country code will be added to the to the :data`notBlockedIn` list. :type request: :api:`twisted.web.http.Request` :param request: A ``Request`` object containing the HTTP method, full URI, and any URL/POST arguments and headers present. """ countryCodes = request.args.get("unblocked", list()) for countryCode in countryCodes: try: country = UNBLOCKED_PATTERN.match(countryCode).group() except (TypeError, AttributeError): pass else: if country: self.notBlockedIn.append(country.lower()) logging.info("HTTPS request for bridges not blocked in: %r" % country) if self.addClientCountryCode: # Look up the country code of the input IP, and request bridges # not blocked in that country. if addr.isIPAddress(self.client): country = geo.getCountryCode(ipaddr.IPAddress(self.client)) if country: self.notBlockedIn.append(country.lower()) logging.info( ("HTTPS client's bridges also shouldn't be blocked " "in their GeoIP country code: %s") % country)
[docs] def withPluggableTransportType(self, parameters): """This request included a specific Pluggable Transport identifier. Add any Pluggable Transport methodname found in the HTTP GET **parameters** to the list of ``transports``. Currently, a request for a transport is recognized if the request contains the ``'transport='`` parameter. :param parameters: The :api:`twisted.web.http.Request.args`. """ for methodname in parameters.get("transport", list()): try: transport = TRANSPORT_PATTERN.match(methodname).group() except (TypeError, AttributeError): pass else: if transport: self.transports.append(transport) logging.info("HTTPS request for transport type: %r" % transport)