Having a problem understanding Body on the server...
# http4k
d
Having a problem understanding Body on the server side. Im using request.body.stream to feed to existing java code during a POST usually it works perfectliy but sometimes (consistantly) I get a EOF on the stream immediately. This makes sense if the stream was being read prior -- but it wasnt by me -- The comment to StreamBody is 'scary' ­čÖé but I cant find a comment on how to avoid a SteamBody -- as far as I can tell debugging , the body is already a StreamBody by the time its routed to the handler -- Still a mystery why it works sometimes and not others. regardless - if I wanted to avoid the problem -- how ?? Therese some places in the source where its tested isAvailble() and conditionally uses stream or stringBody() -- can I just use stringBody() always ?
d
Something is definitely reading your stream... It's an age old puzzle! But first, there's a lot to unpack so let's break it down with some of the usual candidates: 1. Are you using a debugging filter which is eating your stream first? 2. Are you using the contracts module? If so, and you've defined a recieving () in your meta block, then the preextraction filter will be reading it when verifying the contract. To get around this, set the preFlightExtraction option in the meta block to only extract the non-body parts.
If it is #2, then we have a little bit of a dilemma - we can't validate the contract (by default) without checking the contents. Which means reading the stream. We could rewrap the read bodyString (in the preextractionfilter) back into a Memory request and pass it to the endpoint handler, which would give the end user access to the stream again, but it is a bit of a lie because the contents are really in memory.
d
re quesions 1 )no 2) no I am reading a header however -- THis is the handler in question (a POST handler for AWS SNS messages using the aws SNS servlet handler library object AWSNotifications { fun sns(req: Request): Response { val messageType=req.header("x-amz-sns-message-type") if (messageType == null) return Response(Status.BAD_REQUEST).body("Unexpected message - missing sns header") // WTF: just use bodyBytes val body = req.bodyString() val ret=SnsHub.post(body.byteInputStream(Charsets.UTF_8)) return Response(ret).body("Received") } fun s3(req: Request): Response=Response(Status.OK) fun HubServer(port: Int)=HubAPI.Hub().asServer(Jetty(port)) fun server(port: Int) { HubServer(port).start().block() } }
I dont really need this 'fixed ' the payload is small and converting to String is find
Im mainly trying to understand whats going on
Dont know if it matters -- but this is a combined websocket and http route
Im going to guess then that req.header(...) Is causing the stream to be read ( althoguh its a > 0 arg method so is it writing a header ? ) Even so -- It would be 'nice' if body.stream, apon detecting that the stream was read, created a new one form the body array so code doesnt fall over and die unexpectedly.
d
Ok - first thing - I've added some javadocs to the HttpMessage classes and now this is released as 3.172.0
I'd also like to understand what's going on with your app, because it sounds very (very!) strange. When you say that
Copy code
*usually* it works perfectliy but sometimes (consistantly) I get a EOF on the stream immediately.
do you mean that for any particular run of the server process it always does it, or does the behaviour vary within a single running process instance?
Here's a Gist with what I believe is the same behaviour as your app: https://gist.github.com/daviddenton/6c6ca879e96f66779f394ca7a200983b - but this one works ok. Would like to see if we can work out where they differ
I'd also be interested to see what the upstream filter stack looks like in
HubAPI.Hub()
(ie. all the filters composed that are before the request hits the sns handler)