ev/read
blocked indefinitely when called inside spork/http/server-handler
#1223
-
Hi! I tried to write a simple "echo" server in HTTP using I then tried to dig in, but it seems I can't quite grasp the complex fiber states, so I'm not sure whether I did something dumb or walked into a bug. When testing, I used the curl command curl -v --raw --form field=value http://127.0.0.1:8000 And this simple python program import requests
requests.post('http://127.0.0.1:8000', b'x' * 5) They all reproduced the problem. The full Janet program is listed below, and I attached a Wireshark dump file capturing the problematic HTTP session (see it with filter I appreciate any pointers. Thanks! (import spork/httpf)
(import spork/http)
(defn read-byte-chunks [conn n]
(var bytes-remaining n)
(while (pos? bytes-remaining)
(def bytes (ev/read conn bytes-remaining))
#(def [bytes] (ev/gather (ev/read conn bytes-remaining)))
(when (nil? bytes)
(print (string/format "---- short read! %q bytes remaining" bytes-remaining))
(break))
(-= bytes-remaining (length bytes))
(yield bytes)
(print (string/format "---- bytes-remaining %q" bytes-remaining))))
(defn http-generic-handler [req]
(def resp-headers
@{"content-type" "text/plain"
"server" "HTTP Generic Handler"})
(def conn (in req :connection))
(def content-length
(let [clen-str (get (req :headers) "content-length")
clen (if clen-str
(scan-number clen-str))]
(or clen 0)))
(print (string/format "---- Content-Length: %q" content-length))
(var bytes-remaining content-length)
{:status 200
:headers resp-headers
:body (coro (yield "Hello World!\r\n\r\n")
(yield (string/format "%q\r\n\r\n" req))
(print (string/format "---- going to read %q bytes" bytes-remaining))
(read-byte-chunks conn bytes-remaining)
)})
(defn main [&]
(let [s (httpf/server)]
(put s :on-connection
(fn conn-handler [conn]
(http/server-handler
conn
(-> http-generic-handler
http/cookies
http/logger))))
(httpf/listen s "127.0.0.1" 8000))) |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 1 reply
-
I should have mentionend that this problem exists in both Linux (6.3.x) and Windows 10. And the Janet version I used was 1.29.1. |
Beta Was this translation helpful? Give feedback.
-
I believe it's hanging because your code doesn't take into account the number of bytes that have already been read from the socket when it decides to Instead, you can use |
Beta Was this translation helpful? Give feedback.
-
You don't really need httpf for something like this: (import spork/http)
(defn on-request
[req &]
(def body (http/read-body req))
(printf "body: %q" body)
{:status 200
:headers {"content-type" "text/plain"}
:body (slice body)}) # slice is needed right now to clone the buffer
(http/server on-request "127.0.0.1" "8000") |
Beta Was this translation helpful? Give feedback.
-
Thank you for your replies @ianthehenry @bakpakin ! It's exactly the issue pointed out by @ianthehenry . I looked into It seems The original code is merely an answer to my own question, "What should I do If I want to pipe something through in the response body?" |
Beta Was this translation helpful? Give feedback.
I believe it's hanging because your code doesn't take into account the number of bytes that have already been read from the socket when it decides to
read
. The Spork HTTP framework has toread
from the socket at least once in order to parse the headers out, and it looks like it always reads in chunks of 4kb. So if you send a request with headers smaller than 4kb, part of the body has already been consumed (and put into(req :buffer)
), so you can't readcontent-length
more bytes from the socket.Instead, you can use
http/read-body
, which takes into account the bytes already read and only issues additional read calls if it needs to.