diff options
| -rw-r--r-- | libpathod/language/http2.py | 19 | ||||
| -rw-r--r-- | libpathod/pathoc.py | 7 | ||||
| -rw-r--r-- | libpathod/pathod.py | 7 | ||||
| -rw-r--r-- | test/test_language_http2.py | 111 | ||||
| -rw-r--r-- | test/test_pathod.py | 14 | ||||
| -rw-r--r-- | test/tutils.py | 6 | 
6 files changed, 141 insertions, 23 deletions
diff --git a/libpathod/language/http2.py b/libpathod/language/http2.py index c28b904e..dec2d5fe 100644 --- a/libpathod/language/http2.py +++ b/libpathod/language/http2.py @@ -35,8 +35,15 @@ class Path(base.Value):  class Header(base.KeyValue): +    unique_name = None      preamble = "h" +    def values(self, settings): +        return ( +            self.key.get_generator(settings), +            self.value.get_generator(settings), +        ) +  class Body(base.Value):      preamble = "b" @@ -45,9 +52,11 @@ class Body(base.Value):  class Times(base.Integer):      preamble = "x" +  class Code(base.Integer):      pass +  class Request(message.Message):      comps = (          Header, @@ -57,7 +66,7 @@ class Request(message.Message):      logattrs = ["method", "path"]      def __init__(self, tokens): -        super(Response, self).__init__(tokens) +        super(Request, self).__init__(tokens)          self.rendered_values = None      @property @@ -106,9 +115,7 @@ class Request(message.Message):          if self.rendered_values:              return self.rendered_values          else: -            headers = self.headers -            if headers: -                headers = headers.values(settings) +            headers = [header.values(settings) for header in self.headers]              body = self.body              if body: @@ -173,9 +180,7 @@ class Response(message.Message):          if self.rendered_values:              return self.rendered_values          else: -            headers = self.headers -            if headers: -                headers = headers.values(settings) +            headers = [header.values(settings) for header in self.headers]              body = self.body              if body: diff --git a/libpathod/pathoc.py b/libpathod/pathoc.py index 9c021360..c42cc82a 100644 --- a/libpathod/pathoc.py +++ b/libpathod/pathoc.py @@ -30,13 +30,8 @@ class SSLInfo:          self.certchain, self.cipher, self.alp = certchain, cipher, alp      def __str__(self): -        if self.alp: -            alp = self.alp -        else: -            alp = '<no protocol negotiated>' -          parts = [ -            "Application Layer Protocol: %s" % alp, +            "Application Layer Protocol: %s" % self.alp,              "Cipher: %s, %s bit, %s" % self.cipher,              "SSL certificate chain:"          ] diff --git a/libpathod/pathod.py b/libpathod/pathod.py index b6f04b92..212abbdc 100644 --- a/libpathod/pathod.py +++ b/libpathod/pathod.py @@ -234,6 +234,7 @@ class PathodHandler(tcp.BaseHandler):                  method = headers[':method']                  path = headers[':path']                  headers = odict.ODict(headers) +                httpversion = ""              else:                  req = self.read_http_request(lg)                  if 'next_handle' in req: @@ -246,6 +247,7 @@ class PathodHandler(tcp.BaseHandler):                  path = req['path']                  headers = req['headers']                  body = req['body'] +                httpversion = req['httpversion']              clientcert = None              if self.clientcert: @@ -265,7 +267,7 @@ class PathodHandler(tcp.BaseHandler):                      path=path,                      method=method,                      headers=headers.lst, -                    # httpversion=httpversion, +                    httpversion=httpversion,                      sni=self.sni,                      remote_address=self.address(),                      clientcert=clientcert, @@ -375,7 +377,8 @@ class PathodHandler(tcp.BaseHandler):              method=method,              path=path,              headers=headers, -            body=body) +            body=body, +            httpversion=httpversion)      def make_http_error_response(self, reason, body=None):          """ diff --git a/test/test_language_http2.py b/test/test_language_http2.py index 3c751fd1..0be42253 100644 --- a/test/test_language_http2.py +++ b/test/test_language_http2.py @@ -10,8 +10,29 @@ import tutils  def parse_request(s):      return language.parse_pathoc(s, True).next() +def parse_response(s): +    return language.parse_pathod(s, True).next() + +def default_settings(): +    return language.Settings( +        request_host = "foo.com", +        protocol = netlib.http2.HTTP2Protocol(tcp.TCPClient(('localhost', 1234))) +    ) + + +def test_make_error_response(): +    d = cStringIO.StringIO() +    s = http2.make_error_response("foo", "bar") +    language.serve(s, d, default_settings()) +  class TestRequest: +    def test_cached_values(self): +        req = parse_request("get:/") +        req_id = id(req) +        assert req_id == id(req.resolve(default_settings())) +        assert req.values(default_settings()) == req.values(default_settings()) +      def test_nonascii(self):          tutils.raises("ascii", parse_request, "get:\xf0") @@ -57,16 +78,31 @@ class TestRequest:          assert r[0].method.string() == "GET"          assert r[1].method.string() == "GET" -    def test_render(self): +    def test_render_simple(self):          s = cStringIO.StringIO()          r = parse_request("GET:'/foo'")          assert language.serve(              r,              s, -            language.Settings( -                request_host = "foo.com", -                protocol = netlib.http2.HTTP2Protocol(tcp.TCPClient(('localhost', 1234))) -            ) +            default_settings(), +        ) + +    def test_render_with_headers(self): +        s = cStringIO.StringIO() +        r = parse_request('GET:/foo:h"foo"="bar"') +        assert language.serve( +            r, +            s, +            default_settings(), +        ) + +    def test_render_with_body(self): +        s = cStringIO.StringIO() +        r = parse_request("GET:'/foo':bfoobar") +        assert language.serve( +            r, +            s, +            default_settings(),          )      def test_spec(self): @@ -74,3 +110,68 @@ class TestRequest:              s = parse_request(s).spec()              assert parse_request(s).spec() == s          rt("get:/foo") + + +class TestResponse: +    def test_cached_values(self): +        res = parse_response("200") +        res_id = id(res) +        assert res_id == id(res.resolve(default_settings())) +        assert res.values(default_settings()) == res.values(default_settings()) + +    def test_nonascii(self): +        tutils.raises("ascii", parse_response, "200:\xf0") + +    def test_err(self): +        tutils.raises(language.ParseException, parse_response, 'GET:/') + +    def test_simple(self): +        r = parse_response('200') +        assert r.code.string() == "200" +        assert len(r.headers) == 0 + +        r = parse_response('200:h"foo"="bar"') +        assert r.code.string() == "200" +        assert len(r.headers) == 1 +        assert r.headers[0].values(default_settings()) == ("foo", "bar") +        assert r.body == None + +        r = parse_response('200:h"foo"="bar":bfoobar:h"bla"="fasel"') +        assert r.code.string() == "200" +        assert len(r.headers) == 2 +        assert r.headers[0].values(default_settings()) == ("foo", "bar") +        assert r.headers[1].values(default_settings()) == ("bla", "fasel") +        assert r.body.string() == "foobar" + +    def test_render_simple(self): +        s = cStringIO.StringIO() +        r = parse_response('200') +        assert language.serve( +            r, +            s, +            default_settings(), +        ) + +    def test_render_with_headers(self): +        s = cStringIO.StringIO() +        r = parse_response('200:h"foo"="bar"') +        assert language.serve( +            r, +            s, +            default_settings(), +        ) + +    def test_render_with_body(self): +        s = cStringIO.StringIO() +        r = parse_response('200:bfoobar') +        assert language.serve( +            r, +            s, +            default_settings(), +        ) + +    def test_spec(self): +        def rt(s): +            s = parse_response(s).spec() +            assert parse_response(s).spec() == s +        rt("200:bfoobar") diff --git a/test/test_pathod.py b/test/test_pathod.py index f85ef38d..1a3a5004 100644 --- a/test/test_pathod.py +++ b/test/test_pathod.py @@ -1,7 +1,7 @@  import sys  import cStringIO  from libpathod import pathod, version -from netlib import tcp, http +from netlib import tcp, http, http2  import tutils @@ -269,3 +269,15 @@ class TestDaemonSSL(CommonTests):          r, _ = self.pathoc([r"get:/p/202"])          assert r[0].status_code == 202          assert self.d.last_log()["cipher"][1] > 0 + +class TestHTTP2(tutils.DaemonTests): +    force_http2 = True +    ssl = True +    noweb = True +    noapi = True +    nohang = True + +    def test_http2(self): +        r, _ = self.pathoc(["GET:/"], ssl=True, use_http2=True) +        print(r) +        assert r[0].status_code == "800" diff --git a/test/tutils.py b/test/tutils.py index 60c0765a..2184ade5 100644 --- a/test/tutils.py +++ b/test/tutils.py @@ -73,7 +73,8 @@ class DaemonTests(object):          timeout=None,          connect_to=None,          ssl=None, -        ws_read_limit=None +        ws_read_limit=None, +        use_http2=False,      ):          """              Returns a (messages, text log) tuple. @@ -86,7 +87,8 @@ class DaemonTests(object):              ssl=ssl,              ws_read_limit=ws_read_limit,              timeout = timeout, -            fp = logfp +            fp = logfp, +            use_http2 = use_http2,          )          c.connect(connect_to)          ret = []  | 
