예제 #1
0
 def test_parse_err(self):
     tutils.raises(language.ParseException, language.parse_pathod, "400:msg,b:")
     try:
         language.parse_pathod("400'msg':b:")
     except language.ParseException as v:
         assert v.marked()
         assert str(v)
예제 #2
0
    def test_parse_pathod(self):
        a = next(parse_pathod("400:ir,@100")).actions[0]
        assert a.offset == "r"
        assert a.value.datatype == "bytes"
        assert a.value.usize == 100

        a = next(parse_pathod("400:ia,@100")).actions[0]
        assert a.offset == "a"
예제 #3
0
def test_shortcuts():
    assert next(language.parse_pathod(
        "400:c'foo'")).headers[0].key.val == b"Content-Type"
    assert next(language.parse_pathod(
        "400:l'foo'")).headers[0].key.val == b"Location"

    assert b"Android" in tservers.render(parse_request("get:/:ua"))
    assert b"User-Agent" in tservers.render(parse_request("get:/:ua"))
예제 #4
0
    def test_render(self):
        s = io.BytesIO()
        r = next(language.parse_pathod("400:m'msg'"))
        assert language.serve(r, s, {})

        r = next(language.parse_pathod("400:p0,100:dr"))
        assert "p0" in r.spec()
        s = r.preview_safe()
        assert "p0" not in s.spec()
예제 #5
0
 def test_length(self):
     def testlen(x):
         s = io.BytesIO()
         x = next(x)
         language.serve(x, s, language.Settings())
         assert x.length(language.Settings()) == len(s.getvalue())
     testlen(language.parse_pathod("400:m'msg':r"))
     testlen(language.parse_pathod("400:m'msg':h'foo'='bar':r"))
     testlen(language.parse_pathod("400:m'msg':h'foo'='bar':b@100b:r"))
예제 #6
0
    def test_raw(self):
        s = io.BytesIO()
        r = next(language.parse_pathod("400:b'foo'"))
        language.serve(r, s, {})
        v = s.getvalue()
        assert b"Content-Length" in v

        s = io.BytesIO()
        r = next(language.parse_pathod("400:b'foo':r"))
        language.serve(r, s, {})
        v = s.getvalue()
        assert b"Content-Length" not in v
예제 #7
0
    def test_raw(self):
        s = StringIO()
        r = language.parse_pathod("400:b'foo'").next()
        language.serve(r, s, {})
        v = s.getvalue()
        assert "Content-Length" in v

        s = StringIO()
        r = language.parse_pathod("400:b'foo':r").next()
        language.serve(r, s, {})
        v = s.getvalue()
        assert "Content-Length" not in v
예제 #8
0
def test_write_values_after():
    s = StringIO()
    r = language.parse_pathod("400:da").next()
    language.serve(r, s, {})

    s = StringIO()
    r = language.parse_pathod("400:pa,0").next()
    language.serve(r, s, {})

    s = StringIO()
    r = language.parse_pathod("400:ia,'xx'").next()
    language.serve(r, s, {})
    assert s.getvalue().endswith("xx")
예제 #9
0
def test_write_values_after():
    s = io.BytesIO()
    r = next(language.parse_pathod("400:da"))
    language.serve(r, s, {})

    s = io.BytesIO()
    r = next(language.parse_pathod("400:pa,0"))
    language.serve(r, s, {})

    s = io.BytesIO()
    r = next(language.parse_pathod("400:ia,'xx'"))
    language.serve(r, s, {})
    assert s.getvalue().endswith(b'xx')
예제 #10
0
    def test_response(self):
        r = next(language.parse_pathod("400:m'msg'"))
        assert r.status_code.string() == b"400"
        assert r.reason.string() == b"msg"

        r = next(language.parse_pathod("400:m'msg':b@100b"))
        assert r.reason.string() == b"msg"
        assert r.body.values({})
        assert str(r)

        r = next(language.parse_pathod("200"))
        assert r.status_code.string() == b"200"
        assert not r.reason
        assert b"OK" in [i[:] for i in r.preamble({})]
예제 #11
0
 def test_parse_stress(self):
     # While larger values are known to work on linux, len() technically
     # returns an int and a python 2.7 int on windows has 32bit precision.
     # Therefore, we should keep the body length < 2147483647 bytes in our
     # tests.
     r = next(language.parse_pathod("400:b@1g"))
     assert r.length({})
예제 #12
0
    def test_maximum_length(self):
        def testlen(x):
            x = next(x)
            s = io.BytesIO()
            m = x.maximum_length({})
            language.serve(x, s, {})
            assert m >= len(s.getvalue())

        r = language.parse_pathod("400:m'msg':b@100:d0")
        testlen(r)

        r = language.parse_pathod("400:m'msg':b@100:d0:i0,'foo'")
        testlen(r)

        r = language.parse_pathod("400:m'msg':b@100:d0:i0,'foo'")
        testlen(r)
예제 #13
0
 def rt(s):
     s = language.parse_pathod(s).next().spec()
     assert language.parse_pathod(s).next().spec() == s
예제 #14
0
 def test_websockets(self):
     r = language.parse_pathod("ws").next()
     tutils.raises("no websocket key", r.resolve, language.Settings())
     res = r.resolve(language.Settings(websocket_key="foo"))
     assert res.status_code.string() == "101"
예제 #15
0
 def rt(s):
     s = next(language.parse_pathod(s)).spec()
     assert next(language.parse_pathod(s)).spec() == s
예제 #16
0
 def test_websockets(self):
     r = next(language.parse_pathod("ws"))
     with pytest.raises("no websocket key"):
         r.resolve(language.Settings())
     res = r.resolve(language.Settings(websocket_key=b"foo"))
     assert res.status_code.string() == b"101"
예제 #17
0
 def test_websockets(self):
     r = next(language.parse_pathod("ws"))
     with pytest.raises(Exception, match="No websocket key"):
         r.resolve(language.Settings())
     res = r.resolve(language.Settings(websocket_key=b"foo"))
     assert res.status_code.string() == b"101"
예제 #18
0
 def test_parse_pause_random(self):
     r = next(language.parse_pathod("400:pr,10"))
     assert r.actions[0].spec() == "pr,10"
예제 #19
0
 def test_parse_pause_before(self):
     r = next(language.parse_pathod("400:p0,10"))
     assert r.actions[0].spec() == "p0,10"
예제 #20
0
 def test_parse_pause_after(self):
     r = next(language.parse_pathod("400:pa,10"))
     assert r.actions[0].spec() == "pa,10"
예제 #21
0
 def test_parse_header(self):
     r = next(language.parse_pathod('400:h"foo"="bar"'))
     assert http.get_header(b"foo", r.headers)
예제 #22
0
 def test_nonascii(self):
     with pytest.raises(Exception, match="ASCII"):
         language.parse_pathod("foo:b\xf0")
예제 #23
0
 def dummy_response(self):
     return next(language.parse_pathod("400'msg'"))
    def handle_http_request(self, logger):
        """
            Returns a (handler, log) tuple.

            handler: Handler for the next request, or None to disconnect
            log: A dictionary, or None
        """
        with logger.ctx() as lg:
            try:
                req = self.protocol.read_request(self.rfile)
            except exceptions.HttpReadDisconnect:
                return None, None
            except exceptions.HttpException as s:
                s = str(s)
                lg(s)
                return None, dict(type="error", msg=s)

            if req.method == 'CONNECT':
                return self.protocol.handle_http_connect(
                    [req.host, req.port, req.http_version], lg)

            method = req.method
            path = req.path
            http_version = req.http_version
            headers = req.headers
            first_line_format = req.first_line_format

            clientcert = None
            if self.clientcert:
                clientcert = dict(
                    cn=self.clientcert.cn,
                    subject=self.clientcert.subject,
                    serial=self.clientcert.serial,
                    notbefore=self.clientcert.notbefore.isoformat(),
                    notafter=self.clientcert.notafter.isoformat(),
                    keyinfo=self.clientcert.keyinfo,
                )

            retlog = dict(
                type="crafted",
                protocol="http",
                request=dict(path=path,
                             method=method,
                             headers=headers.fields,
                             http_version=http_version,
                             sni=self.sni,
                             remote_address=self.address,
                             clientcert=clientcert,
                             first_line_format=first_line_format),
                cipher=None,
            )
            if self.ssl_established:
                retlog["cipher"] = self.get_current_cipher()

            m = utils.MemBool()

            valid_websocket_handshake = websockets.check_handshake(headers)
            self.settings.websocket_key = websockets.get_client_key(headers)

            # If this is a websocket initiation, we respond with a proper
            # server response, unless over-ridden.
            if valid_websocket_handshake:
                anchor_gen = language.parse_pathod("ws")
            else:
                anchor_gen = None

            for regex, spec in self.server.anchors:
                if regex.match(path):
                    anchor_gen = language.parse_pathod(spec, self.use_http2)
                    break
            else:
                if m(path.startswith(self.server.craftanchor)):
                    spec = urllib.parse.unquote(
                        path)[len(self.server.craftanchor):]
                    if spec:
                        try:
                            anchor_gen = language.parse_pathod(
                                spec, self.use_http2)
                        except language.ParseException as v:
                            lg("Parse error: %s" % v.msg)
                            anchor_gen = iter([
                                self.make_http_error_response(
                                    "Parse Error",
                                    "Error parsing response spec: %s\n" %
                                    (v.msg + v.marked()))
                            ])
                else:
                    if self.use_http2:
                        anchor_gen = iter([
                            self.make_http_error_response(
                                "Spec Error",
                                "HTTP/2 only supports request/response with the craft anchor point: %s"
                                % self.server.craftanchor)
                        ])

            if not anchor_gen:
                anchor_gen = iter([
                    self.make_http_error_response(
                        "Not found", "No valid craft request found")
                ])

            spec = next(anchor_gen)

            if self.use_http2 and isinstance(spec, language.http2.Response):
                spec.stream_id = req.stream_id

            lg("crafting spec: %s" % spec)
            nexthandler, retlog["response"] = self.http_serve_crafted(spec, lg)
            if nexthandler and valid_websocket_handshake:
                self.protocol = protocols.websockets.WebsocketsProtocol(self)
                return self.protocol.handle_websocket, retlog
            else:
                return nexthandler, retlog
예제 #25
0
def parse_response(s):
    return next(language.parse_pathod(s, True))
예제 #26
0
def test_unique_components():
    with pytest.raises(Exception, match="multiple body clauses"):
        language.parse_pathod("400:b@1:b@1")
예제 #27
0
 def rt(s):
     s = next(language.parse_pathod(s)).spec()
     assert next(language.parse_pathod(s)).spec() == s
예제 #28
0
 def test_parse_header(self):
     r = next(language.parse_pathod('400:h"foo"="bar"'))
     assert http.get_header(b"foo", r.headers)
예제 #29
0
 def test_request(self):
     r = next(parse_pathod('400:p10,10'))
     assert r.actions[0].spec() == "p10,10"
예제 #30
0
 def test_parse_pause_after(self):
     r = next(language.parse_pathod("400:pa,10"))
     assert r.actions[0].spec() == "pa,10"
예제 #31
0
 def test_serve(self):
     s = StringIO()
     r = language.parse_pathod("400:i0,'foo'").next()
     assert language.serve(r, s, {})
예제 #32
0
def parse_response(s):
    return language.parse_pathod(s, True).next()
예제 #33
0
def test_unique_components():
    with pytest.raises("multiple body clauses"):
        language.parse_pathod("400:b@1:b@1")
예제 #34
0
 def test_websockets(self):
     r = next(language.parse_pathod("ws"))
     tutils.raises("no websocket key", r.resolve, language.Settings())
     res = r.resolve(language.Settings(websocket_key=b"foo"))
     assert res.status_code.string() == b"101"
예제 #35
0
 def test_parse_pause_before(self):
     r = next(language.parse_pathod("400:p0,10"))
     assert r.actions[0].spec() == "p0,10"
예제 #36
0
 def test_parse_pathod(self):
     a = language.parse_pathod("400:d0").next().actions[0]
     assert a.spec() == "d0"
     a = language.parse_pathod("400:dr").next().actions[0]
     assert a.spec() == "dr"
예제 #37
0
 def test_request(self):
     r = next(parse_pathod('400:p10,10'))
     assert r.actions[0].spec() == "p10,10"
예제 #38
0
 def test_request(self):
     r = language.parse_pathod('400:p10,10').next()
     assert r.actions[0].spec() == "p10,10"
예제 #39
0
 def test_serve(self):
     s = BytesIO()
     r = next(parse_pathod("400:i0,'foo'"))
     assert serve(r, s, {})
예제 #40
0
 def test_nonascii(self):
     with pytest.raises("ascii"):
         language.parse_pathod("foo:b\xf0")
예제 #41
0
 def test_parse_pause_random(self):
     r = next(language.parse_pathod("400:pr,10"))
     assert r.actions[0].spec() == "pr,10"
예제 #42
0
 def test_parse_pathod(self):
     a = next(parse_pathod("400:d0")).actions[0]
     assert a.spec() == "d0"
     a = next(parse_pathod("400:dr")).actions[0]
     assert a.spec() == "dr"
예제 #43
0
 def rt(s):
     s = language.parse_pathod(s).next().spec()
     assert language.parse_pathod(s).next().spec() == s
예제 #44
0
 def test_serve(self):
     s = BytesIO()
     r = next(parse_pathod("400:i0,'foo'"))
     assert serve(r, s, {})
예제 #45
0
 def dummy_response(self):
     return next(language.parse_pathod("400'msg'"))
예제 #46
0
    def handle_http_request(self, logger):
        """
            Returns a (handler, log) tuple.

            handler: Handler for the next request, or None to disconnect
            log: A dictionary, or None
        """
        with logger.ctx() as lg:
            try:
                req = self.protocol.read_request(self.rfile)
            except exceptions.HttpReadDisconnect:
                return None, None
            except exceptions.HttpException as s:
                s = str(s)
                lg(s)
                return None, dict(type="error", msg=s)

            if req.method == 'CONNECT':
                return self.protocol.handle_http_connect([req.host, req.port, req.http_version], lg)

            method = req.method
            path = req.path
            http_version = req.http_version
            headers = req.headers
            first_line_format = req.first_line_format

            clientcert = None
            if self.clientcert:
                clientcert = dict(
                    cn=self.clientcert.cn,
                    subject=self.clientcert.subject,
                    serial=self.clientcert.serial,
                    notbefore=self.clientcert.notbefore.isoformat(),
                    notafter=self.clientcert.notafter.isoformat(),
                    keyinfo=self.clientcert.keyinfo,
                )

            retlog = dict(
                type="crafted",
                protocol="http",
                request=dict(
                    path=path,
                    method=method,
                    headers=headers.fields,
                    http_version=http_version,
                    sni=self.sni,
                    remote_address=self.address,
                    clientcert=clientcert,
                    first_line_format=first_line_format
                ),
                cipher=None,
            )
            if self.ssl_established:
                retlog["cipher"] = self.get_current_cipher()

            m = utils.MemBool()

            valid_websocket_handshake = websockets.check_handshake(headers)
            self.settings.websocket_key = websockets.get_client_key(headers)

            # If this is a websocket initiation, we respond with a proper
            # server response, unless over-ridden.
            if valid_websocket_handshake:
                anchor_gen = language.parse_pathod("ws")
            else:
                anchor_gen = None

            for regex, spec in self.server.anchors:
                if regex.match(path):
                    anchor_gen = language.parse_pathod(spec, self.use_http2)
                    break
            else:
                if m(path.startswith(self.server.craftanchor)):
                    spec = urllib.parse.unquote(path)[len(self.server.craftanchor):]
                    if spec:
                        try:
                            anchor_gen = language.parse_pathod(spec, self.use_http2)
                        except language.ParseException as v:
                            lg("Parse error: %s" % v.msg)
                            anchor_gen = iter([self.make_http_error_response(
                                "Parse Error",
                                "Error parsing response spec: %s\n" % (
                                    v.msg + v.marked()
                                )
                            )])
                else:
                    if self.use_http2:
                        anchor_gen = iter([self.make_http_error_response(
                            "Spec Error",
                            "HTTP/2 only supports request/response with the craft anchor point: %s" %
                            self.server.craftanchor
                        )])

            if not anchor_gen:
                anchor_gen = iter([self.make_http_error_response(
                    "Not found",
                    "No valid craft request found"
                )])

            spec = next(anchor_gen)

            if self.use_http2 and isinstance(spec, language.http2.Response):
                spec.stream_id = req.stream_id

            lg("crafting spec: %s" % spec)
            nexthandler, retlog["response"] = self.http_serve_crafted(
                spec,
                lg
            )
            if nexthandler and valid_websocket_handshake:
                self.protocol = protocols.websockets.WebsocketsProtocol(self)
                return self.protocol.handle_websocket, retlog
            else:
                return nexthandler, retlog
예제 #47
0
 def test_parse_pathod(self):
     a = next(parse_pathod("400:d0")).actions[0]
     assert a.spec() == "d0"
     a = next(parse_pathod("400:dr")).actions[0]
     assert a.spec() == "dr"