JuliaWeb / GnuTLS.jl

Transport Level Security for Julia Streams provided by GnuTLS
Other
8 stars 13 forks source link

eof(::Session) and read(::Session) don't get along #26

Open jkroso opened 9 years ago

jkroso commented 9 years ago

The following prints the complete response then throws a "read: end of file" error. Where as I would expect it to block on eof until the connection is closed by the github server.

using GnuTLS

sess = GnuTLS.Session()
set_priority_string!(sess)
set_credentials!(sess, GnuTLS.CertificateStore())
associate_stream(sess, connect("github.com", 443))
handshake!(sess)
write(sess, "GET / HTTP/1.1\r\n\r\n")

while !eof(sess)
  print(read(sess, Char))
end
sbromberger commented 9 years ago

the issue is in read()- if the ccall returns 0, it throws an EOFError. Better to use readavailable() / readall(), which should handle this gracefully:

while !eof(sess)
         print(bytestring(readavailable(sess)))
end

Please confirm that this works for you and I'll close it out.

jkroso commented 9 years ago

Now it throws "stream is closed or unusable" from the readavailable call so it looks like eof still isn't doing its job properly

sbromberger commented 9 years ago

Can you make sure you've done a Pkg.update() first? We've explicitly fixed this issue in the latest versions of Requests and GnuTLS.

jkroso commented 9 years ago

Oh yup sweet readavailable works with the latest version. I still feel like eof should be fixed though

sbromberger commented 9 years ago

How would you propose doing that with read()?

That is, eof() isn't broken; EOFError is thrown when the ccall that is performed by read() returns 0. Since read() is designed to be (more or less) atomic, what should be done?

jkroso commented 9 years ago

I guess you would probably have to block inside eof until at least the next byte is available so you can see if its the null byte.

However, then you would have to hold that data in a buffer until read or one of its variants are called. So it will probably add a lot of internal complexity to manage the buffer but at least at the end Session will have a peek method :)

sbromberger commented 9 years ago

well, we could do a wait_readnb(s,1) in read() but that's really just mimicking what we do in eof() on the read stream.

My current preference is that eof() shouldn't be used with read() in any case, since any eof check in read() will likely block on nb_available < 1, and it's probably better just to throw the exception right away.

Of course, my present understanding of 1) how this should work and 2) how it actually works is suspect.

jkroso commented 9 years ago

That is, eof() isn't broken; EOFError is thrown when the ccall that is performed by read() returns 0. Since read() is designed to be (more or less) atomic, what should be done?

Huh..? if a call to read would result in an EOFError shouldn't eof return true?

sbromberger commented 9 years ago

So - one other thing that doesn't make a difference in this particular case, but read() needs a UInt8 (1 byte), not a Char (4 bytes).