예제 #1
0
 def test_etags(self):
     assert http.quote_etag('foo') == '"foo"'
     assert http.quote_etag('foo', True) == 'W/"foo"'
     assert http.unquote_etag('"foo"') == ('foo', False)
     assert http.unquote_etag('W/"foo"') == ('foo', True)
     es = http.parse_etags('"foo", "bar", W/"baz", blar')
     assert sorted(es) == ['bar', 'blar', 'foo']
     assert 'foo' in es
     assert 'baz' not in es
     assert es.contains_weak('baz')
     assert 'blar' in es
     assert es.contains_raw('W/"baz"')
     assert es.contains_raw('"foo"')
     assert sorted(es.to_header().split(', ')) == ['"bar"', '"blar"', '"foo"', 'W/"baz"']
예제 #2
0
 def test_etags(self):
     assert http.quote_etag('foo') == '"foo"'
     assert http.quote_etag('foo', True) == 'w/"foo"'
     assert http.unquote_etag('"foo"') == ('foo', False)
     assert http.unquote_etag('w/"foo"') == ('foo', True)
     es = http.parse_etags('"foo", "bar", w/"baz", blar')
     assert sorted(es) == ['bar', 'blar', 'foo']
     assert 'foo' in es
     assert 'baz' not in es
     assert es.contains_weak('baz')
     assert 'blar' in es
     assert es.contains_raw('w/"baz"')
     assert es.contains_raw('"foo"')
     assert sorted(es.to_header().split(', ')) == ['"bar"', '"blar"', '"foo"', 'w/"baz"']
예제 #3
0
 def test_etags(self):
     assert http.quote_etag("foo") == '"foo"'
     assert http.quote_etag("foo", True) == 'w/"foo"'
     assert http.unquote_etag('"foo"') == ("foo", False)
     assert http.unquote_etag('w/"foo"') == ("foo", True)
     es = http.parse_etags('"foo", "bar", w/"baz", blar')
     assert sorted(es) == ["bar", "blar", "foo"]
     assert "foo" in es
     assert "baz" not in es
     assert es.contains_weak("baz")
     assert "blar" in es
     assert es.contains_raw('w/"baz"')
     assert es.contains_raw('"foo"')
     assert sorted(es.to_header().split(", ")) == ['"bar"', '"blar"', '"foo"', 'w/"baz"']
예제 #4
0
    def test_exception_header_forwarded(self):
        """Test that HTTPException's headers are extended properly"""
        app = Flask(__name__)
        app.config['DEBUG'] = True
        api = flask_restful.Api(app)

        class NotModified(HTTPException):
            code = 304

            def __init__(self, etag, *args, **kwargs):
                super(NotModified, self).__init__(*args, **kwargs)
                self.etag = quote_etag(etag)

            def get_headers(self, *args, **kwargs):
                """Get a list of headers."""
                return [('ETag', self.etag)]

        class Foo1(flask_restful.Resource):
            def get(self):
                flask_abort(304, etag='myETag')

        api.add_resource(Foo1, '/foo')
        _aborter.mapping.update({304: NotModified})

        with app.test_client() as client:
            foo = client.get('/foo')
            self.assertEquals(foo.get_etag(),
                              unquote_etag(quote_etag('myETag')))
예제 #5
0
def feed(config, tz, template, page=None):
    include_day = config.include_day
    start = datetime.fromtimestamp(config.start_timestamp, tz)
    now = datetime.now(start.tzinfo)

    total_posts = count_dates(start, now, include_day)
    per_page = 50
    last_page = total_posts // per_page - 1

    headers = {
        'Date': http_date(now),
    }

    links = []
    if page is None:
        etag = quote_etag(str(total_posts))
        next_date, dates = recent_dates(start, now, include_day, per_page)
        max_age = int((next_date - now).total_seconds())
        if last_page >= 0:
            links.append(('prev-archive', last_page))
    elif page <= last_page:
        etag = '"0"'
        dates = archived_dates(start, include_day, page * per_page, per_page)
        max_age = 7 * 24 * 60 * 60
        links.append(('current', None))
        if page < last_page:
            links.append(('next-archive', page + 1))
        if page > 0:
            links.append(('prev-archive', page - 1))
    else:
        abort(404)

    headers['Cache-Control'] = "public, max-age={}, immutable".format(max_age)
    headers['Expires'] = http_date(now + timedelta(seconds=max_age))
    headers['ETag'] = etag
    if not is_resource_modified(request.environ, etag):
        return Response(status=304, headers=headers)

    day_names = [
        calendar.day_name[day] for day, included in enumerate(include_day)
        if included
    ]
    if len(day_names) > 1:
        days_description = '{} and {}'.format(
            ', '.join(day_names[:-1]),
            day_names[-1],
        )
    else:
        days_description = day_names[0]

    feed = render_template(
        "feed.xml",
        template=template,
        days_description=days_description,
        start=start,
        config=config,
        links=links,
        dates=dates,
    )
    return Response(feed, mimetype='application/rss+xml', headers=headers)
예제 #6
0
파일: rest.py 프로젝트: DerRechner/Hanabi
    def response(self, request, data, etag=None, cache_policy=None):
        """Renders `data` to a JSON response.

        An ETag may be specified. When it is not specified one will be generated
        based on the data.

        The caching policy can be optionally configured. By default it takes the
        policy from the controller object: `cache_policy`.
        """
        if etag is None and data is not None:
            etag = self.etag(data)
        # FIXME: Check content-type headers
        if data is None:
            if etag is None:
                raise TypeError('response requires an etag when '
                                'the response body is None')
            resp = Response(status=304, content_type='application/json')
        else:
            # Avoid sending the resource when an ETag matches
            request_etags = parse_etags(
                request.environ.get('HTTP_IF_NONE_MATCH'))
            if request_etags.contains(etag):
                 resp = Response(status=304, content_type='application/json')
            # Render the given data to a response object
            else:
                resp = Response(self.data_encoder.encode(data), content_type='application/json')
        resp.headers['ETag'] = quote_etag(etag)
        if cache_policy is None:
            cache_policy = self.cache_policy
        return cache_policy(resp)
예제 #7
0
    def build_etag(self, response, include_etag=True, **kwargs):
        """
        Add an etag to the response body.

        Uses spooky where possible because it is empirically fast and well-regarded.

        See: http://blog.reverberate.org/2012/01/state-of-hash-functions-2012.html

        """
        if not include_etag:
            return

        if not spooky:
            # use built-in md5
            response.add_etag()
            return

        # use spooky
        response.headers["ETag"] = quote_etag(
            hexlify(
                spooky.hash128(
                    response.get_data(),
                ).to_bytes(16, "little"),
            ).decode("utf-8"),
        )
예제 #8
0
    def test_exception_header_forwarded(self):
        '''Ensure that HTTPException's headers are extended properly'''
        self.app.config['DEBUG'] = True
        api = restplus.Api(self.app)

        class NotModified(HTTPException):
            code = 304

            def __init__(self, etag, *args, **kwargs):
                super(NotModified, self).__init__(*args, **kwargs)
                self.etag = quote_etag(etag)

            def get_headers(self, *args, **kwargs):
                return [('ETag', self.etag)]

        @api.route('/foo')
        class Foo1(restplus.Resource):
            def get(self):
                abort(304, etag='myETag')

        abort.mapping.update({304: NotModified})

        with self.app.test_client() as client:
            foo = client.get('/foo')
            self.assertEquals(foo.get_etag(),
                              unquote_etag(quote_etag('myETag')))
 def make_headers(self, content=None):
     """Add `ETag` header to response."""
     headers = super().make_headers(content=content)
     etag = content.get("revision_id") if content else None
     if etag:
         headers["ETag"] = quote_etag(str(etag), False)
     return headers
예제 #10
0
    def test_exception_header_forwarded(self):
        """Test that HTTPException's headers are extended properly"""
        app = Flask(__name__)
        app.config['DEBUG'] = True
        api = flask_restful.Api(app)

        class NotModified(HTTPException):
            code = 304

            def __init__(self, etag, *args, **kwargs):
                super(NotModified, self).__init__(*args, **kwargs)
                self.etag = quote_etag(etag)

            def get_headers(self, *args, **kwargs):
                """Get a list of headers."""
                return [('ETag', self.etag)]

        class Foo1(flask_restful.Resource):
            def get(self):
                flask_abort(304, etag='myETag')

        api.add_resource(Foo1, '/foo')
        flask_abort.mapping.update({304: NotModified})

        with app.test_client() as client:
            foo = client.get('/foo')
            self.assertEquals(foo.get_etag(),
                              unquote_etag(quote_etag('myETag')))
예제 #11
0
    def build_etag(self, response, include_etag=True, **kwargs):
        """
        Add an etag to the response body.

        Uses spooky where possible because it is empirically fast and well-regarded.

        See: http://blog.reverberate.org/2012/01/state-of-hash-functions-2012.html

        """
        if not include_etag:
            return

        if not spooky:
            # use built-in md5
            response.add_etag()
            return

        # use spooky
        response.headers["ETag"] = quote_etag(
            hexlify(
                spooky.hash128(
                    response.get_data(),
                ).to_bytes(16, "little"),
            ).decode("utf-8"),
        )
    def test_exception_header_forwarded(self):
        '''Ensure that HTTPException's headers are extended properly'''
        self.app.config['DEBUG'] = True
        api = restplus.Api(self.app)

        class NotModified(HTTPException):
            code = 304

            def __init__(self, etag, *args, **kwargs):
                super(NotModified, self).__init__(*args, **kwargs)
                self.etag = quote_etag(etag)

            def get_headers(self, *args, **kwargs):
                return [('ETag', self.etag)]

        @api.route('/foo')
        class Foo1(restplus.Resource):
            def get(self):
                abort(304, etag='myETag')

        abort.mapping.update({304: NotModified})

        with self.app.test_client() as client:
            foo = client.get('/foo')
            self.assertEquals(foo.get_etag(),
                              unquote_etag(quote_etag('myETag')))
예제 #13
0
 def test_etags(self):
     assert http.quote_etag("foo") == '"foo"'
     assert http.quote_etag("foo", True) == 'W/"foo"'
     assert http.unquote_etag('"foo"') == ("foo", False)
     assert http.unquote_etag('W/"foo"') == ("foo", True)
     es = http.parse_etags('"foo", "bar", W/"baz", blar')
     assert sorted(es) == ["bar", "blar", "foo"]
     assert "foo" in es
     assert "baz" not in es
     assert es.contains_weak("baz")
     assert "blar" in es
     assert es.contains_raw('W/"baz"')
     assert es.contains_raw('"foo"')
     assert sorted(es.to_header().split(", ")) == [
         '"bar"',
         '"blar"',
         '"foo"',
         'W/"baz"',
     ]
예제 #14
0
 def check_normal_response(res, method):
     if method != client.head:
         parsed = json.loads(res.get_data(as_text=True))
         expected = {'id': 1, 'method': parsed['method']}
         assert parsed == expected
         # check that the right method was called
         assert method_names[parsed['method']] == method
         assert res.content_type == 'application/json'
     assert res.status_code == 200
     # check that the ETag is correct
     assert unquote_etag(res.headers['ETag']) == \
         unquote_etag(quote_etag('abc'))
예제 #15
0
 def check_normal_response(res, method):
     if method != client.head:
         parsed = json.loads(res.get_data(as_text=True))
         expected = {'id': 1, 'method': parsed['method']}
         assert parsed == expected
         # check that the right method was called
         assert method_names[parsed['method']] == method
         assert res.content_type == 'application/json'
     assert res.status_code == 200
     # check that the ETag is correct
     assert unquote_etag(res.headers['ETag']) == \
         unquote_etag(quote_etag('abc'))
예제 #16
0
def etag_headers(obj_or_list, code, many=False):
    """Headers for a single resource item."""
    headers = {
        'content-type': resource_requestctx.accept_mimetype,
    }
    if many:
        return headers

    etag = obj_or_list.get("revision_id")
    if etag:
        headers["ETag"] = quote_etag(str(etag), False)
    return headers
예제 #17
0
def serve_file(path):
    headers = {}

    st = os.stat(path)

    etag = 'clay-{0}-{1}-{2}'.format(
        os.path.getmtime(path), os.path.getsize(path),
        adler32(path.encode('utf-8')) & 0xffffffff)
    headers['ETag'] = quote_etag(etag)

    # Set the Last-Modified response header, so that
    # modified-since validation code can work.
    headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)

    _, ext = os.path.splitext(path)
    content_type = mimetypes.types_map.get(ext, None)
    headers['Content-Type'] = content_type or 'text/plain'

    fileobj = open(path, 'rb')
    return serve_fileobj(fileobj, headers, st.st_size)
예제 #18
0
def serve_file(path):
    headers = {}

    st = os.stat(path)

    etag = 'clay-{0}-{1}-{2}'.format(
        os.path.getmtime(path),
        os.path.getsize(path),
        adler32(path.encode('utf-8')) & 0xffffffff
    )
    headers['ETag'] = quote_etag(etag)

    # Set the Last-Modified response header, so that
    # modified-since validation code can work.
    headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)

    _, ext = os.path.splitext(path)
    content_type = mimetypes.types_map.get(ext, None)
    headers['Content-Type'] = content_type or 'text/plain'

    fileobj = open(path, 'rb')
    return serve_fileobj(fileobj, headers, st.st_size)
예제 #19
0
    def test_exception_header_forwarded(self, app, client):
        '''Ensure that HTTPException's headers are extended properly'''
        api = restplus.Api(app)

        class NotModified(HTTPException):
            code = 304

            def __init__(self, etag, *args, **kwargs):
                super(NotModified, self).__init__(*args, **kwargs)
                self.etag = quote_etag(etag)

            def get_headers(self, *args, **kwargs):
                return [('ETag', self.etag)]

        custom_abort = Aborter(mapping={304: NotModified})

        @api.route('/foo')
        class Foo1(restplus.Resource):
            def get(self):
                custom_abort(304, etag='myETag')

        foo = client.get('/foo')
        assert foo.get_etag() == unquote_etag(quote_etag('myETag'))
예제 #20
0
    def test_exception_header_forwarded(self, app, client):
        '''Ensure that HTTPException's headers are extended properly'''
        api = restplus.Api(app)

        class NotModified(HTTPException):
            code = 304

            def __init__(self, etag, *args, **kwargs):
                super(NotModified, self).__init__(*args, **kwargs)
                self.etag = quote_etag(etag)

            def get_headers(self, *args, **kwargs):
                return [('ETag', self.etag)]

        custom_abort = Aborter(mapping={304: NotModified})

        @api.route('/foo')
        class Foo1(restplus.Resource):
            def get(self):
                custom_abort(304, etag='myETag')

        foo = client.get('/foo')
        assert foo.get_etag() == unquote_etag(quote_etag('myETag'))
예제 #21
0
 def set_etag(self, etag, weak = False):
     self.headers['ETag'] = quote_etag(etag, weak)
예제 #22
0
 def __init__(self, etag, *args, **kwargs):
     super(NotModified, self).__init__(*args, **kwargs)
     self.etag = quote_etag(etag)
예제 #23
0
 def check_304_response(res):
     assert res.status_code == 304
     # check that the ETag is correct
     assert unquote_etag(res.headers['ETag']) == \
         unquote_etag(quote_etag('abc'))
예제 #24
0
 def __init__(self, etag, *args, **kwargs):
     super(NotModified, self).__init__(*args, **kwargs)
     self.etag = quote_etag(etag)
예제 #25
0
 def set_etag(self, etag: str, weak: bool = False) -> None:
     """Set the etag, and override the old one if there was one."""
     self.headers["ETag"] = quote_etag(etag, weak)
예제 #26
0
 def check_304_response(res):
     assert res.status_code == 304
     # check that the ETag is correct
     assert unquote_etag(res.headers['ETag']) == \
         unquote_etag(quote_etag('abc'))
예제 #27
0
 def set_etag(self, etag, weak=False):
     """Set the etag, and override the old one if there was one."""
     self.headers['ETag'] = quote_etag(etag, weak)
예제 #28
0
 def set_etag(self, etag, weak = False):
     self.headers['ETag'] = quote_etag(etag, weak)