Ejemplo n.º 1
0
class TestStore:
    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)

    def test_500_01(self):
        url = TestEnv.mkurl("https", "cgi", "/proxy/hello.py")
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/1.1" == r["response"]["json"]["protocol"]
        assert "" == r["response"]["json"]["https"]
        assert "" == r["response"]["json"]["ssl_protocol"]
        assert "" == r["response"]["json"]["h2"]
        assert "" == r["response"]["json"]["h2push"]

    # upload and GET again using curl, compare to original content
    def curl_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/proxy/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)
        r = TestEnv.curl_upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert 200 <= r["response"]["status"] < 300

        # why is the scheme wrong?
        r2 = TestEnv.curl_get(
            re.sub(r'http:', 'https:', r["response"]["header"]["location"]))
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]

    def test_500_10(self):
        self.curl_upload_and_verify("data-1k", ["--http2"])
        self.curl_upload_and_verify("data-10k", ["--http2"])
        self.curl_upload_and_verify("data-100k", ["--http2"])
        self.curl_upload_and_verify("data-1m", ["--http2"])

    # POST some data using nghttp and see it echo'ed properly back
    def nghttp_post_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/proxy/echo.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)
        r = TestEnv.nghttp().upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert 200 <= r["response"]["status"] < 300
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        #assert len(src) == len(r["response"]["body"])
        assert src == r["response"]["body"]

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_500_20(self):
        self.nghttp_post_and_verify("data-1k", [])
        self.nghttp_post_and_verify("data-10k", [])
        self.nghttp_post_and_verify("data-100k", [])
        self.nghttp_post_and_verify("data-1m", [])

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_500_21(self):
        self.nghttp_post_and_verify("data-1k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-10k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-100k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-1m", ["--no-content-length"])

    # upload and GET again using nghttp, compare to original content
    def nghttp_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/proxy/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload_file(url, fpath, options=options)
        assert r["rv"] == 0
        assert 200 <= r["response"]["status"] < 300
        assert r["response"]["header"]["location"]

        # why is the scheme wrong?
        r2 = TestEnv.nghttp().get(
            re.sub(r'http:', 'https:', r["response"]["header"]["location"]))
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_500_22(self):
        self.nghttp_upload_and_verify("data-1k", [])
        self.nghttp_upload_and_verify("data-10k", [])
        self.nghttp_upload_and_verify("data-100k", [])
        self.nghttp_upload_and_verify("data-1m", [])

    @pytest.mark.skipif(
        not TestEnv.has_nghttp() or True,
        reason="no nghttp command available and python3 chokes in chunks")
    def test_500_23(self):
        self.nghttp_upload_and_verify("data-1k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-10k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-100k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-1m", ["--no-content-length"])

    # upload using nghttp and check returned status
    def nghttp_upload_stat(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/proxy/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload_file(url, fpath, options=options)
        assert r["rv"] == 0
        assert 200 <= r["response"]["status"] < 300
        assert r["response"]["header"]["location"]

    @pytest.mark.skipif(
        not TestEnv.has_nghttp() or True,
        reason="no nghttp command available and python3 chokes on chunks")
    def test_500_24(self):
        for i in range(100):
            self.nghttp_upload_stat("data-1k", ["--no-content-length"])
Ejemplo n.º 2
0
    HttpdConf().add_vhost_cgi(h2proxy_self=True).install()
    assert TestEnv.apache_restart() == 0
        
def teardown_module(module):
    print("teardown_module: %s" % module.__name__)
    assert TestEnv.apache_stop() == 0

def setup_data():
    s100="012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678\n"
    with open(os.path.join(TestEnv.GEN_DIR, "data-1k"), 'w') as f:
        for i in range(10):
            f.write(s100)

# The trailer tests depend on "nghttp" as no other client seems to be able to send those
# rare things.
@pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
class TestStore:

    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)

    # check if the server survives a trailer or two
    def test_202_01(self):
        url = TestEnv.mkurl("https", "cgi", "/echo.py")
        fpath = os.path.join(TestEnv.GEN_DIR, "data-1k")
        r = TestEnv.nghttp().upload(url, fpath, options=[ "--trailer", "test: 1" ])
        assert 300 > r["response"]["status"]
        assert 1000 == len(r["response"]["body"])
Ejemplo n.º 3
0
class TestStore:
    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)

    # upload and GET again using curl, compare to original content
    def curl_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)
        r = TestEnv.curl_upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300

        r2 = TestEnv.curl_get(r["response"]["header"]["location"])
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]

    def test_004_01(self):
        self.curl_upload_and_verify("data-1k", ["--http1.1"])
        self.curl_upload_and_verify("data-1k", ["--http2"])

    def test_004_02(self):
        self.curl_upload_and_verify("data-10k", ["--http1.1"])
        self.curl_upload_and_verify("data-10k", ["--http2"])

    def test_004_03(self):
        self.curl_upload_and_verify("data-100k", ["--http1.1"])
        self.curl_upload_and_verify("data-100k", ["--http2"])

    def test_004_04(self):
        self.curl_upload_and_verify("data-1m", ["--http1.1"])
        self.curl_upload_and_verify("data-1m", ["--http2"])

    def test_004_05(self):
        self.curl_upload_and_verify(
            "data-1k", ["-v", "--http1.1", "-H", "Expect: 100-continue"])
        self.curl_upload_and_verify(
            "data-1k", ["-v", "--http2", "-H", "Expect: 100-continue"])

    @pytest.mark.skipif(True,
                        reason="python3 regresses in chunked inputs to cgi")
    def test_004_06(self):
        self.curl_upload_and_verify("data-1k",
                                    ["--http1.1", "-H", "Content-Length: "])
        self.curl_upload_and_verify("data-1k",
                                    ["--http2", "-H", "Content-Length: "])

    # verify that we parse nghttp output correctly
    def check_nghttp_body(self, ref_input, nghttp_output):
        with open(TestEnv.e2e_src(os.path.join(TestEnv.GEN_DIR, ref_input)),
                  mode='rb') as f:
            refbody = f.read()
        with open(TestEnv.e2e_src(nghttp_output), mode='rb') as f:
            text = f.read()
        o = TestEnv.nghttp().parse_output(text)
        assert "response" in o
        assert "body" in o["response"]
        if refbody != o["response"]["body"]:
            with open(TestEnv.e2e_src(
                    os.path.join(TestEnv.GEN_DIR, '%s.parsed' % ref_input)),
                      mode='bw') as f:
                f.write(o["response"]["body"])
        assert len(refbody) == len(o["response"]["body"])
        assert refbody == o["response"]["body"]

    def test_004_20(self):
        self.check_nghttp_body('data-1k', 'data/nghttp-output-1k-1.txt')
        self.check_nghttp_body('data-10k', 'data/nghttp-output-10k-1.txt')
        self.check_nghttp_body('data-100k', 'data/nghttp-output-100k-1.txt')

    # POST some data using nghttp and see it echo'ed properly back
    def nghttp_post_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/echo.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300

        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r["response"]["body"]

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_21(self):
        self.nghttp_post_and_verify("data-1k", [])
        self.nghttp_post_and_verify("data-10k", [])
        self.nghttp_post_and_verify("data-100k", [])
        self.nghttp_post_and_verify("data-1m", [])

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_22(self):
        self.nghttp_post_and_verify("data-1k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-10k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-100k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-1m", ["--no-content-length"])

    # upload and GET again using nghttp, compare to original content
    def nghttp_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload_file(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300
        assert r["response"]["header"]["location"]

        r2 = TestEnv.nghttp().get(r["response"]["header"]["location"])
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_23(self):
        self.nghttp_upload_and_verify("data-1k", [])
        self.nghttp_upload_and_verify("data-10k", [])
        self.nghttp_upload_and_verify("data-100k", [])
        self.nghttp_upload_and_verify("data-1m", [])

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_24(self):
        self.nghttp_upload_and_verify("data-1k", ["--expect-continue"])
        self.nghttp_upload_and_verify("data-100k", ["--expect-continue"])

    @pytest.mark.skipif(True,
                        reason="python3 regresses in chunked inputs to cgi")
    def test_004_25(self):
        self.nghttp_upload_and_verify("data-1k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-10k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-100k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-1m", ["--no-content-length"])
Ejemplo n.º 4
0
        H2PushResource "/006/006.css" critical
    </Location>
    <Location /006-push32.html>
        Header add Link "</006/006.css>;rel=preload"
    </Location>
    """).end_vhost().install()
    assert TestEnv.apache_restart() == 0


def teardown_module(module):
    print("teardown_module: %s" % module.__name__)
    assert TestEnv.apache_stop() == 0


# The push tests depend on "nghttp"
@pytest.mark.skipif(not TestEnv.has_nghttp(),
                    reason="no nghttp command available")
class TestStore:
    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)

    ############################
    # Link: header handling, various combinations

    # plain resource without configured pushes
    def test_400_00(self):
        url = TestEnv.mkurl("https", "push", "/006.html")
        r = TestEnv.nghttp().get(url)
Ejemplo n.º 5
0
class TestStore:

    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)
    
    # single page without any assets
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_006_01(self):
        url = TestEnv.mkurl("https", "test1", "/001.html")
        r = TestEnv.nghttp().assets(url)
        assert 0 == r["rv"]
        assert 1 == len(r["assets"])
        assert r["assets"] == [
            { "status": 200, "size": "251", "path" : "/001.html" }
        ]

    # single image without any assets
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_006_02(self):
        url = TestEnv.mkurl("https", "test1", "/002.jpg")
        r = TestEnv.nghttp().assets(url)
        assert 0 == r["rv"]
        assert 1 == len(r["assets"])
        assert r["assets"] == [
            { "status": 200, "size": "88K", "path" : "/002.jpg" }
        ]
        
    # gophertiles, yea!
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_006_03(self):
        url = TestEnv.mkurl("https", "test1", "/004.html")
        r = TestEnv.nghttp().assets(url)
        assert 0 == r["rv"]
        assert 181 == len(r["assets"])
        assert r["assets"] == [
            { "status": 200, "size": "10K", "path": "/004.html" },
            { "status": 200, "size": "742", "path": "/004/gophertiles.jpg" },
            { "status": 200, "size": "945", "path": "/004/gophertiles_002.jpg" },
            { "status": 200, "size": "697", "path": "/004/gophertiles_003.jpg" },            
            { "status": 200, "size": "725", "path": "/004/gophertiles_004.jpg" },
            { "status": 200, "size": "837", "path": "/004/gophertiles_005.jpg" },
            { "status": 200, "size": "770", "path": "/004/gophertiles_006.jpg" },
            { "status": 200, "size": "747", "path": "/004/gophertiles_007.jpg" },
            { "status": 200, "size": "694", "path": "/004/gophertiles_008.jpg" },
            { "status": 200, "size": "704", "path": "/004/gophertiles_009.jpg" },
            { "status": 200, "size": "994", "path": "/004/gophertiles_010.jpg" },
            { "status": 200, "size": "979", "path": "/004/gophertiles_011.jpg" },
            { "status": 200, "size": "895", "path": "/004/gophertiles_012.jpg" },
            { "status": 200, "size": "958", "path": "/004/gophertiles_013.jpg" },
            { "status": 200, "size": "894", "path": "/004/gophertiles_014.jpg" },
            { "status": 200, "size": "702", "path": "/004/gophertiles_015.jpg" },
            { "status": 200, "size": "703", "path": "/004/gophertiles_016.jpg" },
            { "status": 200, "size": "707", "path": "/004/gophertiles_017.jpg" },
            { "status": 200, "size": "701", "path": "/004/gophertiles_018.jpg" },
            { "status": 200, "size": "1013", "path": "/004/gophertiles_019.jpg" },
            { "status": 200, "size": "737", "path": "/004/gophertiles_020.jpg" },
            { "status": 200, "size": "801", "path": "/004/gophertiles_021.jpg" },
            { "status": 200, "size": "702", "path": "/004/gophertiles_022.jpg" },
            { "status": 200, "size": "905", "path": "/004/gophertiles_023.jpg" },
            { "status": 200, "size": "980", "path": "/004/gophertiles_024.jpg" },
            { "status": 200, "size": "708", "path": "/004/gophertiles_025.jpg" },
            { "status": 200, "size": "694", "path": "/004/gophertiles_026.jpg" },
            { "status": 200, "size": "697", "path": "/004/gophertiles_027.jpg" },
            { "status": 200, "size": "795", "path": "/004/gophertiles_028.jpg" },
            { "status": 200, "size": "978", "path": "/004/gophertiles_029.jpg" },
            { "status": 200, "size": "707", "path": "/004/gophertiles_030.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_031.jpg" },
            { "status": 200, "size": "688", "path": "/004/gophertiles_032.jpg" },
            { "status": 200, "size": "701", "path": "/004/gophertiles_033.jpg" },
            { "status": 200, "size": "898", "path": "/004/gophertiles_034.jpg" },
            { "status": 200, "size": "986", "path": "/004/gophertiles_035.jpg" },
            { "status": 200, "size": "770", "path": "/004/gophertiles_036.jpg" },
            { "status": 200, "size": "959", "path": "/004/gophertiles_037.jpg" },
            { "status": 200, "size": "936", "path": "/004/gophertiles_038.jpg" },
            { "status": 200, "size": "700", "path": "/004/gophertiles_039.jpg" },
            { "status": 200, "size": "784", "path": "/004/gophertiles_040.jpg" },
            { "status": 200, "size": "758", "path": "/004/gophertiles_041.jpg" },
            { "status": 200, "size": "796", "path": "/004/gophertiles_042.jpg" },
            { "status": 200, "size": "813", "path": "/004/gophertiles_043.jpg" },
            { "status": 200, "size": "924", "path": "/004/gophertiles_044.jpg" },
            { "status": 200, "size": "978", "path": "/004/gophertiles_045.jpg" },
            { "status": 200, "size": "752", "path": "/004/gophertiles_046.jpg" },
            { "status": 200, "size": "751", "path": "/004/gophertiles_047.jpg" },
            { "status": 200, "size": "737", "path": "/004/gophertiles_048.jpg" },
            { "status": 200, "size": "992", "path": "/004/gophertiles_049.jpg" },
            { "status": 200, "size": "688", "path": "/004/gophertiles_050.jpg" },
            { "status": 200, "size": "697", "path": "/004/gophertiles_051.jpg" },
            { "status": 200, "size": "699", "path": "/004/gophertiles_052.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_053.jpg" },
            { "status": 200, "size": "694", "path": "/004/gophertiles_054.jpg" },
            { "status": 200, "size": "767", "path": "/004/gophertiles_055.jpg" },
            { "status": 200, "size": "952", "path": "/004/gophertiles_056.jpg" },
            { "status": 200, "size": "788", "path": "/004/gophertiles_057.jpg" },
            { "status": 200, "size": "759", "path": "/004/gophertiles_058.jpg" },
            { "status": 200, "size": "700", "path": "/004/gophertiles_059.jpg" },
            { "status": 200, "size": "985", "path": "/004/gophertiles_060.jpg" },
            { "status": 200, "size": "915", "path": "/004/gophertiles_061.jpg" },
            { "status": 200, "size": "681", "path": "/004/gophertiles_062.jpg" },
            { "status": 200, "size": "707", "path": "/004/gophertiles_063.jpg" },
            { "status": 200, "size": "693", "path": "/004/gophertiles_064.jpg" },
            { "status": 200, "size": "861", "path": "/004/gophertiles_065.jpg" },
            { "status": 200, "size": "991", "path": "/004/gophertiles_066.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_067.jpg" },
            { "status": 200, "size": "697", "path": "/004/gophertiles_068.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_069.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_070.jpg" },
            { "status": 200, "size": "784", "path": "/004/gophertiles_071.jpg" },
            { "status": 200, "size": "698", "path": "/004/gophertiles_072.jpg" },
            { "status": 200, "size": "1004", "path": "/004/gophertiles_073.jpg" },
            { "status": 200, "size": "969", "path": "/004/gophertiles_074.jpg" },
            { "status": 200, "size": "915", "path": "/004/gophertiles_075.jpg" },
            { "status": 200, "size": "784", "path": "/004/gophertiles_076.jpg" },
            { "status": 200, "size": "697", "path": "/004/gophertiles_077.jpg" },
            { "status": 200, "size": "692", "path": "/004/gophertiles_078.jpg" },
            { "status": 200, "size": "702", "path": "/004/gophertiles_079.jpg" },
            { "status": 200, "size": "725", "path": "/004/gophertiles_080.jpg" },
            { "status": 200, "size": "877", "path": "/004/gophertiles_081.jpg" },
            { "status": 200, "size": "743", "path": "/004/gophertiles_082.jpg" },
            { "status": 200, "size": "785", "path": "/004/gophertiles_083.jpg" },
            { "status": 200, "size": "690", "path": "/004/gophertiles_084.jpg" },
            { "status": 200, "size": "724", "path": "/004/gophertiles_085.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_086.jpg" },
            { "status": 200, "size": "883", "path": "/004/gophertiles_087.jpg" },
            { "status": 200, "size": "702", "path": "/004/gophertiles_088.jpg" },
            { "status": 200, "size": "693", "path": "/004/gophertiles_089.jpg" },
            { "status": 200, "size": "947", "path": "/004/gophertiles_090.jpg" },
            { "status": 200, "size": "959", "path": "/004/gophertiles_091.jpg" },
            { "status": 200, "size": "736", "path": "/004/gophertiles_092.jpg" },
            { "status": 200, "size": "806", "path": "/004/gophertiles_093.jpg" },
            { "status": 200, "size": "820", "path": "/004/gophertiles_094.jpg" },
            { "status": 200, "size": "918", "path": "/004/gophertiles_095.jpg" },
            { "status": 200, "size": "689", "path": "/004/gophertiles_096.jpg" },
            { "status": 200, "size": "796", "path": "/004/gophertiles_097.jpg" },
            { "status": 200, "size": "686", "path": "/004/gophertiles_098.jpg" },
            { "status": 200, "size": "698", "path": "/004/gophertiles_099.jpg" },
            { "status": 200, "size": "686", "path": "/004/gophertiles_100.jpg" },
            { "status": 200, "size": "686", "path": "/004/gophertiles_101.jpg" },
            { "status": 200, "size": "682", "path": "/004/gophertiles_102.jpg" },
            { "status": 200, "size": "703", "path": "/004/gophertiles_103.jpg" },
            { "status": 200, "size": "698", "path": "/004/gophertiles_104.jpg" },
            { "status": 200, "size": "702", "path": "/004/gophertiles_105.jpg" },
            { "status": 200, "size": "989", "path": "/004/gophertiles_106.jpg" },
            { "status": 200, "size": "720", "path": "/004/gophertiles_107.jpg" },
            { "status": 200, "size": "834", "path": "/004/gophertiles_108.jpg" },
            { "status": 200, "size": "756", "path": "/004/gophertiles_109.jpg" },
            { "status": 200, "size": "703", "path": "/004/gophertiles_110.jpg" },
            { "status": 200, "size": "815", "path": "/004/gophertiles_111.jpg" },
            { "status": 200, "size": "780", "path": "/004/gophertiles_112.jpg" },
            { "status": 200, "size": "992", "path": "/004/gophertiles_113.jpg" },
            { "status": 200, "size": "862", "path": "/004/gophertiles_114.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_115.jpg" },
            { "status": 200, "size": "756", "path": "/004/gophertiles_116.jpg" },
            { "status": 200, "size": "1012", "path": "/004/gophertiles_117.jpg" },
            { "status": 200, "size": "905", "path": "/004/gophertiles_118.jpg" },
            { "status": 200, "size": "808", "path": "/004/gophertiles_119.jpg" },
            { "status": 200, "size": "814", "path": "/004/gophertiles_120.jpg" },
            { "status": 200, "size": "832", "path": "/004/gophertiles_121.jpg" },
            { "status": 200, "size": "704", "path": "/004/gophertiles_122.jpg" },
            { "status": 200, "size": "741", "path": "/004/gophertiles_123.jpg" },
            { "status": 200, "size": "694", "path": "/004/gophertiles_124.jpg" },
            { "status": 200, "size": "950", "path": "/004/gophertiles_125.jpg" },
            { "status": 200, "size": "770", "path": "/004/gophertiles_126.jpg" },
            { "status": 200, "size": "749", "path": "/004/gophertiles_127.jpg" },
            { "status": 200, "size": "942", "path": "/004/gophertiles_128.jpg" },
            { "status": 200, "size": "997", "path": "/004/gophertiles_129.jpg" },
            { "status": 200, "size": "708", "path": "/004/gophertiles_130.jpg" },
            { "status": 200, "size": "821", "path": "/004/gophertiles_131.jpg" },
            { "status": 200, "size": "849", "path": "/004/gophertiles_132.jpg" },
            { "status": 200, "size": "715", "path": "/004/gophertiles_133.jpg" },
            { "status": 200, "size": "794", "path": "/004/gophertiles_134.jpg" },
            { "status": 200, "size": "869", "path": "/004/gophertiles_135.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_136.jpg" },
            { "status": 200, "size": "757", "path": "/004/gophertiles_137.jpg" },
            { "status": 200, "size": "991", "path": "/004/gophertiles_138.jpg" },
            { "status": 200, "size": "704", "path": "/004/gophertiles_139.jpg" },
            { "status": 200, "size": "707", "path": "/004/gophertiles_140.jpg" },
            { "status": 200, "size": "959", "path": "/004/gophertiles_141.jpg" },
            { "status": 200, "size": "691", "path": "/004/gophertiles_142.jpg" },
            { "status": 200, "size": "921", "path": "/004/gophertiles_143.jpg" },
            { "status": 200, "size": "932", "path": "/004/gophertiles_144.jpg" },
            { "status": 200, "size": "696", "path": "/004/gophertiles_145.jpg" },
            { "status": 200, "size": "711", "path": "/004/gophertiles_146.jpg" },
            { "status": 200, "size": "817", "path": "/004/gophertiles_147.jpg" },
            { "status": 200, "size": "966", "path": "/004/gophertiles_148.jpg" },
            { "status": 200, "size": "1002", "path": "/004/gophertiles_149.jpg" },
            { "status": 200, "size": "900", "path": "/004/gophertiles_150.jpg" },
            { "status": 200, "size": "724", "path": "/004/gophertiles_151.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_152.jpg" },
            { "status": 200, "size": "702", "path": "/004/gophertiles_153.jpg" },
            { "status": 200, "size": "971", "path": "/004/gophertiles_154.jpg" },
            { "status": 200, "size": "708", "path": "/004/gophertiles_155.jpg" },
            { "status": 200, "size": "699", "path": "/004/gophertiles_156.jpg" },
            { "status": 200, "size": "834", "path": "/004/gophertiles_157.jpg" },
            { "status": 200, "size": "702", "path": "/004/gophertiles_158.jpg" },
            { "status": 200, "size": "880", "path": "/004/gophertiles_159.jpg" },
            { "status": 200, "size": "701", "path": "/004/gophertiles_160.jpg" },
            { "status": 200, "size": "688", "path": "/004/gophertiles_161.jpg" },
            { "status": 200, "size": "853", "path": "/004/gophertiles_162.jpg" },
            { "status": 200, "size": "690", "path": "/004/gophertiles_163.jpg" },
            { "status": 200, "size": "759", "path": "/004/gophertiles_164.jpg" },
            { "status": 200, "size": "831", "path": "/004/gophertiles_165.jpg" },
            { "status": 200, "size": "732", "path": "/004/gophertiles_166.jpg" },
            { "status": 200, "size": "955", "path": "/004/gophertiles_167.jpg" },
            { "status": 200, "size": "1K", "path": "/004/gophertiles_168.jpg" },
            { "status": 200, "size": "969", "path": "/004/gophertiles_169.jpg" },
            { "status": 200, "size": "701", "path": "/004/gophertiles_170.jpg" },
            { "status": 200, "size": "755", "path": "/004/gophertiles_171.jpg" },
            { "status": 200, "size": "924", "path": "/004/gophertiles_172.jpg" },
            { "status": 200, "size": "958", "path": "/004/gophertiles_173.jpg" },
            { "status": 200, "size": "998", "path": "/004/gophertiles_174.jpg" },
            { "status": 200, "size": "702", "path": "/004/gophertiles_175.jpg" },
            { "status": 200, "size": "760", "path": "/004/gophertiles_176.jpg" },
            { "status": 200, "size": "732", "path": "/004/gophertiles_177.jpg" },
            { "status": 200, "size": "929", "path": "/004/gophertiles_178.jpg" },
            { "status": 200, "size": "712", "path": "/004/gophertiles_179.jpg" },
            { "status": 200, "size": "1013", "path": "/004/gophertiles_180.jpg" }
        ]            
            
    # page with js and css
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_006_04(self):
        url = TestEnv.mkurl("https", "test1", "/006.html")
        r = TestEnv.nghttp().assets(url)
        assert 0 == r["rv"]
        assert 3 == len(r["assets"])
        assert r["assets"] == [
            { "status": 200, "size": "543", "path": "/006.html" },
            { "status": 200, "size": "216", "path": "/006/006.css" },
            { "status": 200, "size": "839", "path": "/006/006.js" }
        ]

    # page with image, try different window size
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_006_05(self):
        url = TestEnv.mkurl("https", "test1", "/003.html")
        r = TestEnv.nghttp().assets(url, options=[ "--window-bits=24" ])
        assert 0 == r["rv"]
        assert 2 == len(r["assets"])
        assert r["assets"] == [
            { "status": 200, "size": "316", "path": "/003.html" },
            { "status": 200, "size": "88K", "path": "/003/003_img.jpg" }
        ]
Ejemplo n.º 6
0
    <Location /006-hints.html>
        H2PushResource "/006/006.css" critical
    </Location>
    <Location /006-nohints.html>
        Header add Link "</006/006.css>;rel=preload"
    </Location>
    """).end_vhost(
    ).install()
    assert TestEnv.apache_restart() == 0
        
def teardown_module(module):
    print("teardown_module: %s" % module.__name__)
    assert TestEnv.apache_stop() == 0

# The push tests depend on "nghttp"
@pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
class TestStore:

    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)
    
    # H2EarlyHints enabled in general, check that it works for H2PushResource
    def test_400_31(self):
        url = TestEnv.mkurl("https", "hints", "/006-hints.html")
        r = TestEnv.nghttp().get(url)
        assert 200 == r["response"]["status"]
        promises = r["streams"][r["response"]["id"]]["promises"]
        assert 1 == len(promises)
Ejemplo n.º 7
0
class TestStore:

    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)
    
    # check SSL environment variables from CGI script
    def test_003_01(self):
        url = TestEnv.mkurl("https", "cgi", "/hello.py")
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2.0" == r["response"]["json"]["protocol"]
        assert "on" == r["response"]["json"]["https"]
        assert "TLSv1.2" == r["response"]["json"]["ssl_protocol"]
        assert "on" == r["response"]["json"]["h2"]
        assert "off" == r["response"]["json"]["h2push"]

        r = TestEnv.curl_get(url, 5, [ "--http1.1" ])
        assert 200 == r["response"]["status"]
        assert "HTTP/1.1" == r["response"]["json"]["protocol"]
        assert "on" == r["response"]["json"]["https"]
        assert "TLSv1.2" == r["response"]["json"]["ssl_protocol"]
        assert "" == r["response"]["json"]["h2"]
        assert "" == r["response"]["json"]["h2push"]

    # retrieve a html file from the server and compare it to its source
    def test_003_02(self):
        with open(TestEnv.e2e_src( "htdocs/test1/index.html"), mode='rb') as file:
            src = file.read()

        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        assert src == r["response"]["body"]

        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5, [ "--http1.1" ])
        assert 200 == r["response"]["status"]
        assert "HTTP/1.1" == r["response"]["protocol"]
        assert src == r["response"]["body"]

    # retrieve chunked content from a cgi script
    def check_necho(self, n, text):
        url = TestEnv.mkurl("https", "cgi", "/necho.py")
        r = TestEnv.curl_get(url, 5, [ "-F", ("count=%d" % (n)), "-F", ("text=%s" % (text)) ])
        assert 200 == r["response"]["status"]
        exp = ""
        for i in range(n):
            exp += text + "\n"
        assert exp == r["response"]["body"]
    
    def test_003_10(self):
        self.check_necho(10, "0123456789")

    def test_003_11(self):
        self.check_necho(100, "0123456789")

    def test_003_12(self):
        self.check_necho(1000, "0123456789")

    def test_003_13(self):
        self.check_necho(10000, "0123456789")

    def test_003_14(self):
        self.check_necho(100000, "0123456789")

    # github issue #126
    def test_003_20(self):
        url = TestEnv.mkurl("https", "test1", "/006/")
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
 <head>
  <title>Index of /006</title>
 </head>
 <body>
<title>My Header Title</title>
<ul><li><a href="/"> Parent Directory</a></li>
<li><a href="006.css"> 006.css</a></li>
<li><a href="006.js"> 006.js</a></li>
<li><a href="header.html"> header.html</a></li>
</ul>
</body></html>
''' == r["response"]["body"]

    # github issue #133
    def clean_header(self, s):
        s = re.sub(r'\r\n', '\n', s, flags=re.MULTILINE)
        s = re.sub(r'^date:.*\n', '', s, flags=re.MULTILINE)
        s = re.sub(r'^server:.*\n', '', s, flags=re.MULTILINE)
        s = re.sub(r'^last-modified:.*\n', '', s, flags=re.MULTILINE)
        s = re.sub(r'^etag:.*\n', '', s, flags=re.MULTILINE)
        s = re.sub(r'^vary:.*\n', '', s, flags=re.MULTILINE)
        return re.sub(r'^accept-ranges:.*\n', '', s, flags=re.MULTILINE)
        
    def test_003_21(self):
        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5, [ "-I" ])
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        s = self.clean_header(r["response"]["body"])
        assert '''HTTP/2 200 
content-length: 2007
content-type: text/html

''' == s

        r = TestEnv.curl_get(url, 5, [ "-I", url ])
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        s = self.clean_header(r["response"]["body"])
        assert '''HTTP/2 200 
content-length: 2007
content-type: text/html

HTTP/2 200 
content-length: 2007
content-type: text/html

''' == s

    # test conditionals: if-modified-since
    @pytest.mark.parametrize("path", [
        "/004.html", "/proxy/004.html", "/h2proxy/004.html"
    ])
    def test_003_30(self, path):
        url = TestEnv.mkurl("https", "test1", path)
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        h = r["response"]["header"]
        assert "last-modified" in h
        lastmod = h["last-modified"]
        r = TestEnv.curl_get(url, 5, [ '-H', ("if-modified-since: %s" % lastmod) ])
        assert 304 == r["response"]["status"]

    # test conditionals: if-etag
    @pytest.mark.parametrize("path", [
        "/004.html", "/proxy/004.html", "/h2proxy/004.html"
    ])
    def test_003_31(self, path):
        url = TestEnv.mkurl("https", "test1", path)
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        h = r["response"]["header"]
        assert "etag" in h
        etag = h["etag"]
        r = TestEnv.curl_get(url, 5, [ '-H', ("if-none-match: %s" % etag) ])
        assert 304 == r["response"]["status"]

    # test various response body lengths to work correctly 
    def test_003_40(self):
        n = 1001
        while n <= 1025024:
            url = TestEnv.mkurl("https", "cgi", "/mnot164.py?count=%d&text=X" % (n))
            r = TestEnv.curl_get(url, 5)
            assert 200 == r["response"]["status"]
            assert "HTTP/2" == r["response"]["protocol"]
            assert n == len(r["response"]["body"])
            n *= 2

    # test various response body lengths to work correctly 
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    @pytest.mark.parametrize("n", [
        0, 1, 1291, 1292, 80000, 80123, 81087, 98452
    ])
    def test_003_41(self, n):
        url = TestEnv.mkurl("https", "cgi", "/mnot164.py?count=%d&text=X" % (n))
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        assert n == len(r["response"]["body"])
        
    # test ranges
    @pytest.mark.parametrize("path", [
        "/004.html", "/proxy/004.html", "/h2proxy/004.html"
    ])
    def test_003_50(self, path):
        # check that the resource supports ranges and we see its raw content-length
        url = TestEnv.mkurl("https", "test1", path)
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        h = r["response"]["header"]
        assert "accept-ranges" in h
        assert "bytes" == h["accept-ranges"]
        assert "content-length" in h
        clen = h["content-length"]
        # get the first 1024 bytes of the resource, 206 status, but content-length as original
        r = TestEnv.curl_get(url, 5, options=[ "-H", "range: bytes=0-1023"])
        assert 206 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        assert 1024 == len(r["response"]["body"])
        assert "content-length" in h
        assert clen == h["content-length"]
Ejemplo n.º 8
0
class TestStore:

    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)

    # accessing http://test1, will not try h2 and advertise h2 in the response
    def test_103_01(self):
        url = TestEnv.mkurl("http", "test1", "/index.html")
        r = TestEnv.curl_get(url)
        assert 0 == r["rv"]
        assert "response" in r
        assert "upgrade" in r["response"]["header"]
        assert "h2c" == r["response"]["header"]["upgrade"]
        
    # accessing http://noh2, will not advertise, because noh2 host does not have it enabled
    def test_103_02(self):
        url = TestEnv.mkurl("http", "noh2", "/index.html")
        r = TestEnv.curl_get(url)
        assert 0 == r["rv"]
        assert "response" in r
        assert not "upgrade" in r["response"]["header"]
        
    # accessing http://test2, will not advertise, because h2 has less preference than http/1.1
    def test_103_03(self):
        url = TestEnv.mkurl("http", "test2", "/index.html")
        r = TestEnv.curl_get(url)
        assert 0 == r["rv"]
        assert "response" in r
        assert not "upgrade" in r["response"]["header"]

    # accessing https://noh2, will not advertise, because noh2 host does not have it enabled
    def test_103_04(self):
        url = TestEnv.mkurl("https", "noh2", "/index.html")
        r = TestEnv.curl_get(url)
        assert 0 == r["rv"]
        assert "response" in r
        assert not "upgrade" in r["response"]["header"]

    # accessing https://test2, will not advertise, because h2 has less preference than http/1.1
    def test_103_05(self):
        url = TestEnv.mkurl("https", "test2", "/index.html")
        r = TestEnv.curl_get(url)
        assert 0 == r["rv"]
        assert "response" in r
        assert not "upgrade" in r["response"]["header"]
        
    # accessing https://test1, will advertise h2 in the response
    def test_103_06(self):
        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, options=[ "--http1.1" ])
        assert 0 == r["rv"]
        assert "response" in r
        assert "upgrade" in r["response"]["header"]
        assert "h2" == r["response"]["header"]["upgrade"]
        
    # accessing https://test3, will not send Upgrade since it is suppressed
    def test_103_07(self):
        url = TestEnv.mkurl("https", "test3", "/index.html")
        r = TestEnv.curl_get(url, options=[ "--http1.1" ])
        assert 0 == r["rv"]
        assert "response" in r
        assert not "upgrade" in r["response"]["header"]
        

    # upgrade to h2c for a request, where h2c is preferred
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_103_20(self):
        url = TestEnv.mkurl("http", "test1", "/index.html")
        r = TestEnv.nghttp().get(url, options=[ "-u" ])
        assert 200 == r["response"]["status"]

    # upgrade to h2c for a request where http/1.1 is preferred, but the clients upgrade
    # wish is honored nevertheless
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_103_21(self):
        url = TestEnv.mkurl("http", "test2", "/index.html")
        r = TestEnv.nghttp().get(url, options=[ "-u" ])
        assert 404 == r["response"]["status"]

    # ugrade to h2c on a host where h2c is not enabled will fail
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_103_22(self):
        url = TestEnv.mkurl("http", "noh2", "/index.html")
        r = TestEnv.nghttp().get(url, options=[ "-u" ])
        assert not "response" in r

    # ugrade to h2c on a host where h2c is preferred, but Upgrade is disabled
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_103_23(self):
        url = TestEnv.mkurl("http", "test1b", "/index.html")
        r = TestEnv.nghttp().get(url, options=[ "-u" ])
        assert not "response" in r

    # ugrade to h2c on a host where h2c is preferred, but Upgrade is disabled on the server,
    # but allowed for a specific location
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    def test_103_23(self):
        url = TestEnv.mkurl("http", "test1b", "/006.html")
        r = TestEnv.nghttp().get(url, options=[ "-u" ])
        assert 200 == r["response"]["status"]
Ejemplo n.º 9
0
class TestStore:
    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)

    # upload and GET again using curl, compare to original content
    def curl_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)
        r = TestEnv.curl_upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300

        r2 = TestEnv.curl_get(r["response"]["header"]["location"])
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]

    def test_004_01(self):
        self.curl_upload_and_verify("data-1k", ["--http1.1"])
        self.curl_upload_and_verify("data-1k", ["--http2"])

    def test_004_02(self):
        self.curl_upload_and_verify("data-10k", ["--http1.1"])
        self.curl_upload_and_verify("data-10k", ["--http2"])

    def test_004_03(self):
        self.curl_upload_and_verify("data-100k", ["--http1.1"])
        self.curl_upload_and_verify("data-100k", ["--http2"])

    def test_004_04(self):
        self.curl_upload_and_verify("data-1m", ["--http1.1"])
        self.curl_upload_and_verify("data-1m", ["--http2"])

    def test_004_05(self):
        self.curl_upload_and_verify(
            "data-1k", ["-v", "--http1.1", "-H", "Expect: 100-continue"])
        self.curl_upload_and_verify(
            "data-1k", ["-v", "--http2", "-H", "Expect: 100-continue"])

    @pytest.mark.skipif(True,
                        reason="python3 regresses in chunked inputs to cgi")
    def test_004_06(self):
        self.curl_upload_and_verify("data-1k",
                                    ["--http1.1", "-H", "Content-Length: "])
        self.curl_upload_and_verify("data-1k",
                                    ["--http2", "-H", "Content-Length: "])

    @pytest.mark.parametrize("name, value", [
        ("HTTP2", "on"),
        ("H2PUSH", "off"),
        ("H2_PUSHED", ""),
        ("H2_PUSHED_ON", ""),
        ("H2_STREAM_ID", "1"),
        ("H2_STREAM_TAG", r'\d+-1'),
    ])
    def test_004_07(self, name, value):
        url = TestEnv.mkurl("https", "cgi", "/env.py")
        r = TestEnv.curl_post_value(url, "name", name)
        assert r["rv"] == 0
        assert r["response"]["status"] == 200
        m = re.match("{0}=(.*)".format(name),
                     r["response"]["body"].decode('utf-8'))
        assert m
        assert re.match(value, m.group(1))

    # verify that we parse nghttp output correctly
    def check_nghttp_body(self, ref_input, nghttp_output):
        with open(TestEnv.e2e_src(os.path.join(TestEnv.GEN_DIR, ref_input)),
                  mode='rb') as f:
            refbody = f.read()
        with open(TestEnv.e2e_src(nghttp_output), mode='rb') as f:
            text = f.read()
        o = TestEnv.nghttp().parse_output(text)
        assert "response" in o
        assert "body" in o["response"]
        if refbody != o["response"]["body"]:
            with open(TestEnv.e2e_src(
                    os.path.join(TestEnv.GEN_DIR, '%s.parsed' % ref_input)),
                      mode='bw') as f:
                f.write(o["response"]["body"])
        assert len(refbody) == len(o["response"]["body"])
        assert refbody == o["response"]["body"]

    def test_004_20(self):
        self.check_nghttp_body('data-1k', 'data/nghttp-output-1k-1.txt')
        self.check_nghttp_body('data-10k', 'data/nghttp-output-10k-1.txt')
        self.check_nghttp_body('data-100k', 'data/nghttp-output-100k-1.txt')

    # POST some data using nghttp and see it echo'ed properly back
    def nghttp_post_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/echo.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300

        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r["response"]["body"]

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_21(self):
        self.nghttp_post_and_verify("data-1k", [])
        self.nghttp_post_and_verify("data-10k", [])
        self.nghttp_post_and_verify("data-100k", [])
        self.nghttp_post_and_verify("data-1m", [])

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_22(self):
        self.nghttp_post_and_verify("data-1k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-10k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-100k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-1m", ["--no-content-length"])

    # upload and GET again using nghttp, compare to original content
    def nghttp_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload_file(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300
        assert r["response"]["header"]["location"]

        r2 = TestEnv.nghttp().get(r["response"]["header"]["location"])
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_23(self):
        self.nghttp_upload_and_verify("data-1k", [])
        self.nghttp_upload_and_verify("data-10k", [])
        self.nghttp_upload_and_verify("data-100k", [])
        self.nghttp_upload_and_verify("data-1m", [])

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_24(self):
        self.nghttp_upload_and_verify("data-1k", ["--expect-continue"])
        self.nghttp_upload_and_verify("data-100k", ["--expect-continue"])

    @pytest.mark.skipif(True,
                        reason="python3 regresses in chunked inputs to cgi")
    def test_004_25(self):
        self.nghttp_upload_and_verify("data-1k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-10k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-100k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-1m", ["--no-content-length"])

    def test_004_30(self):
        # issue: #203
        resource = "data-1k"
        full_length = 1000
        chunk = 200
        self.curl_upload_and_verify(resource, ["-v", "--http2"])
        logfile = os.path.join(TestEnv.HTTPD_LOGS_DIR, "test_004_30")
        if os.path.isfile(logfile):
            os.remove(logfile)
        HttpdConf().add_line("""
LogFormat "{ \\"request\\": \\"%r\\", \\"status\\": %>s, \\"bytes_resp_B\\": %B, \\"bytes_tx_O\\": %O, \\"bytes_rx_I\\": %I, \\"bytes_rx_tx_S\\": %S }" issue_203
CustomLog logs/test_004_30 issue_203
        """).add_vhost_cgi().install()
        assert TestEnv.apache_restart() == 0
        url = TestEnv.mkurl("https", "cgi", "/files/{0}".format(resource))
        r = TestEnv.curl_get(url, 5, ["--http2"])
        assert 200 == r["response"]["status"]
        r = TestEnv.curl_get(
            url, 5,
            ["--http1.1", "-H", "Range: bytes=0-{0}".format(chunk - 1)])
        assert 206 == r["response"]["status"]
        assert chunk == len(r["response"]["body"].decode('utf-8'))
        r = TestEnv.curl_get(
            url, 5, ["--http2", "-H", "Range: bytes=0-{0}".format(chunk - 1)])
        assert 206 == r["response"]["status"]
        assert chunk == len(r["response"]["body"].decode('utf-8'))
        # now check what response lengths have actually been reported
        lines = open(logfile).readlines()
        log_h2_full = json.loads(lines[-3])
        log_h1 = json.loads(lines[-2])
        log_h2 = json.loads(lines[-1])
        assert log_h2_full['bytes_rx_I'] > 0
        assert log_h2_full['bytes_resp_B'] == full_length
        assert log_h2_full['bytes_tx_O'] > full_length
        assert log_h1['bytes_rx_I'] > 0  # input bytes recieved
        assert log_h1['bytes_resp_B'] == chunk  # response bytes sent (payload)
        assert log_h1['bytes_tx_O'] > chunk  # output bytes sent
        assert log_h2['bytes_rx_I'] > 0
        assert log_h2['bytes_resp_B'] == chunk
        assert log_h2['bytes_tx_O'] > chunk

    def test_004_40(self):
        # echo content using h2test_module "echo" handler
        def post_and_verify(fname, options=None):
            url = TestEnv.mkurl("https", "cgi", "/h2test/echo")
            fpath = os.path.join(TestEnv.GEN_DIR, fname)
            r = TestEnv.curl_upload(url, fpath, options=options)
            assert r["rv"] == 0
            assert r["response"]["status"] >= 200 and r["response"][
                "status"] < 300

            ct = r["response"]["header"]["content-type"]
            mail_hd = "Content-Type: " + ct + "\r\nMIME-Version: 1.0\r\n\r\n"
            mime_msg = mail_hd.encode() + r["response"]["body"]
            # this MIME API is from hell
            body = email.parser.BytesParser().parsebytes(mime_msg)
            assert body
            assert body.is_multipart()
            filepart = None
            for part in body.walk():
                if fname == part.get_filename():
                    filepart = part
            assert filepart
            with open(TestEnv.e2e_src(fpath), mode='rb') as file:
                src = file.read()
            assert src == filepart.get_payload(decode=True)

        post_and_verify("data-1k", [])