Пример #1
0
 def add_cors_headers(status, headers, exc_info=None):
     headers = Headers(headers)
     headers.add("Access-Control-Allow-Origin", self.origin(environ))
     headers.add("Access-Control-Allow-Headers", "Origin, Content-Type")
     headers.add("Access-Control-Allow-Credentials", "true")
     headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
     headers.add("Access-Control-Expose-Headers", "X-Set-Cookie")
     return start_response(status, headers.to_list(), exc_info)
Пример #2
0
 def add_cors_headers(status, headers, exc_info=None):
     headers = Headers(headers)
     headers.add("Access-Control-Allow-Origin", self.origin(environ))
     headers.add("Access-Control-Allow-Credentials", "true")
     headers.add("Access-Control-Allow-Methods", ", ".join(self.methods))
     if self.allowed:
         headers.add("Access-Control-Allow-Headers", ", ".join(self.allowed))
     if self.exposed:
         headers.add("Access-Control-Expose-Headers", ", ".join(self.exposed))
     return start_response(status, headers.to_list(), exc_info)
Пример #3
0
 def add_cors_headers(status, headers, exc_info=None):
     headers = Headers(headers)
     headers.add("Access-Control-Allow-Origin", self.origin(environ))
     headers.add("Access-Control-Allow-Credentials", "true")
     headers.add("Access-Control-Allow-Methods", ", ".join(self.methods))
     if self.allowed:
         headers.add("Access-Control-Allow-Headers", ", ".join(self.allowed))
     if self.exposed:
         headers.add("Access-Control-Expose-Headers", ", ".join(self.exposed))
     return start_response(status, headers.to_list(), exc_info)
Пример #4
0
 def add_cors_headers(status, headers, exc_info=None):
     headers = Headers(headers)
     headers.add("Access-Control-Allow-Origin",
                 get_origin(status, headers))
     headers.add("Access-Control-Allow-Headers",
                 cfg.get("cors_headers"))
     headers.add("Access-Control-Allow-Credentials",
                 cfg.get("cors_credentials"))
     headers.add("Access-Control-Allow-Methods",
                 cfg.get("cors_methods"))
     headers.add("Access-Control-Expose-Headers",
                 cfg.get("cors_expose_headers"))
     return start_response(status, headers.to_list(), exc_info)
Пример #5
0
 def add_cors_headers(status, headers, exc_info=None):
     headers = Headers(headers)
     headers.add("Access-Control-Allow-Origin",
                 get_origin(status, headers))
     headers.add("Access-Control-Allow-Headers",
                 cfg.get("cors_headers"))
     headers.add("Access-Control-Allow-Credentials",
                 cfg.get("cors_credentials"))
     headers.add("Access-Control-Allow-Methods",
                 cfg.get("cors_methods"))
     headers.add("Access-Control-Expose-Headers",
                 cfg.get("cors_expose_headers"))
     return start_response(status, headers.to_list(), exc_info)
Пример #6
0
        def add_cors_headers(status, headers, exc_info=None):

            for host in self.hosts:
                if environ.get("HTTP_ORIGIN", None) == host.rstrip("/"):
                    origin = host.rstrip("/")
                    break
            else:
                origin = host.rstrip("/")

            headers = Headers(headers)
            headers.add("Access-Control-Allow-Origin", origin)
            headers.add("Access-Control-Allow-Headers", "Origin, Content-Type")
            headers.add("Access-Control-Allow-Credentials", "true")
            headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
            headers.add("Access-Control-Expose-Headers", "X-Set-Cookie")
            return start_response(status, headers.to_list(), exc_info)
Пример #7
0
class BaseResponse(object):
    charset = 'utf-8'
    default_status = 200
    default_mimetype = 'text/plain'
    implicit_sequence_conversion = True

    def __init__(self, response = None, status = None, headers = None, mimetype = None, content_type = None, direct_passthrough = False):
        if isinstance(headers, Headers):
            self.headers = headers
        elif not headers:
            self.headers = Headers()
        else:
            self.headers = Headers(headers)
        if content_type is None:
            if mimetype is None and 'content-type' not in self.headers:
                mimetype = self.default_mimetype
            if mimetype is not None:
                mimetype = get_content_type(mimetype, self.charset)
            content_type = mimetype
        if content_type is not None:
            self.headers['Content-Type'] = content_type
        if status is None:
            status = self.default_status
        if isinstance(status, (int, long)):
            self.status_code = status
        else:
            self.status = status
        self.direct_passthrough = direct_passthrough
        self._on_close = []
        if response is None:
            self.response = []
        elif isinstance(response, basestring):
            self.data = response
        else:
            self.response = response

    def call_on_close(self, func):
        self._on_close.append(func)

    def __repr__(self):
        if self.is_sequence:
            body_info = '%d bytes' % sum(map(len, self.iter_encoded()))
        else:
            body_info = self.is_streamed and 'streamed' or 'likely-streamed'
        return '<%s %s [%s]>' % (self.__class__.__name__, body_info, self.status)

    @classmethod
    def force_type(cls, response, environ = None):
        if not isinstance(response, BaseResponse):
            if environ is None:
                raise TypeError('cannot convert WSGI application into response objects without an environ')
            response = BaseResponse(*_run_wsgi_app(response, environ))
        response.__class__ = cls
        return response

    @classmethod
    def from_app(cls, app, environ, buffered = False):
        return cls(*_run_wsgi_app(app, environ, buffered))

    def _get_status_code(self):
        try:
            return int(self.status.split(None, 1)[0])
        except ValueError:
            return 0

    def _set_status_code(self, code):
        try:
            self.status = '%d %s' % (code, HTTP_STATUS_CODES[code].upper())
        except KeyError:
            self.status = '%d UNKNOWN' % code

    status_code = property(_get_status_code, _set_status_code, 'The HTTP Status code as number')
    del _get_status_code
    del _set_status_code

    def _get_data(self):
        self._ensure_sequence()
        return ''.join(self.iter_encoded())

    def _set_data(self, value):
        if isinstance(value, unicode):
            value = value.encode(self.charset)
        self.response = [value]

    data = property(_get_data, _set_data, doc=_get_data.__doc__)
    del _get_data
    del _set_data

    def _ensure_sequence(self, mutable = False):
        if self.is_sequence:
            if mutable and not isinstance(self.response, list):
                self.response = list(self.response)
            return
        if not self.implicit_sequence_conversion:
            raise RuntimeError('The response object required the iterable to be a sequence, but the implicit conversion was disabled.  Call make_sequence() yourself.')
        self.make_sequence()

    def make_sequence(self):
        if not self.is_sequence:
            close = getattr(self.response, 'close', None)
            self.response = list(self.iter_encoded())
            if close is not None:
                self.call_on_close(close)

    def iter_encoded(self, charset = None):
        if __debug__ and charset is not None:
            from warnings import warn
            warn(DeprecationWarning('charset was deprecated and is ignored.'), stacklevel=2)
        charset = self.charset
        for item in self.response:
            if isinstance(item, unicode):
                yield item.encode(charset)
            else:
                yield str(item)

    def set_cookie(self, key, value = '', max_age = None, expires = None, path = '/', domain = None, secure = None, httponly = False):
        self.headers.add('Set-Cookie', dump_cookie(key, value, max_age, expires, path, domain, secure, httponly, self.charset))

    def delete_cookie(self, key, path = '/', domain = None):
        self.set_cookie(key, expires=0, max_age=0, path=path, domain=domain)

    @property
    def header_list(self):
        return self.headers.to_list(self.charset)

    @property
    def is_streamed(self):
        try:
            len(self.response)
        except TypeError:
            return True

        return False

    @property
    def is_sequence(self):
        return isinstance(self.response, (tuple, list))

    def close(self):
        if hasattr(self.response, 'close'):
            self.response.close()
        for func in self._on_close:
            func()

    def freeze(self):
        self.response = list(self.iter_encoded())
        self.headers['Content-Length'] = str(sum(map(len, self.response)))

    def fix_headers(self, environ):
        self.headers[:] = self.get_wsgi_headers(environ)

    def get_wsgi_headers(self, environ):
        headers = Headers(self.headers)
        location = headers.get('location')
        if location is not None:
            if isinstance(location, unicode):
                location = iri_to_uri(location)
            headers['Location'] = urlparse.urljoin(get_current_url(environ, root_only=True), location)
        content_location = headers.get('content-location')
        if content_location is not None and isinstance(content_location, unicode):
            headers['Content-Location'] = iri_to_uri(content_location)
        if 100 <= self.status_code < 200 or self.status_code == 204:
            headers['Content-Length'] = '0'
        elif self.status_code == 304:
            remove_entity_headers(headers)
        if self.is_sequence and 'content-length' not in self.headers:
            try:
                content_length = sum((len(str(x)) for x in self.response))
            except UnicodeError:
                pass
            else:
                headers['Content-Length'] = str(content_length)

        return headers

    def get_app_iter(self, environ):
        if environ['REQUEST_METHOD'] == 'HEAD' or 100 <= self.status_code < 200 or self.status_code in (204, 304):
            return ()
        if self.direct_passthrough:
            return self.response
        return ClosingIterator(self.iter_encoded(), self.close)

    def get_wsgi_response(self, environ):
        if self.fix_headers.func_code is not BaseResponse.fix_headers.func_code:
            self.fix_headers(environ)
            headers = self.headers
        else:
            headers = self.get_wsgi_headers(environ)
        app_iter = self.get_app_iter(environ)
        return (app_iter, self.status, headers.to_list(self.charset))

    def __call__(self, environ, start_response):
        app_iter, status, headers = self.get_wsgi_response(environ)
        start_response(status, headers)
        return app_iter
Пример #8
0
def test_headers():
    # simple header tests
    headers = Headers()
    headers.add("Content-Type", "text/plain")
    headers.add("X-Foo", "bar")
    assert "x-Foo" in headers
    assert "Content-type" in headers

    headers["Content-Type"] = "foo/bar"
    assert headers["Content-Type"] == "foo/bar"
    assert len(headers.getlist("Content-Type")) == 1

    # list conversion
    assert headers.to_list() == [("Content-Type", "foo/bar"), ("X-Foo", "bar")]
    assert str(headers) == ("Content-Type: foo/bar\r\n" "X-Foo: bar\r\n" "\r\n")
    assert str(Headers()) == "\r\n"

    # extended add
    headers.add("Content-Disposition", "attachment", filename="foo")
    assert headers["Content-Disposition"] == "attachment; filename=foo"

    headers.add("x", "y", z='"')
    assert headers["x"] == r'y; z="\""'

    # defaults
    headers = Headers([("Content-Type", "text/plain"), ("X-Foo", "bar"), ("X-Bar", "1"), ("X-Bar", "2")])
    assert headers.getlist("x-bar") == ["1", "2"]
    assert headers.get("x-Bar") == "1"
    assert headers.get("Content-Type") == "text/plain"

    assert headers.setdefault("X-Foo", "nope") == "bar"
    assert headers.setdefault("X-Bar", "nope") == "1"
    assert headers.setdefault("X-Baz", "quux") == "quux"
    assert headers.setdefault("X-Baz", "nope") == "quux"
    headers.pop("X-Baz")

    # type conversion
    assert headers.get("x-bar", type=int) == 1
    assert headers.getlist("x-bar", type=int) == [1, 2]

    # list like operations
    assert headers[0] == ("Content-Type", "text/plain")
    assert headers[:1] == Headers([("Content-Type", "text/plain")])
    del headers[:2]
    del headers[-1]
    assert headers == Headers([("X-Bar", "1")])

    # copying
    a = Headers([("foo", "bar")])
    b = a.copy()
    a.add("foo", "baz")
    assert a.getlist("foo") == ["bar", "baz"]
    assert b.getlist("foo") == ["bar"]

    headers = Headers([("a", 1)])
    assert headers.pop("a") == 1
    assert headers.pop("b", 2) == 2
    assert_raises(KeyError, headers.pop, "c")

    # set replaces and accepts same arguments as add
    a = Headers()
    a.set("Content-Disposition", "useless")
    a.set("Content-Disposition", "attachment", filename="foo")
    assert a["Content-Disposition"] == "attachment; filename=foo"
Пример #9
0
def test_headers():
    # simple header tests
    headers = Headers()
    headers.add('Content-Type', 'text/plain')
    headers.add('X-Foo', 'bar')
    assert 'x-Foo' in headers
    assert 'Content-type' in headers

    headers['Content-Type'] = 'foo/bar'
    assert headers['Content-Type'] == 'foo/bar'
    assert len(headers.getlist('Content-Type')) == 1

    # list conversion
    assert headers.to_list() == [
        ('Content-Type', 'foo/bar'),
        ('X-Foo', 'bar')
    ]
    assert str(headers) == (
        "Content-Type: foo/bar\r\n"
        "X-Foo: bar\r\n"
        "\r\n")
    assert str(Headers()) == "\r\n"

    # extended add
    headers.add('Content-Disposition', 'attachment', filename='foo')
    assert headers['Content-Disposition'] == 'attachment; filename=foo'

    headers.add('x', 'y', z='"')
    assert headers['x'] == r'y; z="\""'

    # defaults
    headers = Headers([
        ('Content-Type', 'text/plain'),
        ('X-Foo',        'bar'),
        ('X-Bar',        '1'),
        ('X-Bar',        '2')
    ])
    assert headers.getlist('x-bar') == ['1', '2']
    assert headers.get('x-Bar') == '1'
    assert headers.get('Content-Type') == 'text/plain'

    assert headers.setdefault('X-Foo', 'nope') == 'bar'
    assert headers.setdefault('X-Bar', 'nope') == '1'
    assert headers.setdefault('X-Baz', 'quux') == 'quux'
    assert headers.setdefault('X-Baz', 'nope') == 'quux'
    headers.pop('X-Baz')

    # type conversion
    assert headers.get('x-bar', type=int) == 1
    assert headers.getlist('x-bar', type=int) == [1, 2]

    # list like operations
    assert headers[0] == ('Content-Type', 'text/plain')
    assert headers[:1] == Headers([('Content-Type', 'text/plain')])
    del headers[:2]
    del headers[-1]
    assert headers == Headers([('X-Bar', '1')])

    # copying
    a = Headers([('foo', 'bar')])
    b = a.copy()
    a.add('foo', 'baz')
    assert a.getlist('foo') == ['bar', 'baz']
    assert b.getlist('foo') == ['bar']

    headers = Headers([('a', 1)])
    assert headers.pop('a') == 1
    assert headers.pop('b', 2) == 2
    assert_raises(KeyError, headers.pop, 'c')

    # set replaces and accepts same arguments as add
    a = Headers()
    a.set('Content-Disposition', 'useless')
    a.set('Content-Disposition', 'attachment', filename='foo')
    assert a['Content-Disposition'] == 'attachment; filename=foo'
Пример #10
0
class BaseResponse(object):
    charset = 'utf-8'
    default_status = 200
    default_mimetype = 'text/plain'
    implicit_sequence_conversion = True

    def __init__(self, response = None, status = None, headers = None, mimetype = None, content_type = None, direct_passthrough = False):
        if isinstance(headers, Headers):
            self.headers = headers
        elif not headers:
            self.headers = Headers()
        else:
            self.headers = Headers(headers)
        if content_type is None:
            if mimetype is None and 'content-type' not in self.headers:
                mimetype = self.default_mimetype
            if mimetype is not None:
                mimetype = get_content_type(mimetype, self.charset)
            content_type = mimetype
        if content_type is not None:
            self.headers['Content-Type'] = content_type
        if status is None:
            status = self.default_status
        if isinstance(status, (int, long)):
            self.status_code = status
        else:
            self.status = status
        self.direct_passthrough = direct_passthrough
        self._on_close = []
        if response is None:
            self.response = []
        elif isinstance(response, basestring):
            self.data = response
        else:
            self.response = response

    def call_on_close(self, func):
        self._on_close.append(func)

    def __repr__(self):
        if self.is_sequence:
            body_info = '%d bytes' % sum(map(len, self.iter_encoded()))
        else:
            body_info = self.is_streamed and 'streamed' or 'likely-streamed'
        return '<%s %s [%s]>' % (self.__class__.__name__, body_info, self.status)

    @classmethod
    def force_type(cls, response, environ = None):
        if not isinstance(response, BaseResponse):
            if environ is None:
                raise TypeError('cannot convert WSGI application into response objects without an environ')
            response = BaseResponse(*_run_wsgi_app(response, environ))
        response.__class__ = cls
        return response

    @classmethod
    def from_app(cls, app, environ, buffered = False):
        return cls(*_run_wsgi_app(app, environ, buffered))

    def _get_status_code(self):
        try:
            return int(self.status.split(None, 1)[0])
        except ValueError:
            return 0

    def _set_status_code(self, code):
        try:
            self.status = '%d %s' % (code, HTTP_STATUS_CODES[code].upper())
        except KeyError:
            self.status = '%d UNKNOWN' % code

    status_code = property(_get_status_code, _set_status_code, 'The HTTP Status code as number')
    del _get_status_code
    del _set_status_code

    def _get_data(self):
        self._ensure_sequence()
        return ''.join(self.iter_encoded())

    def _set_data(self, value):
        if isinstance(value, unicode):
            value = value.encode(self.charset)
        self.response = [value]

    data = property(_get_data, _set_data, doc=_get_data.__doc__)
    del _get_data
    del _set_data

    def _ensure_sequence(self, mutable = False):
        if self.is_sequence:
            if mutable and not isinstance(self.response, list):
                self.response = list(self.response)
            return
        if not self.implicit_sequence_conversion:
            raise RuntimeError('The response object required the iterable to be a sequence, but the implicit conversion was disabled.  Call make_sequence() yourself.')
        self.make_sequence()

    def make_sequence(self):
        if not self.is_sequence:
            close = getattr(self.response, 'close', None)
            self.response = list(self.iter_encoded())
            if close is not None:
                self.call_on_close(close)

    def iter_encoded(self, charset = None):
        if __debug__ and charset is not None:
            from warnings import warn
            warn(DeprecationWarning('charset was deprecated and is ignored.'), stacklevel=2)
        charset = self.charset
        for item in self.response:
            if isinstance(item, unicode):
                yield item.encode(charset)
            else:
                yield str(item)

    def set_cookie(self, key, value = '', max_age = None, expires = None, path = '/', domain = None, secure = None, httponly = False):
        self.headers.add('Set-Cookie', dump_cookie(key, value, max_age, expires, path, domain, secure, httponly, self.charset))

    def delete_cookie(self, key, path = '/', domain = None):
        self.set_cookie(key, expires=0, max_age=0, path=path, domain=domain)

    @property
    def header_list(self):
        return self.headers.to_list(self.charset)

    @property
    def is_streamed(self):
        try:
            len(self.response)
        except TypeError:
            return True

        return False

    @property
    def is_sequence(self):
        return isinstance(self.response, (tuple, list))

    def close(self):
        if hasattr(self.response, 'close'):
            self.response.close()
        for func in self._on_close:
            func()

    def freeze(self):
        self.response = list(self.iter_encoded())
        self.headers['Content-Length'] = str(sum(map(len, self.response)))

    def fix_headers(self, environ):
        self.headers[:] = self.get_wsgi_headers(environ)

    def get_wsgi_headers(self, environ):
        headers = Headers(self.headers)
        location = headers.get('location')
        if location is not None:
            if isinstance(location, unicode):
                location = iri_to_uri(location)
            headers['Location'] = urlparse.urljoin(get_current_url(environ, root_only=True), location)
        content_location = headers.get('content-location')
        if content_location is not None and isinstance(content_location, unicode):
            headers['Content-Location'] = iri_to_uri(content_location)
        if 100 <= self.status_code < 200 or self.status_code == 204:
            headers['Content-Length'] = '0'
        elif self.status_code == 304:
            remove_entity_headers(headers)
        if self.is_sequence and 'content-length' not in self.headers:
            try:
                content_length = sum((len(str(x)) for x in self.response))
            except UnicodeError:
                pass
            else:
                headers['Content-Length'] = str(content_length)

        return headers

    def get_app_iter(self, environ):
        if environ['REQUEST_METHOD'] == 'HEAD' or 100 <= self.status_code < 200 or self.status_code in (204, 304):
            return ()
        if self.direct_passthrough:
            return self.response
        return ClosingIterator(self.iter_encoded(), self.close)

    def get_wsgi_response(self, environ):
        if self.fix_headers.func_code is not BaseResponse.fix_headers.func_code:
            self.fix_headers(environ)
            headers = self.headers
        else:
            headers = self.get_wsgi_headers(environ)
        app_iter = self.get_app_iter(environ)
        return (app_iter, self.status, headers.to_list(self.charset))

    def __call__(self, environ, start_response):
        app_iter, status, headers = self.get_wsgi_response(environ)
        start_response(status, headers)
        return app_iter
Пример #11
0
def test_headers():
    # simple header tests
    headers = Headers()
    headers.add('Content-Type', 'text/plain')
    headers.add('X-Foo', 'bar')
    assert 'x-Foo' in headers
    assert 'Content-type' in headers

    headers['Content-Type'] = 'foo/bar'
    assert headers['Content-Type'] == 'foo/bar'
    assert len(headers.getlist('Content-Type')) == 1

    # list conversion
    assert headers.to_list() == [('Content-Type', 'foo/bar'), ('X-Foo', 'bar')]
    assert str(headers) == ("Content-Type: foo/bar\r\n"
                            "X-Foo: bar\r\n"
                            "\r\n")
    assert str(Headers()) == "\r\n"

    # extended add
    headers.add('Content-Disposition', 'attachment', filename='foo')
    assert headers['Content-Disposition'] == 'attachment; filename=foo'

    headers.add('x', 'y', z='"')
    assert headers['x'] == r'y; z="\""'

    # defaults
    headers = Headers([('Content-Type', 'text/plain'), ('X-Foo', 'bar'),
                       ('X-Bar', '1'), ('X-Bar', '2')])
    assert headers.getlist('x-bar') == ['1', '2']
    assert headers.get('x-Bar') == '1'
    assert headers.get('Content-Type') == 'text/plain'

    assert headers.setdefault('X-Foo', 'nope') == 'bar'
    assert headers.setdefault('X-Bar', 'nope') == '1'
    assert headers.setdefault('X-Baz', 'quux') == 'quux'
    assert headers.setdefault('X-Baz', 'nope') == 'quux'
    headers.pop('X-Baz')

    # type conversion
    assert headers.get('x-bar', type=int) == 1
    assert headers.getlist('x-bar', type=int) == [1, 2]

    # list like operations
    assert headers[0] == ('Content-Type', 'text/plain')
    assert headers[:1] == Headers([('Content-Type', 'text/plain')])
    del headers[:2]
    del headers[-1]
    assert headers == Headers([('X-Bar', '1')])

    # copying
    a = Headers([('foo', 'bar')])
    b = a.copy()
    a.add('foo', 'baz')
    assert a.getlist('foo') == ['bar', 'baz']
    assert b.getlist('foo') == ['bar']

    headers = Headers([('a', 1)])
    assert headers.pop('a') == 1
    assert headers.pop('b', 2) == 2
    assert_raises(KeyError, headers.pop, 'c')

    # set replaces and accepts same arguments as add
    a = Headers()
    a.set('Content-Disposition', 'useless')
    a.set('Content-Disposition', 'attachment', filename='foo')
    assert a['Content-Disposition'] == 'attachment; filename=foo'