TestNghttp.py (mod_http2-1.15.16) | : | TestNghttp.py (mod_http2-1.15.17) | ||
---|---|---|---|---|
skipping to change at line 56 | skipping to change at line 56 | |||
"body" : b'' | "body" : b'' | |||
}, | }, | |||
"paddings" : [], | "paddings" : [], | |||
"promises" : [] | "promises" : [] | |||
} | } | |||
return streams[sid] if sid in streams else None | return streams[sid] if sid in streams else None | |||
def run( self, urls, timeout, options ) : | def run( self, urls, timeout, options ) : | |||
return self._baserun(urls, timeout, options) | return self._baserun(urls, timeout, options) | |||
def _baserun( self, url, timeout, options ) : | def complete_args(self, url, timeout, options: [str]) -> [str]: | |||
if not isinstance(url, list): | if not isinstance(url, list): | |||
url = [ url ] | url = [url] | |||
u = urlparse(url[0]) | u = urlparse(url[0]) | |||
args = [ self.NGHTTP ] | args = [self.NGHTTP] | |||
if self.CONNECT_ADDR: | if self.CONNECT_ADDR: | |||
connect_host = self.CONNECT_ADDR | connect_host = self.CONNECT_ADDR | |||
args.append("--header=host: %s:%s" % (u.hostname, u.port)) | args.append("--header=host: %s:%s" % (u.hostname, u.port)) | |||
else: | else: | |||
connect_host = u.hostname | connect_host = u.hostname | |||
if options: | if options: | |||
args.extend(options) | args.extend(options) | |||
for xurl in url: | for xurl in url: | |||
xu = urlparse(xurl) | xu = urlparse(xurl) | |||
nurl = "%s://%s:%s/%s" % (u.scheme, connect_host, xu.port, xu.path) | nurl = "%s://%s:%s/%s" % (u.scheme, connect_host, xu.port, xu.path) | |||
if xu.query: | if xu.query: | |||
nurl = "%s?%s" % (nurl, xu.query) | nurl = "%s?%s" % (nurl, xu.query) | |||
args.append( nurl ) | args.append(nurl) | |||
return args | ||||
return self._run( args ) | def _baserun(self, url, timeout, options): | |||
return self._run(self.complete_args(url, timeout, options)) | ||||
def parse_output( self, text ): | def parse_output(self, btext): | |||
# getting meta data and response body out of nghttp's output | # getting meta data and response body out of nghttp's output | |||
# is a bit tricky. Without '-v' we just get the body. With '-v' meta | # is a bit tricky. Without '-v' we just get the body. With '-v' meta | |||
# data and timings in both directions are listed. | # data and timings in both directions are listed. | |||
# We rely on response :status: to be unique and on | # We rely on response :status: to be unique and on | |||
# response body not starting with space. | # response body not starting with space. | |||
# Something not good enough for general purpose, but for these tests. | # Something not good enough for general purpose, but for these tests. | |||
output = {} | output = {} | |||
body = b'' | body = '' | |||
stream = 0 | stream = 0 | |||
streams = {} | streams = {} | |||
skip_indents = True | skip_indents = True | |||
# take the binary program output and chunk into lines. nghttp mixes text | # chunk output into lines. nghttp mixes text | |||
# meta output with bytes from the response body. | # meta output with bytes from the response body. | |||
offset = 0 | lines = [l.decode() for l in btext.split(b'\n')] | |||
lines = [] | ||||
while True: | ||||
index = text.find(b'\n', offset) | ||||
if index < 0: break | ||||
lines.append(text[offset:(index+1)]) | ||||
offset = index + 1 | ||||
if offset < len(text): | ||||
lines.append(text[offset:]) | ||||
for lidx, l in enumerate(lines): | for lidx, l in enumerate(lines): | |||
m = re.match(b'\\[.*\\] recv \\(stream_id=(\\d+)\\) (\\S+): (\\S*)', | if len(l) == 0: | |||
l) | body += '\n' | |||
continue | ||||
m = re.match(r'\[.*\] recv \(stream_id=(\d+)\) (\S+): (\S*)', l) | ||||
if m: | if m: | |||
s = self.get_stream( streams, m.group(1) ) | s = self.get_stream( streams, m.group(1) ) | |||
hname = m.group(2).decode('utf-8') | hname = m.group(2) | |||
hval = m.group(3).decode('utf-8') | hval = m.group(3) | |||
print("stream %d header %s: %s" % (s["id"], hname, hval)) | print("stream %d header %s: %s" % (s["id"], hname, hval)) | |||
header = s["header"] | header = s["header"] | |||
if hname in header: | if hname in header: | |||
header[hname] += ", %s" % hval | header[hname] += ", %s" % hval | |||
else: | else: | |||
header[hname] = hval | header[hname] = hval | |||
body = b'' | body = '' | |||
continue | continue | |||
m = re.match(b'\\[.*\\] recv HEADERS frame <.* stream_id=(\\d+)>', l ) | m = re.match(r'\[.*\] recv HEADERS frame <.* stream_id=(\d+)>', l) | |||
if m: | if m: | |||
s = self.get_stream( streams, m.group(1) ) | s = self.get_stream( streams, m.group(1) ) | |||
if s: | if s: | |||
print("stream %d: recv %d header" % (s["id"], len(s["header" ]))) | print("stream %d: recv %d header" % (s["id"], len(s["header" ]))) | |||
response = s["response"] | response = s["response"] | |||
hkey = "header" | hkey = "header" | |||
if "header" in response: | if "header" in response: | |||
h = response["header"] | h = response["header"] | |||
if ":status" in h and int(h[":status"]) >= 200: | if ":status" in h and int(h[":status"]) >= 200: | |||
hkey = "trailer" | hkey = "trailer" | |||
else: | else: | |||
prev = { | prev = { | |||
"header" : h | "header" : h | |||
} | } | |||
if "previous" in response: | if "previous" in response: | |||
prev["previous"] = response["previous"] | prev["previous"] = response["previous"] | |||
response["previous"] = prev | response["previous"] = prev | |||
response[hkey] = s["header"] | response[hkey] = s["header"] | |||
s["header"] = {} | s["header"] = {} | |||
body = b'' | body = '' | |||
continue | continue | |||
m = re.match(b'(.*)\\[.*\\] recv DATA frame <length=(\\d+), .*stream _id=(\\d+)>', l) | m = re.match(r'(.*)\[.*\] recv DATA frame <length=(\d+), .*stream_id =(\d+)>', l) | |||
if m: | if m: | |||
s = self.get_stream( streams, m.group(3) ) | s = self.get_stream( streams, m.group(3) ) | |||
body += m.group(1) | body += m.group(1) | |||
blen = int(m.group(2)) | blen = int(m.group(2)) | |||
if s: | if s: | |||
print("stream %d: %d DATA bytes added" % (s["id"], blen)) | print("stream %d: %d DATA bytes added" % (s["id"], blen)) | |||
padlen = 0 | padlen = 0 | |||
if len(lines) > lidx + 2: | if len(lines) > lidx + 2: | |||
mpad = re.match(b' +\(padlen=(\d+)\)', lines[lidx+2]) | mpad = re.match(r' +\(padlen=(\d+)\)', lines[lidx+2]) | |||
if mpad: | if mpad: | |||
padlen = int(mpad.group(1)) | padlen = int(mpad.group(1)) | |||
s["paddings"].append(padlen) | s["paddings"].append(padlen) | |||
blen -= padlen | blen -= padlen | |||
s["response"]["body"] += body[-blen:] | s["response"]["body"] += body[-blen:].encode() | |||
body = b'' | body = '' | |||
skip_indents = True | skip_indents = True | |||
continue | continue | |||
m = re.match(b'\\[.*\\] recv PUSH_PROMISE frame <.* stream_id=(\\d+) >', l) | m = re.match(r'\[.*\] recv PUSH_PROMISE frame <.* stream_id=(\d+)>', l) | |||
if m: | if m: | |||
s = self.get_stream( streams, m.group(1) ) | s = self.get_stream( streams, m.group(1) ) | |||
if s: | if s: | |||
# headers we have are request headers for the PUSHed stream | # headers we have are request headers for the PUSHed stream | |||
# these have been received on the originating stream, the pr omised | # these have been received on the originating stream, the pr omised | |||
# stream id it mentioned in the following lines | # stream id it mentioned in the following lines | |||
print("stream %d: %d PUSH_PROMISE header" % (s["id"], len(s[ "header"]))) | print("stream %d: %d PUSH_PROMISE header" % (s["id"], len(s[ "header"]))) | |||
if len(lines) > lidx+2: | if len(lines) > lidx+2: | |||
m2 = re.match(b'\s+\(.*promised_stream_id=(\d+)\)', line s[lidx+2]) | m2 = re.match(r'\s+\(.*promised_stream_id=(\d+)\)', line s[lidx+2]) | |||
if m2: | if m2: | |||
s2 = self.get_stream( streams, m2.group(1) ) | s2 = self.get_stream( streams, m2.group(1) ) | |||
s2["request"]["header"] = s["header"] | s2["request"]["header"] = s["header"] | |||
s["promises"].append(s2) | s["promises"].append(s2) | |||
s["header"] = {} | s["header"] = {} | |||
continue | continue | |||
m = re.match(b'(.*)\\[.*\\] recv (\\S+) frame <length=(\\d+), .*stre am_id=(\\d+)>', l) | m = re.match(r'(.*)\[.*\] recv (\S+) frame <length=(\d+), .*stream_i d=(\d+)>', l) | |||
if m: | if m: | |||
print("recv frame %s on stream %s" % (m.group(2), m.group(4))) | print("recv frame %s on stream %s" % (m.group(2), m.group(4))) | |||
body += m.group(1) | body += m.group(1) | |||
skip_indents = True | skip_indents = True | |||
continue | continue | |||
m = re.match(b'(.*)\\[.*\\] send (\\S+) frame <length=(\\d+), .*stre am_id=(\\d+)>', l) | m = re.match(r'(.*)\[.*\] send (\S+) frame <length=(\d+), .*stream_i d=(\d+)>', l) | |||
if m: | if m: | |||
print("send frame %s on stream %s" % (m.group(2), m.group(4))) | print("send frame %s on stream %s" % (m.group(2), m.group(4))) | |||
body += m.group(1) | body += m.group(1) | |||
skip_indents = True | skip_indents = True | |||
continue | continue | |||
if skip_indents and l.startswith(b' '): | if skip_indents and l.startswith(' '): | |||
continue | continue | |||
if b'[' != l[0]: | if '[' != l[0]: | |||
skip_indents = None | skip_indents = None | |||
body += l | body += l + '\n' | |||
# the main request is done on the lowest odd numbered id | # the main request is done on the lowest odd numbered id | |||
main_stream = 99999999999 | main_stream = 99999999999 | |||
for sid in streams: | for sid in streams: | |||
s = streams[sid] | s = streams[sid] | |||
if ":status" in s["response"]["header"]: | if ":status" in s["response"]["header"]: | |||
s["response"]["status"] = int(s["response"]["header"][":status"] ) | s["response"]["status"] = int(s["response"]["header"][":status"] ) | |||
if (sid % 2) == 1 and sid < main_stream: | if (sid % 2) == 1 and sid < main_stream: | |||
main_stream = sid | main_stream = sid | |||
End of changes. 26 change blocks. | ||||
39 lines changed or deleted | 31 lines changed or added |