Hi, I was investigating this BedSheet BitBucket issue where, to cut a long story short, setting the Content-Type HTTP Request Header of a simple GET in web::WebClient causes a 10 second delay. Here is a test case:
using wisp
using web
class TenSeconds {
Void main() {
willow := WispService { it.port=8099 }.install.start
start := Duration.now
wc := WebClient(`http://localhost:8099/`)
echo("Start")
// This line causes the request to take 10 seconds to write / read
// comment it out for an immediate response
wc.reqHeaders["Content-Type"] = "text/plain"
wc.writeReq
wc.readRes
wc.resStr
wc.close
echo("\nTOTAL TIME: ${(Duration.now-start).toLocale}")
willow.stop.uninstall
}
}
By setting the Content-Type req header, WebUtil.makeContentOutStream() creates a chunked OutStream and sets the Transfer-Encoding req header. Wisp, on the other side of the request, then creates a chunked InStream (because of the Transfer-Encoding req header).
The 10 second delay appears to be some kind of socket time out because, despite these chunked streams being setup, no content is actually transferred.
Is there anything I (or the Fantom web pod) could do to prevent this? I ask because the code flow all seems quite logical.
The Real Problem
So you may be asking:
Why do you set the Content-Type request header in the first place? Just... don't!
It's because the original request is made by dom::HttpReq.send() which I have no control over. (The req is intercepted by a BedSheet proxy which uses WebClient to forward the req to the real application - same as draft.)
Looking at send() in HttpReqPeer.js, the Content-Type header is set when content is sent. But then HttpReq.get() defaults to always sending an empty string:
** Convenience for 'send("GET", "", c)'.
Void get(|HttpRes res| c)
{
send("GET", "", c)
}
Which means GET requests, when repeated by WebClient, will always incur the 10 seconds delay.
Get To The Point!
Could HttpReq.send() be updated to take null content and get() updated to send null?
**
** Send a request with the given content using the given
** HTTP method (case does not matter). After receiving
** the response, call the given closure with the resulting
** HttpRes object.
**
native Void send(Str method, Obj? content, |HttpRes res| c)
** Convenience for 'send("GET", "", c)'.
Void get(|HttpRes res| c)
{
send("GET", null, c)
}
By The Way
On my travels I noticed that web::WebUtil.doMakeContentInStream() reads:
len := headers["Content-Length"]
if (len != null)
return makeFixedInStream(in, len.toInt) { charset = cs }
Should it also check that the Content-Length header is greater than zero? I ask because I've seen many requests with a Content-Length of 0:
len := headers["Content-Length"]
if (len != null && len.toInt > 0)
return makeFixedInStream(in, len.toInt) { charset = cs }
(Phew. I think that's all! I was trying to keep this topic short, but there's so much back-story that it's not really possible - lemme know if you want me to re-explain any part.)
andyFri 27 Feb 2015
Ticket promoted to #2396 and assigned to andy
I'll have to double check the code - but yeah that should be fine to change.
SlimerDude Thu 26 Feb 2015
Hi, I was investigating this BedSheet BitBucket issue where, to cut a long story short, setting the
Content-Type
HTTP Request Header of a simple GET inweb::WebClient
causes a 10 second delay. Here is a test case:By setting the
Content-Type
req header,WebUtil.makeContentOutStream()
creates a chunked OutStream and sets theTransfer-Encoding
req header. Wisp, on the other side of the request, then creates a chunked InStream (because of theTransfer-Encoding
req header).The 10 second delay appears to be some kind of socket time out because, despite these chunked streams being setup, no content is actually transferred.
Is there anything I (or the Fantom
web
pod) could do to prevent this? I ask because the code flow all seems quite logical.The Real Problem
So you may be asking:
It's because the original request is made by
dom::HttpReq.send()
which I have no control over. (The req is intercepted by a BedSheet proxy which uses WebClient to forward the req to the real application - same asdraft
.)Looking at
send()
inHttpReqPeer.js
, theContent-Type
header is set when content is sent. But thenHttpReq.get()
defaults to always sending an empty string:Which means GET requests, when repeated by
WebClient
, will always incur the 10 seconds delay.Get To The Point!
Could
HttpReq.send()
be updated to takenull
content andget()
updated to sendnull
?By The Way
On my travels I noticed that
web::WebUtil.doMakeContentInStream()
reads:Should it also check that the
Content-Length
header is greater than zero? I ask because I've seen many requests with aContent-Length
of0
:(Phew. I think that's all! I was trying to keep this topic short, but there's so much back-story that it's not really possible - lemme know if you want me to re-explain any part.)
andy Fri 27 Feb 2015
Ticket promoted to #2396 and assigned to andy
I'll have to double check the code - but yeah that should be fine to change.
andy Tue 3 Mar 2015
Ticket resolved in 1.0.68
Fixed - changeset
shturman Tue 3 Mar 2015
After update i get "uncaught exception: sys::Err: sys::Type.toFanType: obj is null" in browser console on HttpReq
andy Tue 3 Mar 2015
Need to make sure you pickup the updated peer - double-check your browser cache.
shturman Tue 3 Mar 2015
I did it and see updated dom.js content in Firebug, but the error is still here
SlimerDude Wed 4 Mar 2015
I made a comment on the BitBucket commit.
andy Wed 4 Mar 2015
Yeah typo - should work now