#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helpers for manipulating HTTP requests.
"""
__authors__ = [
'"Todd Larsen" <tlarsen@google.com>',
]
import os
import urlparse
def getSingleIndexedParamValue(request, param_name, values=()):
"""Returns a value indexed by a query parameter in the HTTP request.
Args:
request: the Django HTTP request object
param_name: name of the query parameter in the HTTP request
values: list (or tuple) of ordered values; one of which is
retrieved by the index value of the param_name argument in
the HTTP request
Returns:
None if the query parameter was not present, was not an integer, or
was an integer that is not a valid [0..len(values)-1] index into
the values list.
Otherwise, returns values[int(param_name value)]
"""
value_idx = request.GET.get(param_name)
if isinstance(value_idx, (tuple, list)):
# keep only the first argument if multiple are present
value_idx = value_idx[0]
try:
# GET parameter 'param_name' should be an integer value index
value_idx = int(value_idx) if value_idx is not None else -1
except ValueError:
# ignore bogus or missing parameter values, so return None (no message)
return None
if value_idx < 0:
# value index out of range, so return None (no value)
return None
if value_idx >= len(values):
# value index out of range, so return None (no value)
return None
# return value associated with valid value index
return values[value_idx]
def getSingleIndexedParamValueIfMissing(value, request, param_name,
values=()):
"""Returns missing value indexed by a query parameter in the HTTP request.
Args:
value: an existing value, or a "False" value such as None
request, param_name, values: see getSingleIndexParamValue()
Returns:
value, if value is "non-False"
Otherwise, returns getSingleIndexedParamValue() result.
"""
if value:
# value already present, so return it
return value
return getSingleIndexedParamValue(request, param_name, values=values)
# TODO(tlarsen): write getMultipleIndexParamValues() that returns a
# list of values if present, omitting those values that are
# out of range
def isReferrerSelf(request,
expected_prefix=None, suffix=None, url_name=None):
"""Returns True if HTTP referrer path starts with the HTTP request path.
Args:
request: the Django HTTP request object; request.path is used if
expected_path is not supplied (the most common usage)
expected_prefix: optional HTTP path to use instead of the one in
request.path; default is None (use request.path)
suffix: suffix to remove from the HTTP request path before comparing
it to the HTTP referrer path in the HTTP request object headers
(this is often an link ID, for example, that may be changing from
a POST referrer to a GET redirect target)
url_name: url name of the entity that is being created
Returns:
True if HTTP referrer path begins with the HTTP request path (either
request.path or expected_prefix instead if it was supplied), after
any suffix was removed from that request path
False otherwise
"""
http_from = request.META.get('HTTP_REFERER')
if not http_from:
# no HTTP referrer, so cannot possibly start with expected prefix
return False
http_host = 'http://%s/%s' % (os.environ['HTTP_HOST'], url_name)
if http_from.startswith(http_host):
return True
from_path = urlparse.urlparse(http_from).path
if not expected_prefix:
# use HTTP request path, since expected_prefix was not supplied
expected_prefix = request.path
if suffix:
# remove suffix (such as a link ID) before comparison
chars_to_remove = len(suffix)
if not suffix.startswith('/'):
chars_to_remove = chars_to_remove + 1
expected_prefix = expected_prefix[:-chars_to_remove]
if not from_path.startswith(expected_prefix):
# expected prefix did not match first part of HTTP referrer path
return False
# HTTP referrer started with (possibly truncated) expected prefix
return True
def replaceSuffix(path, old_suffix, new_suffix=None, params=None):
"""Replace the last part of a URL path with something else.
Also appends an optional list of query parameters. Used for
replacing, for example, one link ID at the end of a relative
URL path with another.
Args:
path: HTTP request relative URL path (with no query arguments)
old_suffix: expected suffix at the end of request.path component;
if any False value (such as None), the empty string '' is used
new_suffix: if non-False, appended to request.path along with a
'/' separator (after removing old_suffix if necessary)
params: an optional dictionary of query parameters to append to
the redirect target; appended as ?<key1>=<value1>&<key2>=...
Returns:
/path/with/new_suffix?a=1&b=2
"""
if not old_suffix:
old_suffix = ''
old_suffix = '/' + old_suffix
if path.endswith(old_suffix):
# also removes any trailing '/' if old_suffix was empty
path = path[:-len(old_suffix)]
if new_suffix:
# if present, appends new_suffix, after '/' separator
path = '%s/%s' % (path, new_suffix)
if params:
# appends any query parameters, after a '?' and separated by '&'
path = '%s?%s' % (path, '&'.join(
['%s=%s' % (p,v) for p,v in params.iteritems()]))
return path