aboutsummaryrefslogtreecommitdiffstats
path: root/libpathod/language/http2.py
blob: d78fc5c86086bb931f22164f3f16b541313c01f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import os
import netlib.http2
import pyparsing as pp
from . import base, generators, actions, message

"""
    Normal HTTP requests:
        <method>:<path>:<header>:<body>
    e.g.:
        GET:/
        GET:/:foo=bar
        POST:/:foo=bar:'content body payload'

    Individual HTTP/2 frames:
        h2f:<payload_length>:<type>:<flags>:<stream_id>:<payload>
    e.g.:
        h2f:0:PING
        h2f:42:HEADERS:END_HEADERS:0x1234567:foo=bar,host=example.com
        h2f:42:DATA:END_STREAM,PADDED:0x1234567:'content body payload'
"""


class Method(base.OptionsOrValue):
    options = [
        "GET",
        "HEAD",
        "POST",
        "PUT",
        "DELETE",
    ]


class Path(base.Value):
    pass


class Header(base.KeyValue):
    preamble = "h"


class Body(base.Value):
    preamble = "b"


class Times(base.Integer):
    preamble = "x"


class Request(message.Message):
    comps = (
        Header,
        Body,

        Times,
    )

    @property
    def method(self):
        return self.tok(Method)

    @property
    def path(self):
        return self.tok(Path)

    @property
    def headers(self):
        return self.toks(Header)

    @property
    def body(self):
        return self.tok(Body)

    @property
    def times(self):
        return self.tok(Times)

    @property
    def actions(self):
        return []

    @classmethod
    def expr(klass):
        parts = [i.expr() for i in klass.comps]
        atom = pp.MatchFirst(parts)
        resp = pp.And(
            [
                Method.expr(),
                base.Sep,
                Path.expr(),
                base.Sep,
                pp.ZeroOrMore(base.Sep + atom)
            ]
        )
        resp = resp.setParseAction(klass)
        return resp

    def resolve(self, settings, msg=None):
        tokens = self.tokens[:]
        return self.__class__(
            [i.resolve(settings, self) for i in tokens]
        )

    def values(self, settings):
        return settings.protocol.create_request(
            self.method.value.get_generator(settings),
            self.path,
            self.headers,
            self.body)

    def spec(self):
        return ":".join([i.spec() for i in self.tokens])


# class H2F(base.CaselessLiteral):
#     TOK = "h2f"
#
#
# class WebsocketFrame(message.Message):
#     pass