Ejemplo n.º 1
0
        class A(object):
            environ = {'string': 'abc', 'number': '42'}

            string = utils.environ_property('string')
            missing = utils.environ_property('missing', 'spam')
            read_only = utils.environ_property('number')
            number = utils.environ_property('number', load_func=int)
            broken_number = utils.environ_property('broken_number', load_func=int)
            date = utils.environ_property('date', None, parse_date, http_date,
                                    read_only=False)
            foo = utils.environ_property('foo')
Ejemplo n.º 2
0
    class A(object):
        environ = {"string": "abc", "number": "42"}

        string = utils.environ_property("string")
        missing = utils.environ_property("missing", "spam")
        read_only = utils.environ_property("number")
        number = utils.environ_property("number", load_func=int)
        broken_number = utils.environ_property("broken_number", load_func=int)
        date = utils.environ_property(
            "date", None, parse_date, http_date, read_only=False
        )
        foo = utils.environ_property("foo")
Ejemplo n.º 3
0
class CommonRequestDescriptorsMixin(object):
    content_type = environ_property('CONTENT_TYPE', doc='\n         The Content-Type entity-header field indicates the media type of\n         the entity-body sent to the recipient or, in the case of the HEAD\n         method, the media type that would have been sent had the request\n         been a GET.')
    content_length = environ_property('CONTENT_LENGTH', None, int, str, doc='\n         The Content-Length entity-header field indicates the size of the\n         entity-body in bytes or, in the case of the HEAD method, the size of\n         the entity-body that would have been sent had the request been a\n         GET.')
    referrer = environ_property('HTTP_REFERER', doc='\n        The Referer[sic] request-header field allows the client to specify,\n        for the server\'s benefit, the address (URI) of the resource from which\n        the Request-URI was obtained (the "referrer", although the header\n        field is misspelled).')
    date = environ_property('HTTP_DATE', None, parse_date, doc='\n        The Date general-header field represents the date and time at which\n        the message was originated, having the same semantics as orig-date\n        in RFC 822.')
    max_forwards = environ_property('HTTP_MAX_FORWARDS', None, int, doc='\n         The Max-Forwards request-header field provides a mechanism with the\n         TRACE and OPTIONS methods to limit the number of proxies or gateways\n         that can forward the request to the next inbound server.')

    def _parse_content_type(self):
        if not hasattr(self, '_parsed_content_type'):
            self._parsed_content_type = parse_options_header(self.environ.get('CONTENT_TYPE', ''))

    @property
    def mimetype(self):
        self._parse_content_type()
        return self._parsed_content_type[0]

    @property
    def mimetype_params(self):
        self._parse_content_type()
        return self._parsed_content_type[1]

    @cached_property
    def pragma(self):
        return parse_set_header(self.environ.get('HTTP_PRAGMA', ''))
Ejemplo n.º 4
0
class BaseRequest(object):
    """
    Base Request class.
    """
    charset = 'utf-8'
    is_behind_proxy = False

    def __init__(self, environ, populate_request=True):
        self.environ = environ
        if populate_request:
            self.environ['werkzeug.request'] = self
        self._data_stream = None

    def from_values(cls, path='/', base_url=None, query_string=None, **options):
        """
        Create a new request object based on the values provided.  If
        environ is given missing values are filled from there.  This method
        is useful for small scripts when you need to simulate a request
        from an url.  Do not use this method for unittesting, there is a
        full featured client object in `werkzeug.test` that allows to create
        multipart requests etc.
        """
        if isinstance(query_string, dict):
            query_string = url_encode(query_string, cls.charset)
        environ = options.pop('environ', None)
        new_env = create_environ(path, base_url, query_string, **options)
        result = {}
        if environ is not None:
            result.update(environ)
        result.update(new_env)
        return cls(result)
    from_values = classmethod(from_values)

    def _get_file_stream(self):
        """Called to get a stream for the file upload.

        This must provide a file-like class with `read()`, `readline()`
        and `seek()` methods that is both writeable and readable."""
        return tempfile.TemporaryFile('w+b')

    def _load_post_data(self):
        """Method used internally to retrieve submitted data."""
        self._data_stream = _empty_stream
        post = []
        files = []
        if self.environ['REQUEST_METHOD'] in ('POST', 'PUT'):
            storage = _StorageHelper(self.environ, self._get_file_stream)
            if storage.file:
                self._data_stream = storage.file
            if storage.list is not None:
                for key in storage.keys():
                    values = storage[key]
                    if not isinstance(values, list):
                        values = [values]
                    for item in values:
                        if getattr(item, 'filename', None) is not None:
                            fn = item.filename.decode(self.charset, 'ignore')
                            # fix stupid IE bug (IE6 sends the whole path)
                            if fn[1:3] == ':\\':
                                fn = fn.split('\\')[-1]
                            files.append((key, FileStorage(key, fn, item.type,
                                          item.length, item.file)))
                        else:
                            post.append((key, item.value.decode(self.charset,
                                                                'ignore')))
        self._form = MultiDict(post)
        self._files = MultiDict(files)

    def stream(self):
        """
        The parsed stream if the submitted data was not multipart or
        urlencoded form data.
        """
        if self._data_stream is None:
            self._load_post_data()
        return self._data_stream
    stream = property(stream, doc=stream)
    input_stream = environ_property('wsgi.input', 'The WSGI input stream.')

    def args(self):
        """URL parameters"""
        items = []
        qs = self.environ.get('QUERY_STRING', '')
        for key, values in cgi.parse_qs(qs, True).iteritems():
            for value in values:
                value = value.decode(self.charset, 'ignore')
                items.append((key, value))
        return MultiDict(items)
    args = lazy_property(args)

    def data(self):
        """
        This reads the buffered incoming data from the client into the string.
        """
        return self.stream.read()
    data = lazy_property(data)

    def form(self):
        """
        Form parameters.  Currently it's not guaranteed that the MultiDict
        returned by this function is ordered in the same way as the submitted
        form data.  The reason for this is that the underlaying cgi library
        uses a dict internally and loses the ordering.
        """
        if not hasattr(self, '_form'):
            self._load_post_data()
        return self._form
    form = lazy_property(form)

    def values(self):
        """combined multi dict for `args` and `form`"""
        return CombinedMultiDict([self.args, self.form])
    values = lazy_property(values)

    def files(self):
        """File uploads."""
        if not hasattr(self, '_files'):
            self._load_post_data()
        return self._files
    files = lazy_property(files)

    def cookies(self):
        """Stored Cookies."""
        cookie = SimpleCookie()
        cookie.load(self.environ.get('HTTP_COOKIE', ''))
        result = {}
        for key, value in cookie.iteritems():
            result[key] = value.value.decode(self.charset, 'ignore')
        return result
    cookies = lazy_property(cookies)

    def headers(self):
        """The headers from the WSGI environ."""
        return EnvironHeaders(self.environ)
    headers = lazy_property(headers)

    def accept_mimetypes(self):
        """List of mimetypes this client supports."""
        if not 'HTTP_ACCEPT' in self.environ:
            return Accept(None)
        return parse_accept_header(self.environ['HTTP_ACCEPT'])
    accept_mimetypes = lazy_property(accept_mimetypes)

    def accept_charsets(self):
        """list of charsets this client supports."""
        if not 'HTTP_ACCEPT_CHARSET' in self.environ:
            return Accept(None)
        return parse_accept_header(self.environ['HTTP_ACCEPT_CHARSET'])
    accept_charsets = lazy_property(accept_charsets)

    def accept_encodings(self):
        """
        List of encodings this client accepts.  Encodings in a HTTP term are
        compression encodings such as gzip.  For charsets have a look at
        `accept_charset`.
        """
        if not 'HTTP_ACCEPT_ENCODING' in self.environ:
            return Accept(None)
        return parse_accept_header(self.environ['HTTP_ACCEPT_ENCODING'])
    accept_encodings = lazy_property(accept_encodings)

    def accept_languages(self):
        """List of languages this client accepts."""
        if not 'HTTP_ACCEPT_LANGUAGE' in self.environ:
            return Accept(None)
        return parse_accept_header(self.environ['HTTP_ACCEPT_LANGUAGE'])
    accept_languages = lazy_property(accept_languages)

    def cache_control(self):
        """A `CacheControl` object for the incoming cache control headers."""
        if not 'HTTP_CACHE_CONTROL' in self.environ:
            return CacheControl(None)
        return parse_cache_control_header(self.environ['HTTP_CACHE_CONTROL'])

    def path(self):
        """Requested path."""
        path = '/' + (self.environ.get('PATH_INFO') or '').lstrip('/')
        return path.decode(self.charset, 'ignore')
    path = lazy_property(path)

    def script_root(self):
        """The root path of the script."""
        path = (self.environ.get('SCRIPT_NAME') or '').rstrip('/')
        return path.decode(self.charset, 'ignore')
    script_root = lazy_property(script_root)

    def url(self):
        """The reconstructed current URL"""
        return get_current_url(self.environ)
    url = lazy_property(url)

    def base_url(self):
        """Like `url` but without the querystring"""
        return get_current_url(self.environ, strip_querystring=True)
    base_url = lazy_property(base_url)

    def url_root(self):
        """The full URL root (with hostname), this is the application root."""
        return get_current_url(self.environ, True)
    url_root = lazy_property(url_root)

    def host_url(self):
        """Just the host with scheme."""
        return get_current_url(self.environ, host_only=True)
    host_url = lazy_property(host_url)

    def host(self):
        """Just the host including the port if available."""
        return get_host(self.environ)
    host = lazy_property(host)

    def is_secure(self):
        """True if the request is secure."""
        return self.environ['wsgi.url_scheme'] == 'https'
    is_secure = property(is_secure, doc=is_secure.__doc__)

    query_string = environ_property('QUERY_STRING', '', read_only=True)
    remote_addr = environ_property('REMOTE_ADDR', read_only=True)
    method = environ_property('REQUEST_METHOD', 'GET', read_only=True)

    def access_route(self):
        """
        If an forwarded header exists this is a list of all ip addresses
        from the client ip to the last proxy server.
        """
        if 'HTTP_X_FORWARDED_FOR' in self.environ:
            addr = self.environ['HTTP_X_FORWARDED_FOR'].split(',')
            return [x.strip() for x in addr]
        elif 'REMOTE_ADDR' in self.environ:
            return [self.environ['REMOTE_ADDR']]
        return []
    access_route = lazy_property(access_route)

    def remote_addr(self):
        """The remote address of the client."""
        if self.is_behind_proxy and self.access_route:
            return self.access_route[0]
        return self.environ.get('REMOTE_ADDR')
    remote_addr = property(remote_addr)

    def is_xhr(self):
        """
        True if the request was triggered via an JavaScript XMLHttpRequest.
        This only works with libraries that support the X-Requested-With
        header and set it to "XMLHttpRequest".  Libraries that do that are
        prototype, jQuery and Mochikit.
        """
        return self.environ.get('X_REQUESTED_WITH') == 'XmlHttpRequest'
    is_xhr = property(is_xhr, doc=is_xhr.__doc__)
Ejemplo n.º 5
0
class BaseRequest(object):
    charset = 'utf-8'
    encoding_errors = 'ignore'
    is_behind_proxy = False
    max_content_length = None
    max_form_memory_size = None
    parameter_storage_class = ImmutableMultiDict
    list_storage_class = ImmutableList
    dict_storage_class = ImmutableTypeConversionDict

    def __init__(self, environ, populate_request = True, shallow = False):
        self.environ = environ
        if populate_request and not shallow:
            self.environ['werkzeug.request'] = self
        self.shallow = shallow

    def __repr__(self):
        args = []
        try:
            args.append("'%s'" % self.url)
            args.append('[%s]' % self.method)
        except:
            args.append('(invalid WSGI environ)')

        return '<%s %s>' % (self.__class__.__name__, ' '.join(args))

    @property
    def url_charset(self):
        return self.charset

    @classmethod
    def from_values(cls, *args, **kwargs):
        from werkzeug.test import EnvironBuilder
        charset = kwargs.pop('charset', cls.charset)
        builder = EnvironBuilder(*args, **kwargs)
        try:
            return builder.get_request(cls)
        finally:
            builder.close()

    @classmethod
    def application(cls, f):
        return _patch_wrapper(f, lambda *a: f(*(a[:-2] + (cls(a[-2]),)))(*a[-2:]))

    def _get_file_stream(self, total_content_length, content_type, filename = None, content_length = None):
        return default_stream_factory(total_content_length, content_type, filename, content_length)

    def _load_form_data(self):
        if 'stream' in self.__dict__:
            return
        if self.shallow:
            raise RuntimeError('A shallow request tried to consume form data.  If you really want to do that, set `shallow` to False.')
        data = None
        stream = _empty_stream
        if self.environ['REQUEST_METHOD'] in ('POST', 'PUT'):
            try:
                data = parse_form_data(self.environ, self._get_file_stream, self.charset, self.encoding_errors, self.max_form_memory_size, self.max_content_length, cls=self.parameter_storage_class, silent=False)
            except ValueError as e:
                self._form_parsing_failed(e)

        else:
            content_length = self.headers.get('content-length', type=int)
            if content_length is not None:
                stream = LimitedStream(self.environ['wsgi.input'], content_length)
        if data is None:
            data = (stream, self.parameter_storage_class(), self.parameter_storage_class())
        d = self.__dict__
        d['stream'], d['form'], d['files'] = data

    def _form_parsing_failed(self, error):
        pass

    @cached_property
    def stream(self):
        self._load_form_data()
        return self.stream

    input_stream = environ_property('wsgi.input', "The WSGI input stream.\nIn general it's a bad idea to use this one because you can easily read past the boundary.  Use the :attr:`stream` instead.")

    @cached_property
    def args(self):
        return url_decode(self.environ.get('QUERY_STRING', ''), self.url_charset, errors=self.encoding_errors, cls=self.parameter_storage_class)

    @cached_property
    def data(self):
        return self.stream.read()

    @cached_property
    def form(self):
        self._load_form_data()
        return self.form

    @cached_property
    def values(self):
        args = []
        for d in (self.args, self.form):
            if not isinstance(d, MultiDict):
                d = MultiDict(d)
            args.append(d)

        return CombinedMultiDict(args)

    @cached_property
    def files(self):
        self._load_form_data()
        return self.files

    @cached_property
    def cookies(self):
        return parse_cookie(self.environ, self.charset, cls=self.dict_storage_class)

    @cached_property
    def headers(self):
        return EnvironHeaders(self.environ)

    @cached_property
    def path(self):
        path = '/' + (self.environ.get('PATH_INFO') or '').lstrip('/')
        return _decode_unicode(path, self.url_charset, self.encoding_errors)

    @cached_property
    def script_root(self):
        path = (self.environ.get('SCRIPT_NAME') or '').rstrip('/')
        return _decode_unicode(path, self.url_charset, self.encoding_errors)

    @cached_property
    def url(self):
        return get_current_url(self.environ)

    @cached_property
    def base_url(self):
        return get_current_url(self.environ, strip_querystring=True)

    @cached_property
    def url_root(self):
        return get_current_url(self.environ, True)

    @cached_property
    def host_url(self):
        return get_current_url(self.environ, host_only=True)

    @cached_property
    def host(self):
        return get_host(self.environ)

    query_string = environ_property('QUERY_STRING', '', read_only=True, doc='The URL parameters as raw bytestring.')
    method = environ_property('REQUEST_METHOD', 'GET', read_only=True, doc="The transmission method. (For example ``'GET'`` or ``'POST'``).")

    @cached_property
    def access_route(self):
        if 'HTTP_X_FORWARDED_FOR' in self.environ:
            addr = self.environ['HTTP_X_FORWARDED_FOR'].split(',')
            return self.list_storage_class([ x.strip() for x in addr ])
        if 'REMOTE_ADDR' in self.environ:
            return self.list_storage_class([self.environ['REMOTE_ADDR']])
        return self.list_storage_class()

    @property
    def remote_addr(self):
        if self.is_behind_proxy and self.access_route:
            return self.access_route[0]
        return self.environ.get('REMOTE_ADDR')

    remote_user = environ_property('REMOTE_USER', doc='\n        If the server supports user authentication, and the script is\n        protected, this attribute contains the username the user has\n        authenticated as.')
    is_xhr = property(lambda x: x.environ.get('HTTP_X_REQUESTED_WITH', '').lower() == 'xmlhttprequest', doc='\n        True if the request was triggered via a JavaScript XMLHttpRequest.\n        This only works with libraries that support the `X-Requested-With`\n        header and set it to "XMLHttpRequest".  Libraries that do that are\n        prototype, jQuery and Mochikit and probably some more.')
    is_secure = property(lambda x: x.environ['wsgi.url_scheme'] == 'https', doc='`True` if the request is secure.')
    is_multithread = environ_property('wsgi.multithread', doc='\n        boolean that is `True` if the application is served by\n        a multithreaded WSGI server.')
    is_multiprocess = environ_property('wsgi.multiprocess', doc='\n        boolean that is `True` if the application is served by\n        a WSGI server that spawns multiple processes.')
    is_run_once = environ_property('wsgi.run_once', doc="\n        boolean that is `True` if the application will be executed only\n        once in a process lifetime.  This is the case for CGI for example,\n        but it's not guaranteed that the exeuction only happens one time.")