diff --git a/src/hyperx/client.nim b/src/hyperx/client.nim index 13cd0c9..b22a1f6 100644 --- a/src/hyperx/client.nim +++ b/src/hyperx/client.nim @@ -14,6 +14,7 @@ when defined(hyperxTest): const preface = "PRI * HTTP/2.0\r\L\r\LSM\r\L\r\L" statusLineLen = ":status: xxx\r\n".len + userAgent = "Nim - HyperX" # https://httpwg.org/specs/rfc9113.html#SettingValues stgHeaderTableSize = 4096'u32 stgMaxConcurrentStreams = uint32.high @@ -753,16 +754,17 @@ proc request(client: ClientContext, req: Request): Future[Response] {.async.} = proc get*( client: ClientContext, path: string, - accept = "*" + accept = "*/*" ): Future[Response] {.async.} = var req = newRequest() client.addHeader(req, ":method", "GET") client.addHeader(req, ":scheme", "https") client.addHeader(req, ":path", path) client.addHeader(req, ":authority", client.hostname) + client.addHeader(req, "user-agent", userAgent) + # XXX google closes the stream with protocol error #client.addHeader(req, "host", client.hostname) - #client.addHeader(req, "accept", accept) - #client.addHeader(req, "user-agent", "Nim - HyperX") + client.addHeader(req, "accept", accept) result = await client.request req proc post*( @@ -777,10 +779,10 @@ proc post*( client.addHeader(req, ":scheme", "https") client.addHeader(req, ":path", path) client.addHeader(req, ":authority", client.hostname) + client.addHeader(req, "user-agent", userAgent) client.addHeader(req, "host", client.hostname) client.addHeader(req, "content-type", contentType) client.addHeader(req, "content-length", $data.len) - client.addHeader(req, "user-agent", "Nim - HyperX") req.dataFrm = newFrame() req.dataFrm.add data result = await client.request req diff --git a/src/hyperx/frame.nim b/src/hyperx/frame.nim index dcb39e5..b88ad9e 100644 --- a/src/hyperx/frame.nim +++ b/src/hyperx/frame.nim @@ -339,6 +339,13 @@ func debugPayload*(frm: Frame): string {.raises: [].} = var i = frmHeaderSize result.add "===Payload===" case frm.typ + of frmtRstStream: + var errCode = 0.uint + errCode += frm.s[i+0].uint shl 24 + errCode += frm.s[i+1].uint shl 16 + errCode += frm.s[i+2].uint shl 8 + errCode += frm.s[i+3].uint + result.add fmt("\nError Code {$errCode}") of frmtGoAway: var lastStreamId = 0.uint lastStreamId += frm.s[i+0].uint shl 24 diff --git a/src/hyperx/untestable.nim b/src/hyperx/untestable.nim index 9b17821..a648d3d 100644 --- a/src/hyperx/untestable.nim +++ b/src/hyperx/untestable.nim @@ -13,24 +13,34 @@ when isMainModule: proc main() {.async.} = var client = newClient("www.google.com") withConnection(client): + echo "G" let r = await client.get("/") doAssert ":status: 200" in r.headers doAssert "doctype" in r.text await sleepAsync 2000 - echo "GET" waitFor main() - proc mainPost() {.async.} = + proc mainReqBin() {.async.} = var client = newClient("reqbin.com") withConnection(client): - let r = await client.post( - "/echo/post/form", - "foo=bar&baz=qux".toBytes - ) - doAssert ":status: 200" in r.headers - doAssert "Success" in r.text + block: + echo "GET" + let r = await client.get( + "/echo/get/json", + accept = "application/json" + ) + doAssert ":status: 200" in r.headers + doAssert """{"success":"true"}""" in r.text + block: + echo "POST" + let r = await client.post( + "/echo/post/json", + """{"foo": "bar"}""".toBytes, + contentType = "application/json" + ) + doAssert ":status: 200" in r.headers + doAssert """{"success":"true"}""" in r.text await sleepAsync 2000 - echo "POST" - waitFor mainPost() + waitFor mainReqBin() echo "ok" diff --git a/tests/testclient.nim b/tests/testclient.nim index 78c5dc4..63f4e8f 100644 --- a/tests/testclient.nim +++ b/tests/testclient.nim @@ -9,6 +9,9 @@ import ../src/hyperx/testutils import ../src/hyperx/frame import ../src/hyperx/errors +const + userAgent = "Nim - HyperX" + func toBytes(s: string): seq[byte] = result = newSeq[byte]() for c in s: @@ -81,7 +84,9 @@ testAsync "simple request": ":method: GET\r\L" & ":scheme: https\r\L" & ":path: /\r\L" & - ":authority: foo.bar\r\L" + ":authority: foo.bar\r\L" & + "user-agent: " & userAgent & "\r\L" & + "accept: */*\r\L" testAsync "multiple requests": var tc = newTestClient("foo.bar") @@ -102,14 +107,18 @@ testAsync "multiple requests": ":method: GET\r\L" & ":scheme: https\r\L" & ":path: /1\r\L" & - ":authority: foo.bar\r\L" + ":authority: foo.bar\r\L" & + "user-agent: " & userAgent & "\r\L" & + "accept: */*\r\L" doAssert reqs[2].frm.sid.int == 3 doAssert reqs[2].frm.typ == frmtHeaders doAssert reqs[2].payload == ":method: GET\r\L" & ":scheme: https\r\L" & ":path: /2\r\L" & - ":authority: foo.bar\r\L" + ":authority: foo.bar\r\L" & + "user-agent: " & userAgent & "\r\L" & + "accept: */*\r\L" testAsync "response with bad header compression": proc replyBadHeaders(tc: TestClientContext) {.async.} = @@ -250,8 +259,10 @@ testAsync "header table is populated": tc.reply(":status: 200\r\nfoo: foo\r\n", "bar") ) let reqs = tc.sent() - doAssert tc.headersDec.len == 2 + doAssert tc.headersDec.len == 4 doAssert $tc.headersDec == + "accept: */*\r\L" & + "user-agent: " & userAgent & "\r\L" & ":authority: foo.bar\r\L" & ":path: /foo\r\L" doAssert reqs[1].frm.sid.int == 1 @@ -260,7 +271,9 @@ testAsync "header table is populated": ":method: GET\r\L" & ":scheme: https\r\L" & ":path: /foo\r\L" & - ":authority: foo.bar\r\L" + ":authority: foo.bar\r\L" & + "user-agent: " & userAgent & "\r\L" & + "accept: */*\r\L" testAsync "header table size setting is applied": proc recvTableSizeSetting(tc: TestClientContext, tableSize: uint32) {.async.} = @@ -287,7 +300,9 @@ testAsync "header table size setting is applied": ":method: GET\r\L" & ":scheme: https\r\L" & ":path: /foo\r\L" & - ":authority: foo.bar\r\L" + ":authority: foo.bar\r\L" & + "user-agent: " & userAgent & "\r\L" & + "accept: */*\r\L" # XXX reqs[2] window size update # XXX reqs[3] ack window size update doAssert reqs[4].frm.sid.int == 3 @@ -296,4 +311,6 @@ testAsync "header table size setting is applied": ":method: GET\r\L" & ":scheme: https\r\L" & ":path: /bar\r\L" & - ":authority: foo.bar\r\L" + ":authority: foo.bar\r\L" & + "user-agent: " & userAgent & "\r\L" & + "accept: */*\r\L"