Source code for gimme.request

import re
from .headers import RequestHeaders
from .dotdict import DotDict
from .uri import QueryString
from .errors import AcceptFormatError
from .parsers.contenttype import ContentType
from .parsers.accepted import AcceptedList


[docs]class Request(object): ''' The Request class is responsible for parsing the request headers and body into Pythonic shindigs that are (supposed to be) very easy to work with. :ivar app: The Gimme application. :ivar environ: The WSGI environ dict. :ivar headers: The request headers (an instance of :class:`gimme.headers.RequestHeaders`). :ivar wsgi: The WSGI headers. Also an instance of :class:`gimme.headers.RequestHeaders`. :ivar params: A :class:`gimme.dotdict.DotDict` of the parameters from the route URI. :ivar query: The query string in a dictionary-like object. :ivar accepted: A handy parsing of the HTTP "Accept" header. An instance of :class:`gimme.parsers.accepted.AcceptedList`. :ivar accepted_languages: A handy parsing of the HTTP "Accept-Language" header. An instance of :class:`gimme.parsers.accepted.AcceptedList`. :ivar accepted_charsets: A handy parsing of the HTTP "Accept-Charset" header. An instance of :class:`gimme.parsers.accepted.AcceptedList`. :ivar cookies: The raw HTTP "Cookie" string. :ivar type: Either an instance of :class:`gimme.parsers.contenttype.ContentType` if the HTTP header "Content-Type" is present or ``None``. :param app: The Gimme application. :param environ: The WSGI environ dict. :param match: The matching route, if any. ''' _host_pattern = re.compile('^([^:]*)(:[0-9]+)?') def __init__(self, app, environ, match=None): self.app = app self.environ = environ self.headers = RequestHeaders() self.wsgi = RequestHeaders() self.params = DotDict(match.match.groupdict() if match else {}) self.__raw_body = None self._populate_headers(environ) self.query = QueryString(self.headers.get('query_string', '')) self.accepted = AcceptedList.parse( self.headers.get('accept', ''), ContentType) self.accepted_languages = AcceptedList.parse( self.headers.get('accept_language', '')) self.accepted_charsets = AcceptedList.parse( self.headers.get('accept_charset', '')) self.cookies = self.headers.get('cookie', '') self.type = (ContentType(self.headers.content_type) if 'content_type' in self.headers else None) def _populate_headers(self, environ): for k, v in environ.iteritems(): key = k.lower() if key.startswith('http_'): self.headers[key[5:]] = v elif key.startswith('wsgi.'): self.wsgi[key[5:]] = v else: self.headers[key] = v
[docs] def get(self, key): ''' Return the specified request header. :param key: The header to return. ''' return self.headers[key.replace('-', '_')]
[docs] def accepts(self, content_type): ''' Tests if a given content type is in the HTTP "Accept" header. :param content_type: The content type to check for. ''' return content_type in self.accepted
[docs] def accepts_language(self, language): ''' Tests if a given language is in the HTTP "Accept-Language" header. :param language: The language to check for. ''' return language in self.accepted_languages
[docs] def accepts_charset(self, charset): ''' Tests if a given charset is in the HTTP "Accept-Charset" header. :param charset: The charset to check for. ''' return charset in self.accepted_charsets
@property
[docs] def raw_body(self): ''' The raw request body. ''' if self.__raw_body is None: if (self.headers.get('request_method', None) in ('PUT', 'POST') and 'content_length' in self.headers): content_length = int(self.headers.content_length) self.__raw_body = self.wsgi.input.read(content_length) else: self.__raw_body = '' return self.__raw_body
[docs] def param(self, key): ''' A simple helper method that looks for a given key in three places: self.params, self.body, and self.query. :param key: The parameter to look for. ''' if key in self.params: return self.params[key] elif hasattr(self, 'body') and key in self.body: return self.body[key] elif key in self.query: return self.query[key] raise KeyError(key)
@property
[docs] def xhr(self): ''' Whether or not the HTTP header "X-Requested-With" is present and set to "XMLHttpRequest". ''' return self.headers.get('x_requested_with', None) == 'XMLHttpRequest'
@property
[docs] def path(self): ''' A shortcut for the "PATH_INFO" environ parameter. ''' return self.headers.get('path_info', None)
@property
[docs] def host(self): ''' A shortcut for the HTTP "Host" header. *Note: Strips any port off of the header.* ''' raw_host = self.headers.get('host', '') return self._host_pattern.match(raw_host).group(1)
@property
[docs] def subdomains(self): ''' A list of subdomains per the ``host`` attribute. ''' split = self.headers.get('host', '').split('.') return split[:-2] if len(split) > 2 else []
@property
[docs] def ip(self): ''' A shortcut for the "REMOTE_ADDR" environ parameter. ''' return self.headers.get('remote_addr', None)
@property
[docs] def secure(self): ''' Right now, Gimme only runs in standard HTTP mode. SSL should be implemented at the HTTP server end and piped to Gimme via FastCGI. ''' return False
@property
[docs] def original_url(self): ''' A shortcut for the "REQUEST_URI" environ parameter. ''' return self.headers.get('request_uri', None)
@property
[docs] def protocol(self): ''' Gimme only supports HTTP as of the time of this writing. ''' return 'http'