예제 #1
0
def get_frozen_file_getter(file_path, cache_max_age=12000):
    mime = get_mime_type(file_path)
    size = os.path.getsize(file_path)
    current_etag = str(os.path.getmtime(file_path)).encode()
    headers = [
        Header(b'Last-Modified',
               unix_timestamp_to_datetime(os.path.getmtime(file_path))),
        Header(b'ETag', current_etag),
        Header(b'Cache-Control', b'max-age=' + str(cache_max_age).encode())
    ]

    head_headers = headers + [
        Header(b'Content-Type', mime),
        Header(b'Content-Length',
               str(size).encode())
    ]

    data = get_file_data(file_path, size, size_limit=1.049e+7)

    async def frozen_file_getter(request):
        previous_etag = request.if_none_match

        if previous_etag and previous_etag == current_etag:
            return Response(304, headers, None)

        if request.method == b'HEAD':
            return Response(200, head_headers, None)

        return Response(200, Headers(headers), Content(mime, data))

    return frozen_file_getter
예제 #2
0
def get_response_for_file(request, resource_path, cache_time):
    # TODO: support for accept-range and bytes ranges
    file_size = os.path.getsize(resource_path)
    modified_time = os.path.getmtime(resource_path)
    current_etag = str(modified_time).encode()
    previous_etag = request.if_none_match

    headers = [
        Header(b'Last-Modified', unix_timestamp_to_datetime(modified_time)),
        Header(b'ETag', current_etag)
    ]

    if cache_time > 0:
        headers.append(
            Header(b'Cache-Control', b'max-age=' + str(cache_time).encode()))

    if previous_etag and current_etag == previous_etag:
        return Response(304, headers, None)

    if request.method == b'HEAD':
        headers.append(Header(b'Content-Type', get_mime_type(resource_path)))
        headers.append(Header(b'Content-Length', str(file_size).encode()))
        return Response(200, headers, None)

    return Response(
        200, Headers(headers),
        Content(get_mime_type(resource_path),
                get_file_data(resource_path, file_size)))
예제 #3
0
def test_http_header_check_equality(name_a, value_a, name_b, value_b,
                                    expected_result):
    a = Header(name_a, value_a)
    b = Header(name_b, value_b)

    assert (a == b) == expected_result
    assert (a != b) != expected_result
    assert (b != a) != expected_result
예제 #4
0
def test_http_header_collection_get_single_raises_if_more_items_are_present():
    headers = Headers()

    values = [
        Header(b'Cookie', b'Hello=World;'),
        Header(b'Cookie', b'Foo=foo;'),
        Header(b'Cookie', b'Ufo=ufo;'),
    ]

    headers.add_many(values)
    # keeps only the last one, if a single header is expected
    headers.get_single(b'cookie').value == b'Ufo=ufo;'
예제 #5
0
def test_iadd_http_header_collection_concatenation_with_duplicate_header():
    headers = Headers([
        Header(b'Hello', b'World'),
        Header(b'Svil', b'Power'),
    ])

    headers += Header(b'Svil', b'Kitty')
    example = headers[b'Svil']

    assert len(example) == 2
    assert any(x.value == b'Power' for x in example)
    assert any(x.value == b'Kitty' for x in example)
예제 #6
0
def test_iadd_http_header_collection_concatenation_with_header():
    headers = Headers([
        Header(b'Hello', b'World'),
        Header(b'Svil', b'Power'),
    ])

    headers += Header(b'Foo', b'foo')

    example = headers[b'Foo']
    assert len(example) == 1

    header = example[0]
    assert header.name == b'Foo'
    assert header.value == b'foo'
예제 #7
0
def test_iadd_http_header_collection_concatenation_with_list_of_headers():
    headers = Headers([
        Header(b'Hello', b'World'),
        Header(b'Svil', b'Power'),
    ])

    headers += [Header(b'foo', b'foo'), Header(b'ufo', b'ufo')]

    for name in {b'foo', b'ufo'}:
        example = headers[name]
        assert len(example) == 1

        header = example[0]
        assert header.name.lower() == name
        assert header.value == name
예제 #8
0
def test_cookie_parsing_multiple_cookie_headers():
    request = Request(
        b'POST', b'/',
        Headers([
            Header(b'Cookie',
                   b'ai=something; hello=world; foo=Hello%20World%3B;'),
            Header(b'Cookie', b'jib=jab; ai=else;'),
        ]), None)

    assert request.cookies == {
        b'ai': b'else',
        b'hello': b'world',
        b'foo': b'Hello World;',
        b'jib': b'jab'
    }
예제 #9
0
async def test_application_get_handler():
    app = FakeApplication()

    @app.router.get(b'/')
    async def home(request):
        pass

    @app.router.get(b'/foo')
    async def foo(request):
        pass

    handler = get_new_connection_handler(app)

    message = b'\r\n'.join([
        b'GET / HTTP/1.1',
        b'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0',
        b'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        b'Accept-Language: en-US,en;q=0.5',
        b'Connection: keep-alive',
        b'Upgrade-Insecure-Requests: 1',
        b'Host: foo\r\n\r\n'
    ])

    handler.data_received(message)

    await app.response_done.wait()
    request = app.request  # type: Request

    assert request is not None

    connection = request.headers[b'connection']
    assert connection == [Header(b'Connection', b'keep-alive')]

    text = await request.text()
    assert text == ''
예제 #10
0
async def test_cookies_jar_single_cookie():
    fake_pools = FakePools([
        Response(
            200,
            Headers([
                Header(b'Set-Cookie',
                       write_response_cookie(Cookie(b'X-Foo', b'Foo')))
            ]), TextContent('Hello, World!')),
        Response(200, Headers(), TextContent('Hello!'))
    ])
    check_cookie = False

    async def middleware_for_assertions(request, next_handler):
        if check_cookie:
            cookie = request.cookies.get(b'X-Foo')
            assert cookie is not None, 'X-Foo cookie must be configured for following requests'

        return await next_handler(request)

    async with ClientSession(url=b'https://bezkitu.org',
                             pools=fake_pools,
                             middlewares=[middleware_for_assertions
                                          ]) as client:
        await client.get(
            b'/'
        )  # the first request doesn't have any cookie because the response will set;
        check_cookie = True
        await client.get(b'/')
예제 #11
0
async def test_request_headers():
    fake_pools = FakePools(
        [Response(200, Headers(), TextContent('Hello, World!'))])

    async def middleware_for_assertions(request, next_handler):
        assert b'Hello' in request.headers
        assert request.headers.get_single(b'Hello').value == b'World'

        return await next_handler(request)

    async with ClientSession(url=b'http://localhost:8080',
                             pools=fake_pools,
                             middlewares=[middleware_for_assertions
                                          ]) as client:
        await client.get(b'/', headers=[Header(b'Hello', b'World')])
        await client.post(b'/', headers=[Header(b'Hello', b'World')])
        await client.put(b'/', headers=[Header(b'Hello', b'World')])
        await client.delete(b'/', headers=[Header(b'Hello', b'World')])
예제 #12
0
def test_http_header_collection_add_multiple_times_items():
    headers = Headers()

    values = [
        Header(b'Cookie', b'Hello=World;'),
        Header(b'Cookie', b'Foo=foo;'),
        Header(b'Cookie', b'Ufo=ufo;'),
    ]

    headers.add_many(values)

    cookie_headers = headers[b'cookie']

    assert cookie_headers
    assert len(cookie_headers) == 3
    assert any(x.value == b'Hello=World;' for x in cookie_headers)
    assert any(x.value == b'Foo=foo;' for x in cookie_headers)
    assert any(x.value == b'Ufo=ufo;' for x in cookie_headers)
예제 #13
0
def test_http_header_collection_instantiating_with_dict_values(values):
    headers = Headers(list(
        Header(key, value) for key, value in values.items()))

    for key, value in values.items():
        header = headers[key]
        assert len(header) == 1
        assert header[0].name == key
        assert header[0].value == value
예제 #14
0
async def test_remove_cookie_with_expiration():
    expire_cookie = Cookie(b'X-Foo', b'Foo')
    expire_cookie.expiration = datetime.utcnow() + timedelta(days=-2)
    fake_pools = FakePools([
        Response(
            200,
            Headers([
                Header(b'Set-Cookie',
                       write_response_cookie(Cookie(b'X-Foo', b'Foo')))
            ]), TextContent('Hello, World!')),
        Response(200, Headers(), TextContent('Hello!')),
        Response(
            200,
            Headers(
                [Header(b'Set-Cookie', write_response_cookie(expire_cookie))]),
            TextContent('Hello, World!')),
        Response(200, Headers(), TextContent('Hello!'))
    ])
    expect_cookie = False

    async def middleware_for_assertions(request, next_handler):
        cookie = request.cookies.get(b'X-Foo')
        if expect_cookie:
            assert cookie is not None, 'X-Foo cookie must be configured'
        else:
            assert cookie is None

        return await next_handler(request)

    async with ClientSession(url=b'https://bezkitu.org',
                             pools=fake_pools,
                             middlewares=[middleware_for_assertions
                                          ]) as client:
        await client.get(b'/')  # <-- cookie set here
        expect_cookie = True
        await client.get(b'/')  # <-- expect cookie in request
        expect_cookie = True
        await client.get(
            b'/')  # <-- expect cookie in request; it gets removed here
        expect_cookie = False
        await client.get(
            b'/'
        )  # <-- expect missing cookie; was deleted by previous response
예제 #15
0
def test_http_header_collection_concatenation_with_other_collection():
    headers = Headers([
        Header(b'Hello', b'World'),
        Header(b'Svil', b'Power'),
    ])

    with_addition = headers + Headers([
        Header(b'Foo', b'foo'), Header(b'Ufo', b'ufo')
    ])

    for name in {b'foo', b'ufo'}:
        assert headers[name] == []

        example = with_addition[name]
        assert len(example) == 1

        header = example[0]
        assert header.name.lower() == name
        assert header.value == name
예제 #16
0
async def test_if_read_json_fails_content_type_header_is_checked_non_json_gives_invalid_operation(
):
    request = Request(b'POST', b'/',
                      Headers([Header(b'Content-Type', b'text/html')]), None)

    request.extend_body(b'{"hello":')  # broken json
    request.complete.set()

    with pytest.raises(InvalidOperation):
        await request.json()
예제 #17
0
async def test_if_read_json_fails_content_type_header_is_checked_json_gives_bad_request_format(
):
    request = Request(b'POST', b'/',
                      Headers([Header(b'Content-Type', b'application/json')]),
                      None)

    request.extend_body(b'{"hello":')  # broken json
    request.complete.set()

    with pytest.raises(BadRequestFormat):
        await request.json()
예제 #18
0
async def test_from_header_binding(expected_type, header_value,
                                   expected_value):

    request = Request(b'GET', b'/', Headers([Header(b'X-Foo', header_value)]),
                      None)

    parameter = FromHeader(expected_type, 'X-Foo')

    value = await parameter.get_value(request)

    assert isinstance(value, expected_type)
    assert value == expected_value
예제 #19
0
    async def create_cat(request):
        nonlocal called_times
        called_times += 1
        assert request is not None

        content = await request.read()
        assert b'{"name":"Celine","kind":"Persian"}' == content

        data = await request.json()
        assert {"name": "Celine", "kind": "Persian"} == data

        return Response(201, Headers([Header(b'Server', b'Python/3.7')]), JsonContent({'id': '123'}))
예제 #20
0
async def test_from_header_binding_iterables(declared_type, expected_type,
                                             header_values, expected_values):

    request = Request(
        b'GET', b'/',
        Headers([Header(b'X-Foo', value) for value in header_values]), None)

    parameter = FromHeader(declared_type, 'X-Foo')

    value = await parameter.get_value(request)

    assert isinstance(value, expected_type)
    assert value == expected_values
예제 #21
0
def test_cookie_parsing():
    request = Request(
        b'POST', b'/',
        Headers([
            Header(b'Cookie',
                   b'ai=something; hello=world; foo=Hello%20World%3B;')
        ]), None)

    assert request.cookies == {
        b'ai': b'something',
        b'hello': b'world',
        b'foo': b'Hello World;'
    }
예제 #22
0
def test_cookie_parsing_duplicated_cookie_header_value():
    request = Request(
        b'POST', b'/',
        Headers([
            Header(
                b'Cookie',
                b'ai=something; hello=world; foo=Hello%20World%3B; hello=kitty;'
            )
        ]), None)

    assert request.cookies == {
        b'ai': b'something',
        b'hello': b'kitty',
        b'foo': b'Hello World;'
    }
예제 #23
0
async def fortunes_test(request):
    """Test type 4: Fortunes"""

    connection = await db_pool.acquire()

    try:
        fortunes = await connection.fetch('SELECT * FROM Fortune')
    finally:
        await db_pool.release(connection)

    fortunes.append([0, 'Additional fortune added at request time.'])
    fortunes.sort(key=lambda x: x[1])

    return Response(200, Headers([
        Header(b'Cache-Control', b'no-cache')
    ]), content=Content(b'text/html; charset=utf-8', fortune_template.render(fortunes=fortunes).encode('utf8')))
예제 #24
0
def _file(value: Union[Callable, bytes],
          content_type: Union[str, bytes],
          content_disposition_type: ContentDispositionType,
          file_name: str = None):
    if file_name:
        exact_file_name = ntpath.basename(file_name)
        if not exact_file_name:
            raise ValueError(
                'Invalid file name: it should be an exact file name without path, for example: "foo.txt"'
            )

        content_disposition_value = f'{content_disposition_type.value}; filename="{exact_file_name}"'
    else:
        content_disposition_value = content_disposition_type.value
    response = Response(200,
                        content=Content(_ensure_bytes(content_type), value))
    response.headers.add(
        Header(b'Content-Disposition', content_disposition_value.encode()))
    return response
예제 #25
0
def get_response(html: str):
    return Response(200,
                    Headers([Header(b'Cache-Control', b'no-cache')]),
                    content=HtmlContent(html))
예제 #26
0
def redirect(location: Union[bytes, str]):
    """Returns an HTTP 302 Found response (commonly called redirect), to the given location"""
    return Response(302,
                    Headers([Header(b'Location', _ensure_bytes(location))]))
예제 #27
0
                                          ]) as client:
        await client.get(
            b'/'
        )  # the first request doesn't have any cookie because the response will set;
        check_cookie = True
        await client.get(b'/')


@pytest.mark.asyncio
@pytest.mark.parametrize(
    'first_request_url,second_request_url,set_cookies,expected_cookies',
    [[
        b'https://foo.bezkitu.org', b'https://bezkitu.org',
        [
            Header(
                b'Set-Cookie',
                write_response_cookie(
                    Cookie(b'X-Foo', b'Foo', domain=b'bezkitu.org')))
        ], [b'X-Foo']
    ],
     [
         b'https://foo.bezkitu.org', b'https://foo.bezkitu.org',
         [
             Header(
                 b'Set-Cookie',
                 write_response_cookie(
                     Cookie(b'X-Foo', b'Foo', domain=b'foo.bezkitu.org')))
         ], [b'X-Foo']
     ],
     [
         b'https://foo.bezkitu.org', b'https://bezkitu.org',
         [
예제 #28
0
def see_other(location: Union[bytes, str]):
    """Returns an HTTP 303 See Other response, to the given location."""
    return Response(303,
                    Headers([Header(b'Location', _ensure_bytes(location))]))
예제 #29
0
def temporary_redirect(location: Union[bytes, str]):
    """Returns an HTTP 307 Temporary Redirect response, to the given location."""
    return Response(307,
                    Headers([Header(b'Location', _ensure_bytes(location))]))
예제 #30
0
import pytest
from pytest import raises
from typing import List, Sequence, Set, Tuple
from blacksheep import Request, Headers, Header, JsonContent
from blacksheep.server.bindings import (FromJson, FromHeader, FromQuery,
                                        FromRoute, FromServices, RequestBinder,
                                        InvalidRequestBody,
                                        MissingConverterError, BadRequest)

JsonContentType = Header(b'Content-Type', b'application/json')


class ExampleOne:
    def __init__(self, a, b):
        self.a = a
        self.b = b


class ExampleTwo:
    def __init__(self, a, b, **kwargs):
        self.a = a
        self.b = b


@pytest.mark.asyncio
async def test_from_body_json_binding():

    request = Request(b'POST', b'/', Headers([JsonContentType]),
                      JsonContent({
                          'a': 'world',
                          'b': 9000