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')
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")
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', ''))
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__)
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.")