http-client: content-type override, split header values
Add a "response-content-type-override" field to the resolve step to override body parsing behavior. Send each reponse header as a seperate message rather than concatenated by the Nim HTTP client library.
This commit is contained in:
parent
f6879a906d
commit
0758f0996b
|
@ -302,7 +302,7 @@ $client-resolver ? <accepted ?client> $client [
|
|||
|
||||
# Pass the resolver dataspace to the client.
|
||||
? <service-object <daemon http-client> ?cap> [
|
||||
$cap <resolve <http-client {}> $client-resolver>
|
||||
$cap <resolve <http-client { response-content-type-override: "" }> $client-resolver>
|
||||
]
|
||||
|
||||
<require-service <daemon http-client>>
|
||||
|
|
10
config.prs
10
config.prs
|
@ -24,7 +24,15 @@ UnixAddress = <unix @path string>.
|
|||
|
||||
SocketAddress = TcpAddress / UnixAddress .
|
||||
|
||||
HttpClientStep = <http-client { }>.
|
||||
HttpClientStep = <http-client @detail HttpClientStepDetail>.
|
||||
HttpClientStepDetail = {
|
||||
# Body parsing happens according to a heuristic interpretation
|
||||
# of Content-Type headers.
|
||||
# Set this field as "application/octet-stream" to never parse
|
||||
# response bodies or to "application/json" to parse all response
|
||||
# bodies as JSON.
|
||||
response-content-type-override: string
|
||||
} .
|
||||
|
||||
HttpDriverStep= <http-driver { }>.
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"bom-ref": "pkg:nim/syndicate_utils",
|
||||
"name": "syndicate_utils",
|
||||
"description": "Utilites for Syndicated Actors and Synit",
|
||||
"version": "20240621",
|
||||
"version": "20240622",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Emery Hemingway"
|
||||
|
|
|
@ -28,7 +28,7 @@ proc url(req: HttpRequest): Uri =
|
|||
|
||||
proc toContent(body: Value; contentType: var string): string =
|
||||
case contentType
|
||||
of "application/json":
|
||||
of "application/json", "text/javascript":
|
||||
var stream = newStringStream()
|
||||
writeText(stream, body, textJson)
|
||||
return stream.data.move
|
||||
|
@ -52,9 +52,9 @@ proc toContent(body: Value; contentType: var string): string =
|
|||
raise newException(ValueError, "unknown content type")
|
||||
|
||||
proc spawnHttpClient*(turn: Turn; relay: Cap): Actor {.discardable.} =
|
||||
let pat = Resolve?:{ 0: HttpClientStep.matchType, 1: grab() }
|
||||
let pat = Resolve?:{ 0: HttpClientStep.grabWithin, 1: grab() }
|
||||
result = spawnActor(turn, "http-client") do (turn: Turn):
|
||||
during(turn, relay, pat) do (observer: Cap):
|
||||
during(turn, relay, pat) do (detail: HttpClientStepDetail, observer: Cap):
|
||||
linkActor(turn, "session") do (turn: Turn):
|
||||
let ds = turn.newDataspace()
|
||||
discard publish(turn, observer, ResolvedAccepted(responderSession: ds))
|
||||
|
@ -64,7 +64,7 @@ proc spawnHttpClient*(turn: Turn; relay: Cap): Actor {.discardable.} =
|
|||
try:
|
||||
var
|
||||
headers = newHttpHeaders()
|
||||
contentType = ""
|
||||
contentType: string
|
||||
for key, val in ctx.req.headers:
|
||||
if key == Symbol"content-type" or key == Symbol"Content-Type":
|
||||
contentType = val
|
||||
|
@ -74,20 +74,23 @@ proc spawnHttpClient*(turn: Turn; relay: Cap): Actor {.discardable.} =
|
|||
ctx.req.method.string.toUpper,
|
||||
ctx.req.body.toContent(contentType), headers
|
||||
)
|
||||
client.headers["content-type"] = contentType
|
||||
var resp = HttpResponse(orKind: HttpResponseKind.status)
|
||||
resp.status.code = stdRes.status[0 .. 2].parseInt
|
||||
resp.status.message = stdRes.status[3 .. ^1]
|
||||
message(turn, peer, resp)
|
||||
resp = HttpResponse(orKind: HttpResponseKind.header)
|
||||
for key, val in stdRes.headers:
|
||||
if key == "Content-Type":
|
||||
for key, vals in stdRes.headers.table:
|
||||
for val in vals.items:
|
||||
resp.header.name = key.Symbol
|
||||
resp.header.value = val
|
||||
message(turn, peer, resp)
|
||||
if detail.`response-content-type-override` != "":
|
||||
contentType = detail.`response-content-type-override`
|
||||
else:
|
||||
for val in stdRes.headers.table.getOrDefault("content-type").items:
|
||||
contentType = val
|
||||
resp.header.name = key.Symbol
|
||||
resp.header.value = val
|
||||
message(turn, peer, resp)
|
||||
case contentType
|
||||
of "application/json", "text/preserves":
|
||||
of "application/json", "text/preserves", "text/javascript":
|
||||
message(turn, peer,
|
||||
initRecord("done", stdRes.bodyStream.readAll.parsePreserves))
|
||||
of "application/preserves":
|
||||
|
|
|
@ -39,6 +39,9 @@ type
|
|||
XsltArguments* {.preservesRecord: "xslt".} = object
|
||||
`field0`*: XsltArgumentsField0
|
||||
|
||||
HttpClientStepDetail* {.preservesDictionary.} = object
|
||||
`response-content-type-override`*: string
|
||||
|
||||
JsonSocketTranslatorStepField0* {.preservesDictionary.} = object
|
||||
`socket`*: SocketAddress
|
||||
|
||||
|
@ -51,10 +54,8 @@ type
|
|||
FileSystemUsageArguments* {.preservesRecord: "file-system-usage".} = object
|
||||
`field0`*: FileSystemUsageArgumentsField0
|
||||
|
||||
HttpClientStepField0* {.preservesDictionary.} = object
|
||||
|
||||
HttpClientStep* {.preservesRecord: "http-client".} = object
|
||||
`field0`*: HttpClientStepField0
|
||||
`detail`*: HttpClientStepDetail
|
||||
|
||||
HttpDriverStepField0* {.preservesDictionary.} = object
|
||||
|
||||
|
@ -109,6 +110,7 @@ type
|
|||
proc `$`*(x: JsonTranslatorArguments | SocketAddress | Base64DecoderArguments |
|
||||
SqliteStep |
|
||||
XsltArguments |
|
||||
HttpClientStepDetail |
|
||||
JsonSocketTranslatorStep |
|
||||
FileSystemUsageArguments |
|
||||
HttpClientStep |
|
||||
|
@ -127,6 +129,7 @@ proc `$`*(x: JsonTranslatorArguments | SocketAddress | Base64DecoderArguments |
|
|||
proc encode*(x: JsonTranslatorArguments | SocketAddress | Base64DecoderArguments |
|
||||
SqliteStep |
|
||||
XsltArguments |
|
||||
HttpClientStepDetail |
|
||||
JsonSocketTranslatorStep |
|
||||
FileSystemUsageArguments |
|
||||
HttpClientStep |
|
||||
|
|
Loading…
Reference in New Issue