Example #1
0
def get_participant(request, restrict=True):
    """Given a Request, raise Response or return Participant.

    If user is not None then we'll restrict access to owners and admins.

    """
    user = request.context['user']
    participant_id = request.line.uri.path['participant_id']

    if restrict:
        if user.ANON:
            request.redirect(u'/%s/' % participant_id)

    participant = Participant.query.get(participant_id)

    if participant is None:
        raise Response(404)

    elif participant.claimed_time is None:

        # This is a stub participant record for someone on another platform who
        # hasn't actually registered with Gittip yet. Let's bounce the viewer
        # over to the appropriate platform page.

        to = participant.resolve_unclaimed()
        if to is None:
            raise Response(404)
        request.redirect(to)

    if restrict:
        if participant != user:
            if not user.ADMIN:
                raise Response(403)

    return participant
Example #2
0
def get_user_info(username):
    """Get the given user's information from the DB or failing that, bitbucket.

    :param username:
        A unicode string representing a username in bitbucket.

    :returns:
        A dictionary containing bitbucket specific information for the user.
    """
    typecheck(username, unicode)
    rec = gittip.db.fetchone(
        "SELECT user_info FROM elsewhere "
        "WHERE platform='bitbucket' "
        "AND user_info->'username' = %s", (username, ))
    if rec is not None:
        user_info = rec['user_info']
    else:
        url = "%s/users/%s?pagelen=100"
        user_info = requests.get(url % (BASE_API_URL, username))
        status = user_info.status_code
        content = user_info.content
        if status == 200:
            user_info = json.loads(content)['user']
        elif status == 404:
            raise Response(
                404, "Bitbucket identity '{0}' not found.".format(username))
        else:
            log("Bitbucket api responded with {0}: {1}".format(
                status, content),
                level=logging.WARNING)
            raise Response(502, "Bitbucket lookup failed with %d." % status)

    return user_info
Example #3
0
def cast(path_part, state):
    """This is an Aspen typecaster. Given a slug and a state dict, raise
    Response or return Team.
    """
    redirect = state['website'].redirect
    request = state['request']
    user = state['user']
    slug = path_part
    qs = request.line.uri.querystring

    try:
        team = Team.from_slug(slug)
    except:
        raise Response(400, 'bad slug')

    if team is None:
        # Try to redirect to a Participant.
        from gratipay.models.participant import Participant  # avoid circular import
        participant = Participant.from_username(slug)
        if participant is not None:
            qs = '?' + request.qs.raw if request.qs.raw else ''
            redirect('/~' + request.path.raw[1:] + qs)
        raise Response(404)

    canonicalize(redirect, request.line.uri.path.raw, '/', team.slug, slug, qs)

    if team.is_closed and not user.ADMIN:
        raise Response(410)

    return team
def get_account_elsewhere(website, state, api_lookup=True):
    _ = state['_']
    path = state['request'].line.uri.path

    platform = getattr(website.platforms, path['platform'], None)
    if platform is None:
        raise Response(404)

    uid = path['user_name']
    if "\t" in uid or "\r" in uid or "\n" in uid:
        raise Response(400,
                       _("Invalid character in elsewhere account username."))
    if uid[:1] == '~':
        key = 'user_id'
        uid = uid[1:]
    else:
        key = 'user_name'
    try:
        account = AccountElsewhere._from_thing(key, platform.name, uid)
    except UnknownAccountElsewhere:
        account = None
    if not account:
        if not api_lookup:
            raise Response(404)
        try:
            user_info = platform.get_user_info(key, uid)
        except Response as r:
            if r.code == 404:
                err = _("Account not found on {0}.", platform.display_name)
                raise Response(404, err)
            raise
        account = AccountElsewhere.upsert(user_info)
    return platform, account
Example #5
0
def try_to_serve_304(dispatch_result, request, etag):
    """Try to serve a 304 for static resources.
    """
    if not etag:
        # This is a request for a dynamic resource.
        return

    qs_etag = request.line.uri.querystring.get('etag')
    if qs_etag and qs_etag != etag:
        # Don't serve one version of a file as if it were another.
        raise Response(410)

    headers_etag = request.headers.get('If-None-Match')
    if not headers_etag:
        # This client doesn't want a 304.
        return

    if headers_etag != etag:
        # Cache miss, the client sent an old or invalid etag.
        return

    # Huzzah!
    # =======
    # We can serve a 304! :D

    raise Response(304)
Example #6
0
def get_account_elsewhere(website, state, api_lookup=True):
    path = state['request'].line.uri.path
    platform = getattr(website.platforms, path['platform'], None)
    if platform is None:
        raise Response(404)
    uid = path['user_name']
    if uid[:1] == '~':
        key = 'user_id'
        uid = uid[1:]
    else:
        key = 'user_name'
    try:
        account = AccountElsewhere._from_thing(key, platform.name, uid)
    except UnknownAccountElsewhere:
        account = None
    if not account:
        if not api_lookup:
            raise Response(404)
        try:
            user_info = platform.get_user_info(key, uid)
        except Response as r:
            if r.code == 404:
                _ = state['_']
                err = _("There doesn't seem to be a user named {0} on {1}.",
                        uid, platform.display_name)
                raise Response(404, err)
            raise
        account = AccountElsewhere.upsert(user_info)
    return platform, account
Example #7
0
    def change_username(self, suggested):
        """Raise Response or return None.

        We want to be pretty loose with usernames. Unicode is allowed--XXX
        aspen bug :(. So are spaces.Control characters aren't. We also limit to
        32 characters in length.

        """
        for i, c in enumerate(suggested):
            if i == 32:
                raise Response(413)  # Request Entity Too Large (more or less)
            elif ord(c) < 128 and c not in ASCII_ALLOWED_IN_USERNAME:
                raise Response(400)  # Yeah, no.
            elif c not in ASCII_ALLOWED_IN_USERNAME:
                raise Response(400)  # XXX Burned by an Aspen bug. :`-(
                # https://github.com/whit537/aspen/issues/102

        if suggested in gittip.RESTRICTED_USERNAMES:
            raise Response(400)

        if suggested != self.username:
            # Will raise IntegrityError if the desired username is taken.
            rec = gittip.db.fetchone(
                "UPDATE participants "
                "SET username=%s WHERE username=%s "
                "RETURNING username", (suggested, self.username))

            assert rec is not None  # sanity check
            assert suggested == rec['username']  # sanity check
            self.username = suggested
Example #8
0
def get_team(state):
    """Given a Request, raise Response or return Team.
    """
    redirect = state['website'].redirect
    request = state['request']
    user = state['user']
    slug = request.line.uri.path['team']
    qs = request.line.uri.querystring

    from gratipay.models.team import Team  # avoid circular import
    team = Team.from_slug(slug)

    if team is None:
        # Try to redirect to a Participant.
        from gratipay.models.participant import Participant  # avoid circular import
        participant = Participant.from_username(slug)
        if participant is not None:
            qs = '?' + request.qs.raw if request.qs.raw else ''
            redirect('/~' + request.path.raw[1:] + qs)
        raise Response(404)

    canonicalize(redirect, request.line.uri.path.raw, '/', team.slug, slug, qs)

    if team.is_closed and not user.ADMIN:
        raise Response(410)

    return team
Example #9
0
def change_participant_id(website, old, suggested):
    """Raise response return None.

    We want to be pretty loose with usernames. Unicode is allowed. So are
    spaces.  Control characters aren't. We also limit to 32 characters in
    length.

    """
    for i, c in enumerate(suggested):
        if i == 32:
            raise Response(413)  # Request Entity Too Large (more or less)
        elif ord(c) < 128 and c not in ALLOWED_ASCII:
            raise Response(400)  # Yeah, no.
        elif c not in ALLOWED_ASCII:
            raise Response(400)  # XXX Burned by an Aspen bug. :`-(
            # https://github.com/whit537/aspen/issues/102

    if website is not None and suggested in os.listdir(website.www_root):
        raise Response(400)

    if suggested != old:
        rec = db.fetchone( "UPDATE participants SET id=%s WHERE id=%s " \
                           "RETURNING id", (suggested, old))
        # May raise IntegrityError
        assert rec is not None  # sanity check
        assert suggested == rec['id']  # sanity check
Example #10
0
def get_community(state, restrict=False):
    request, response = state['request'], state['response']
    user = state['user']
    name = request.path['name']

    c = Community.from_name(name)
    if request.method in ('GET', 'HEAD'):
        if not c:
            response.redirect('/for/new?name=' + urlquote(name))
        if c.name != name:
            response.redirect('/for/' + c.name +
                              request.line.uri[5 + len(name):])
    elif not c:
        raise Response(404)
    elif user.ANON:
        raise AuthRequired

    if restrict:
        if user.ANON:
            raise AuthRequired
        if user.id != c.creator and not user.is_admin:
            _ = state['_']
            raise Response(403,
                           _("You are not authorized to access this page."))

    return c
Example #11
0
    def respond(self, request):
        """Given a Request, return a Response.
        """
        request.allow('GET', 'POST')

        if self.state == 0:  # The client wants confirmation.
            response = Response(200, "1:::")
            self.state = 1

        elif request.line.method == 'POST':  # The client is sending us data.
            self.socket._send(request.body.raw)
            response = Response(200)

        elif request.line.method == 'GET':  # The client is asking for data.
            bytes_iter = iter([""])
            timeout = time.time() + self.timeout
            while time.time() < timeout:
                _bytes_iter = self.socket._recv()
                if _bytes_iter is not None:
                    bytes_iter = _bytes_iter
                    break
                request.website.network_engine.sleep(0.010)
            response = Response(200, bytes_iter)

        return response
Example #12
0
def get_participant(state,
                    restrict=True,
                    redirect_stub=True,
                    allow_member=False):
    """Given a Request, raise Response or return Participant.

    If restrict is True then we'll restrict access to owners and admins.

    """
    request = state['request']
    user = state['user']
    slug = request.line.uri.path['username']
    _ = state['_']

    if restrict and user.ANON:
        raise AuthRequired

    if slug.startswith('~'):
        thing = 'id'
        value = slug[1:]
        participant = user if user and str(user.id) == value else None
    else:
        thing = 'lower(username)'
        value = slug.lower()
        participant = user if user and user.username.lower() == value else None

    if participant is None:
        from liberapay.models.participant import Participant  # avoid circular import
        participant = Participant._from_thing(thing, value) if value else None
        if participant is None or participant.kind == 'community':
            raise Response(404)

    if request.method in ('GET', 'HEAD'):
        if slug != participant.username:
            canon = '/' + participant.username + request.line.uri[len(slug) +
                                                                  1:]
            raise Response(302, headers={'Location': canon})

    status = participant.status
    if status == 'closed':
        if user.is_admin:
            return participant
        raise Response(410)
    elif status == 'stub':
        if redirect_stub:
            to = participant.resolve_stub()
            assert to
            raise Response(302, headers={'Location': to})

    if restrict:
        if participant != user:
            if allow_member and participant.kind == 'group' and user.member_of(
                    participant):
                pass
            elif not user.is_admin:
                raise Response(
                    403, _("You are not authorized to access this page."))

    return participant
Example #13
0
def get_csrf_token_from_request(request):
    """Given a Request object, reject it if it's a forgery.
    """
    if request.line.uri.startswith('/assets/'): return
    if request.line.uri.startswith('/callbacks/'): return

    try:
        csrf_token = _sanitize_token(
            request.headers.cookie['csrf_token'].value)
    except KeyError:
        csrf_token = None

    request.context['csrf_token'] = csrf_token or _get_new_csrf_key()

    # Assume that anything not defined as 'safe' by RC2616 needs protection
    if request.line.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):

        if _is_secure(request):
            # Suppose user visits http://example.com/
            # An active network attacker (man-in-the-middle, MITM) sends a
            # POST form that targets https://example.com/detonate-bomb/ and
            # submits it via JavaScript.
            #
            # The attacker will need to provide a CSRF cookie and token, but
            # that's no problem for a MITM and the session-independent
            # nonce we're using. So the MITM can circumvent the CSRF
            # protection. This is true for any HTTP connection, but anyone
            # using HTTPS expects better! For this reason, for
            # https://example.com/ we need additional protection that treats
            # http://example.com/ as completely untrusted. Under HTTPS,
            # Barth et al. found that the Referer header is missing for
            # same-domain requests in only about 0.2% of cases or less, so
            # we can use strict Referer checking.
            referer = request.headers.get('Referer')
            if referer is None:
                raise Response(403, REASON_NO_REFERER)

            good_referer = 'https://%s/' % _get_host(request)
            if not same_origin(referer, good_referer):
                reason = REASON_BAD_REFERER % (referer, good_referer)
                log_dammit(reason)
                raise Response(403, reason)

        if csrf_token is None:
            raise Response(403, REASON_NO_CSRF_COOKIE)

        # Check non-cookie token for match.
        request_csrf_token = ""
        if request.line.method == "POST":
            if isinstance(request.body, dict):
                request_csrf_token = request.body.get('csrf_token', '')

        if request_csrf_token == "":
            # Fall back to X-CSRF-TOKEN, to make things easier for AJAX,
            # and possible for PUT/DELETE.
            request_csrf_token = request.headers.get('X-CSRF-TOKEN', '')

        if not constant_time_compare(request_csrf_token, csrf_token):
            raise Response(403, REASON_BAD_TOKEN)
def cast(path_part, state):
    """This is an Aspen typecaster. Given an id and a state dict, raise
    Response or return PaymentForOpenSource.
    """
    try:
        pfos = PaymentForOpenSource.from_id(path_part)
    except:
        raise Response(404)
    if pfos is None:
        raise Response(404)
    return pfos
def test_get_response_doesnt_reset_content_type_when_negotiating(mk):
    mk(('index.spt', NEGOTIATED_RESOURCE))
    request = StubRequest.from_fs('index.spt')
    request.headers['Accept'] = 'text/html'
    response = Response()
    response.headers['Content-Type'] = 'never/mind'
    actual = get_response(request, response).headers['Content-Type']
    response = Response()
    response.headers['Content-Type'] = 'never/mind'
    actual = get_response(request, response).headers['Content-Type']
    assert actual == "never/mind"
Example #16
0
    def api_get(self, path, sess=None, **kw):
        """
        Given a `path` (e.g. /users/foo), this function sends a GET request to
        the platform's API (e.g. https://api.github.com/users/foo).

        The response is returned, after checking its status code and ratelimit
        headers.
        """
        url = self.api_url + path
        is_user_session = bool(sess)
        if not sess:
            sess = self.get_auth_session()
            if self.name == 'github':
                url += '?' if '?' not in url else '&'
                url += 'client_id=%s&client_secret=%s' % (self.api_key,
                                                          self.api_secret)
        response = sess.get(url, **kw)

        limit, remaining, reset = self.get_ratelimit_headers(response)
        if not is_user_session:
            self.log_ratelimit_headers(limit, remaining, reset)

        # Check response status
        status = response.status_code
        if status == 401 and isinstance(self, PlatformOAuth1):
            # https://tools.ietf.org/html/rfc5849#section-3.2
            if is_user_session:
                raise TokenExpiredError
            raise Response(500)
        if status == 404:
            raise Response(404, response.text)
        if status == 429 and is_user_session:

            def msg(_, to_age):
                if remaining == 0 and reset:
                    return _(
                        "You've consumed your quota of requests, you can try again in {0}.",
                        to_age(reset))
                else:
                    return _(
                        "You're making requests too fast, please try again later."
                    )

            raise LazyResponse(status, msg)
        if status != 200:
            log('{} api responded with {}:\n{}'.format(self.name, status,
                                                       response.text),
                level=logging.ERROR)
            msg = lambda _: _("{0} returned an error, please try again later.",
                              self.display_name)
            raise LazyResponse(502, msg)

        return response
Example #17
0
 def check_api_response_status(self, response):
     """Pass through any 404, convert any other non-200 into a 500.
     """
     status = response.status_code
     if status == 404:
         raise Response(404, response.text)
     elif status != 200:
         log('{} api responded with {}:\n{}'.format(self.name, status,
                                                    response.text),
             level=logging.ERROR)
         raise Response(
             500, '{} lookup failed with {}'.format(self.name, status))
Example #18
0
    def api_get(self, path, sess=None, **kw):
        """
        Given a `path` (e.g. /users/foo), this function sends a GET request to
        the platform's API (e.g. https://api.github.com/users/foo).

        The response is returned, after checking its status code and ratelimit
        headers.
        """
        if not sess:
            sess = self.get_auth_session()
        response = sess.get(self.api_url + path, **kw)

        # Check status
        status = response.status_code
        if status == 404:
            raise Response(404)
        elif status != 200:
            log('{} api responded with {}:\n{}'.format(self.name, status,
                                                       response.text),
                level=logging.ERROR)
            raise Response(
                500, '{} lookup failed with {}'.format(self.name, status))

        # Check ratelimit headers
        prefix = getattr(self, 'ratelimit_headers_prefix', None)
        if prefix:
            limit = response.headers[prefix + 'limit']
            remaining = response.headers[prefix + 'remaining']
            reset = response.headers[prefix + 'reset']
            try:
                limit, remaining, reset = int(limit), int(remaining), int(
                    reset)
            except (TypeError, ValueError):
                d = dict(limit=limit, remaining=remaining, reset=reset)
                log('Got weird rate headers from %s: %s' % (self.name, d))
            else:
                percent_remaining = remaining / limit
                if percent_remaining < 0.5:
                    reset = to_age(datetime.fromtimestamp(reset, tz=utc))
                    log_msg = (
                        '{0} API: {1:.1%} of ratelimit has been consumed, '
                        '{2} requests remaining, resets {3}.').format(
                            self.name, 1 - percent_remaining, remaining, reset)
                    log_lvl = logging.WARNING
                    if percent_remaining < 0.2:
                        log_lvl = logging.ERROR
                    elif percent_remaining < 0.05:
                        log_lvl = logging.CRITICAL
                    log(log_msg, log_lvl)

        return response
Example #19
0
def get_participant(state, restrict=True, resolve_unclaimed=True):
    """Given a Request, raise Response or return Participant.

    If restrict is True then we'll restrict access to owners and admins.

    """
    redirect = state['website'].redirect
    request = state['request']
    user = state['user']
    slug = request.line.uri.path['username']
    qs = request.line.uri.querystring
    _ = state['_']

    if restrict:
        if user.ANON:
            raise Response(401, _("You need to log in to access this page."))

    from gratipay.models.participant import Participant  # avoid circular import
    participant = Participant.from_username(slug)

    if participant is None:
        raise Response(404)

    canonicalize(redirect, request.line.uri.path.raw, '/~/',
                 participant.username, slug, qs)

    if participant.is_closed:
        if user.ADMIN:
            return participant
        raise Response(410)

    if participant.claimed_time is None and resolve_unclaimed:
        to = participant.resolve_unclaimed()
        if to:
            # This is a stub account (someone on another platform who hasn't
            # actually registered with Gratipay yet)
            redirect(to)
        else:
            # This is an archived account (result of take_over)
            if user.ADMIN:
                return participant
            raise Response(404)

    if restrict:
        if participant != user.participant:
            if not user.ADMIN:
                raise Response(
                    403, _("You are not authorized to access this page."))

    return participant
Example #20
0
def export_history(participant,
                   year,
                   key,
                   back_as='namedtuple',
                   require_key=False):
    db = participant.db
    params = dict(username=participant.username, year=year)
    out = {}

    out['given'] = lambda: db.all("""
        SELECT CONCAT('~', tippee) as tippee, sum(amount) AS amount
          FROM transfers
         WHERE tipper = %(username)s
           AND extract(year from timestamp) = %(year)s
      GROUP BY tippee

         UNION

        SELECT team as tippee, sum(amount) AS amount
          FROM payments
         WHERE participant = %(username)s
           AND direction = 'to-team'
           AND extract(year from timestamp) = %(year)s
      GROUP BY tippee
    """,
                                  params,
                                  back_as=back_as)

    # FIXME: Include values from the `payments` table
    out['taken'] = lambda: db.all("""
        SELECT tipper AS team, sum(amount) AS amount
          FROM transfers
         WHERE tippee = %(username)s
           AND context = 'take'
           AND extract(year from timestamp) = %(year)s
      GROUP BY tipper
    """,
                                  params,
                                  back_as=back_as)

    if key:
        try:
            return out[key]()
        except KeyError:
            raise Response(400, "bad key `%s`" % key)
    elif require_key:
        raise Response(400, "missing `key` parameter")
    else:
        return {k: v() for k, v in out.items()}
Example #21
0
def _typecast(key, value):
    """Given two strings, return a string, and an int or string.
    """
    if key.endswith('.int'):    # you can typecast to int
        key = key[:-4]
        try:
            value = int(value)
        except ValueError:
            raise Response(404)
    else:                       # otherwise it's ASCII
        try:
            value = value.decode('ASCII')
        except UnicodeDecodeError:
            raise Response(400)
    return key, value
Example #22
0
def sign_in_with_form_data(body, state):
    p = None
    _, website = state['_'], state['website']

    if body.get('log-in.id'):
        id = body.pop('log-in.id')
        k = 'email' if '@' in id else 'username'
        p = Participant.authenticate(k, 'password', id,
                                     body.pop('log-in.password'))
        if not p:
            state['sign-in.error'] = _("Bad username or password.")
        if p and p.status == 'closed':
            p.update_status('active')

    elif body.get('sign-in.username'):
        if body.pop('sign-in.terms') != 'agree':
            raise Response(400, 'you have to agree to the terms')
        kind = body.pop('sign-in.kind')
        if kind not in ('individual', 'organization'):
            raise Response(400, 'bad kind')
        with website.db.get_cursor() as c:
            p = Participant.make_active(body.pop('sign-in.username'),
                                        kind,
                                        body.pop('sign-in.password'),
                                        cursor=c)
            p.add_email(body.pop('sign-in.email'), cursor=c)
        p.authenticated = True

    elif body.get('email-login.email'):
        email = body.pop('email-login.email')
        p = Participant._from_thing('email', email)
        if p:
            p.start_session()
            qs = {'log-in.id': p.id, 'log-in.token': p.session_token}
            p.send_email(
                'password_reset',
                email=email,
                link=p.url('settings/', qs),
                link_validity=SESSION_TIMEOUT,
            )
            state['email-login.sent-to'] = email
        else:
            state['sign-in.error'] = _(
                "We didn't find any account whose primary email address is {0}.",
                email)
        p = None

    return p
def test_get_response_406_gives_list_of_acceptable_types(mk):
    mk(('index.spt', NEGOTIATED_RESOURCE))
    request = StubRequest.from_fs('index.spt')
    request.headers['Accept'] = 'cheese/head'
    actual = raises(Response, get_response, request, Response()).value.body
    expected = "The following media types are available: text/plain, text/html."
    assert actual == expected
Example #24
0
    def api_error_handler(self, response, is_user_session):
        status = response.status_code
        if status == 404:
            raise Response(404, response.text)
        if status == 429 and is_user_session:
            limit, remaining, reset = self.get_ratelimit_headers(response)

            def msg(_, to_age):
                if remaining == 0 and reset:
                    return _(
                        "You've consumed your quota of requests, you can try again in {0}.",
                        to_age(reset))
                else:
                    return _(
                        "You're making requests too fast, please try again later."
                    )

            raise LazyResponse(status, msg)
        if status != 200:
            log('{} api responded with {}:\n{}'.format(self.name, status,
                                                       response.text),
                level=logging.ERROR)
            msg = lambda _: _("{0} returned an error, please try again later.",
                              self.display_name)
            raise LazyResponse(502, msg)
Example #25
0
 def get_query_id(self, querystring):
     token = querystring['access_token']
     i = token.rfind('.')
     data, data_hash = token[:i], token[i + 1:]
     if data_hash != hashlib.md5(data + '.' + self.api_secret).hexdigest():
         raise Response(400, 'Invalid hash in access_token')
     return querystring['query_id']
Example #26
0
def test_response_headers_protect_against_crlf_injection():
    response = Response()

    def inject():
        response.headers['Location'] = 'foo\r\nbar'

    raises(CRLFInjection, inject)
def outbound(response):
    from gittip import db
    session = {}
    if 'user' in response.request.context:
        user = response.request.context['user']
        if not isinstance(user, User):
            raise Response(
                400, "If you define 'user' in a simplate it has to "
                "be a User instance.")
        session = user.session
    if not session:  # user is anonymous
        if 'session' not in response.request.headers.cookie:
            # no cookie in the request, don't set one on response
            return
        else:
            # expired cookie in the request, instruct browser to delete it
            response.headers.cookie['session'] = ''
            expires = 0
    else:  # user is authenticated
        response.headers['Expires'] = BEGINNING_OF_EPOCH  # don't cache
        response.headers.cookie['session'] = session['session_token']
        expires = session['session_expires'] = time.time() + TIMEOUT
        SQL = """
            UPDATE participants SET session_expires=%s WHERE session_token=%s
        """
        db.execute(SQL, (datetime.datetime.fromtimestamp(expires),
                         session['session_token']))

    cookie = response.headers.cookie['session']
    # I am not setting domain, because it is supposed to default to what we
    # want: the domain of the object requested.
    #cookie['domain']
    cookie['path'] = '/'
    cookie['expires'] = rfc822.formatdate(expires)
    cookie['httponly'] = "Yes, please."
def test_handles_busted_accept(mk):
    mk(('index.spt', NEGOTIATED_RESOURCE))
    request = StubRequest.from_fs('index.spt')
    # Set an invalid Accept header so it will return default (text/plain)
    request.headers['Accept'] = 'text/html;'
    actual = get_response(request, Response()).body
    assert actual == "Greetings, program!\n"
Example #29
0
    def rebuild_url(self):
        """Return a full URL for this request, per PEP 333:

            http://www.python.org/dev/peps/pep-0333/#url-reconstruction

        This function is kind of naive.

        """
        # http://docs.python.org/library/wsgiref.html#wsgiref.util.guess_scheme
        scheme = self.headers.one('HTTPS') and 'https' or 'http'
        url = scheme
        url += '://'

        if 'X-Forwarded-Host' in self.headers:
            url += self.headers.one('X-Forwarded-Host')
        elif 'Host' in self.headers:
            url += self.headers.one('Host')
        else:
            # per spec, return 400 if no Host header given
            raise Response(400)

        url += urllib.quote(self.path.raw)
        # screw params, fragment?
        if self.raw_querystring:
            url += '?' + self.raw_querystring
        return url
def test_can_override_default_renderer_entirely(mk):
    mk(('.aspen/configure-aspen.py', OVERRIDE_SIMPLATE),
       ('index.spt', NEGOTIATED_RESOURCE))
    request = StubRequest.from_fs('index.spt')
    request.headers['Accept'] = 'text/plain'
    actual = get_response(request, Response()).body
    assert actual == "glubber"