Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions tests/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ pyflakes = "*"
autest = "==1.10.2"

traffic-replay = "*" # this should install TRLib, MicroServer, MicroDNS, Traffic-Replay
hyper = "*"
h2 = "*"
dnslib = "*"
# These are likely to be available via yum/dnf or apt-get
requests = "*"
gunicorn = "*"
httpbin = "*"
psutil = "*"

# Keep init.cli.ext updated with this required microserver version.
Expand All @@ -43,11 +42,6 @@ microserver = ">=1.0.6"
jsonschema = "*"
python-jose = "*"

# The latest version of Werkzeug (2.1.0) breaks httpbin because it removes
# deprecated function `BaseResponse` that httpbin directly or indirectly
# depends upon. Pinning Wekrzeug for now until httpbin or its dependencies is
# updated for the changed API.
Werkzeug = "==2.0.3"
flask = "==2.1.3"

[requires]
Expand Down
17 changes: 8 additions & 9 deletions tests/gold_tests/autest-site/httpbin.test.ext
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,23 @@
from ports import get_port


def MakeHttpBinServer(self, name, port=False, ip=False, delay=False, public_ip=False, ssl=False, options={}):
def MakeHttpBinServer(self, name, ip='127.0.0.1', port=None,
options={}) -> 'Process':
data_dir = os.path.join(self.RunDirectory, name)
# create Process
p = self.Processes.Process(name)
if (port == False):
if port is None:
port = get_port(p, "Port")
if (ip == False):
ip = '127.0.0.1'
if (delay == False):
delay = 0

self._RootRunable.SkipUnless(
Condition.HasProgram("gunicorn", "gunicorn needs be installed with httpbin package for this extension to run")
Condition.HasProgram(
"go-httpbin",
"go-httpbin needs be installed and in PATH for this extension to run")
)

command = "gunicorn -b {0}:{1} httpbin:app".format(ip, port)
command = f"go-httpbin -host {ip} -port {port} "
for flag, value in options.items():
command += " {} {}".format(flag, value)
command += f"{flag} {value} "

# create process
p.Command = command
Expand Down
6 changes: 3 additions & 3 deletions tests/gold_tests/cache/background_fill.test.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def __testCase0(self):
tr.Processes.Default.Command = f"""
curl -X PURGE --http1.1 -vs http://127.0.0.1:{self.ts.Variables.port}/drip?duration=4;
timeout 2 curl --http1.1 -vs http://127.0.0.1:{self.ts.Variables.port}/drip?duration=4;
sleep 2;
sleep 4;
curl --http1.1 -vs http://127.0.0.1:{self.ts.Variables.port}/drip?duration=4
"""
tr.Processes.Default.ReturnCode = 0
Expand All @@ -108,7 +108,7 @@ def __testCase1(self):
tr.Processes.Default.Command = f"""
curl -X PURGE --http1.1 -vsk https://127.0.0.1:{self.ts.Variables.ssl_port}/drip?duration=4;
timeout 2 curl --http1.1 -vsk https://127.0.0.1:{self.ts.Variables.ssl_port}/drip?duration=4;
sleep 2;
sleep 4;
curl --http1.1 -vsk https://127.0.0.1:{self.ts.Variables.ssl_port}/drip?duration=4
"""
tr.Processes.Default.ReturnCode = 0
Expand All @@ -124,7 +124,7 @@ def __testCase2(self):
tr.Processes.Default.Command = f"""
curl -X PURGE --http2 -vsk https://127.0.0.1:{self.ts.Variables.ssl_port}/drip?duration=4;
timeout 2 curl --http2 -vsk https://127.0.0.1:{self.ts.Variables.ssl_port}/drip?duration=4;
sleep 2;
sleep 4;
curl --http2 -vsk https://127.0.0.1:{self.ts.Variables.ssl_port}/drip?duration=4
"""
tr.Processes.Default.ReturnCode = 0
Expand Down
1 change: 0 additions & 1 deletion tests/gold_tests/connect/gold/connect_0_stderr.gold
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,3 @@
``
<``
``
* Closing connection 0
19 changes: 9 additions & 10 deletions tests/gold_tests/h2/gold/bigfile.gold
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
Content length = 191414

Body length = 191414

``
content-length: 191414
``
Response fully received: 191414 bytes
Content success

Content length = 191414

Body length = 191414

``
content-length: 191414
``
Response fully received: 191414 bytes
Content success

``
8 changes: 5 additions & 3 deletions tests/gold_tests/h2/gold/chunked.gold
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
HTTP/2 200
date: {}
server: ATS/{}
Response received:
:status: 200
server: ``
date: ``
age: ``
``
microserverapachetrafficserver
``
7 changes: 3 additions & 4 deletions tests/gold_tests/h2/gold/httpbin_0_stderr.gold
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
> Accept: */*
``
< HTTP/2 200 ``
< server: ATS/``
< date: ``
< content-type: application/json
``
< content-type: application/json; encoding=utf-8
< date: ``
< content-length: ``
< age: ``
< via: ``ApacheTrafficServer/``
``
< server: ATS/``
7 changes: 3 additions & 4 deletions tests/gold_tests/h2/gold/httpbin_1_stderr.gold
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
> Accept: */*
``
< HTTP/2 200 ``
< server: ATS/``
< date: ``
< content-type: application/octet-stream
``
< content-length: 0``
< content-length: 0
< date: ``
< age: ``
< via: ``ApacheTrafficServer/``
< server: ATS/``
``
1 change: 1 addition & 0 deletions tests/gold_tests/h2/gold/httpbin_1_stdout.gold
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``
6 changes: 3 additions & 3 deletions tests/gold_tests/h2/gold/httpbin_2_stderr.gold
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
> Accept: */*
``
< HTTP/2 200 ``
< server: ATS/``
< date: ``
< content-type: application/octet-stream
``
< content-type: application/octet-stream
< date: ``
< age: ``
< via: ``ApacheTrafficServer/``
< server: ATS/``
``
2 changes: 1 addition & 1 deletion tests/gold_tests/h2/gold/httpbin_2_stdout.gold
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b99e42637ce13160c48e9b2bc9ed2d4dd175bc6cf44c7814b01e4853f262b284 -
7a884625d64511d986423b361d75a5d037d7fa62b9ecf0959b93adda1afe07ef -
4 changes: 3 additions & 1 deletion tests/gold_tests/h2/gold/httpbin_3_stdout.gold
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
``
"form": {
"key": "value"
"key": [
"value"
]
},
``
}
12 changes: 8 additions & 4 deletions tests/gold_tests/h2/gold/remap-200.gold
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
HTTP/2 200
date: {}
server: ATS/{}

Response received:
:status: 200
server: ``
date: ``
age: ``
Response fully received: 0 bytes
Content success
``
132 changes: 109 additions & 23 deletions tests/gold_tests/h2/h2active_timeout.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3

'''
An h2 client built to trigger active timeout.
'''
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
Expand All @@ -18,45 +19,130 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from hyper import HTTPConnection
import hyper
import socket
import ssl

import h2.connection
import h2.events

import argparse
import time


def makerequest(port, active_timeout):
hyper.tls._context = hyper.tls.init_context()
hyper.tls._context.check_hostname = False
hyper.tls._context.verify_mode = hyper.compat.ssl.CERT_NONE
def get_socket(port: int) -> socket.socket:
"""Create a TLS-wrapped socket.

:param port: The port to connect to.

:returns: A TLS-wrapped socket.
"""

SERVER_NAME = 'localhost'
SERVER_PORT = port

# generic socket and ssl configuration
socket.setdefaulttimeout(15)

# Configure an ssl client side context which will not check the server's certificate.
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ctx.set_alpn_protocols(['h2'])

# open a socket to the server and initiate TLS/SSL
tls_socket = socket.create_connection((SERVER_NAME, SERVER_PORT))
tls_socket = ctx.wrap_socket(tls_socket, server_hostname=SERVER_NAME)
return tls_socket


def makerequest(port: int, path: str, delay: int) -> None:
"""Establish an HTTP/2 connection and send a request.

:param port: The port to connect to.
:param path: The path to request.
:param delay: The delay to wait between sending requests in a stream.
"""

tls_socket = get_socket(port)

conn = HTTPConnection('localhost:{0}'.format(port), secure=True)
h2_connection = h2.connection.H2Connection()
h2_connection.initiate_connection()
tls_socket.sendall(h2_connection.data_to_send())

headers = [
(':method', 'GET'),
(':path', path),
(':authority', 'localhost'),
(':scheme', 'https'),
]

h2_connection.send_headers(1, headers, end_stream=True)
tls_socket.sendall(h2_connection.data_to_send())

# delay, triggering ATS timeout.
time.sleep(delay)

# The following should fail due to the timeout.
try:
# delay after sending the first request
# so the H2 session active timeout triggers
# Then the next request should fail
req_id = conn.request('GET', '/')
time.sleep(active_timeout)
response = conn.get_response(req_id)
req_id = conn.request('GET', '/')
response = conn.get_response(req_id)
except Exception:
print('CONNECTION_TIMEOUT')
return
# Send a second request.
h2_connection.send_headers(3, headers, end_stream=True)
tls_socket.sendall(h2_connection.data_to_send())

response_stream_ended = False
body = b''
while not response_stream_ended:
# read raw data from the socket
data = tls_socket.recv(65536 * 1024)
if not data:
break

# feed raw data into h2, and process resulting events
events = h2_connection.receive_data(data)
for event in events:
if isinstance(event, h2.events.ResponseReceived):
# response headers received
print("Response received:")
for header in event.headers:
print(f' {header[0].decode()}: {header[1].decode()}')
if isinstance(event, h2.events.DataReceived):
# update flow control so the server doesn't starve us
h2_connection.acknowledge_received_data(event.flow_controlled_length, event.stream_id)
# more response body data received
body += event.data
if isinstance(event, h2.events.StreamEnded):
# response body completed, let's exit the loop
response_stream_ended = True
break
# send any pending data to the server
tls_socket.sendall(h2_connection.data_to_send())

print('NO_TIMEOUT')
print(f"Response fully received: {len(body)} bytes")

body_str = body.decode('utf-8')

# tell the server we are closing the h2 connection
h2_connection.close_connection()
tls_socket.sendall(h2_connection.data_to_send())

# close the socket
tls_socket.close()
except Exception:
print("CONNECTION_TIMEOUT")


def main():
parser = argparse.ArgumentParser()
parser.add_argument("--port", "-p",
parser.add_argument("port",
type=int,
help="Port to use")
parser.add_argument("--delay", "-d",
parser.add_argument("path",
help="The path to request")
parser.add_argument("delay",
type=int,
help="Time to delay in seconds")
help="The number of seconds to delay betwen requests in a stream")
args = parser.parse_args()
makerequest(args.port, args.delay)

makerequest(args.port, args.path, args.delay)


if __name__ == '__main__':
Expand Down
Loading