Checking EOF in tls stream

1,716 views
Skip to first unread message

Elazar Leibovich

unread,
Mar 11, 2012, 4:13:13 PM3/11/12
to golan...@googlegroups.com
I'm using the following code to test for EOF in a tls stream

    bufCon := bufio.NewReader(con)
    if _,err := bufCon.Peek(1); err == io.EOF {
        // handle closed connection
        return
    }
    req,err := http.ReadRequest(bufCon)
    ...

Is that the good way to check for EOF in TLS streams? Can I trust that ReadRequest will return io.EOF, only for NON premature EOF, ie closed stream?

Jessta

unread,
Mar 11, 2012, 8:51:04 PM3/11/12
to Elazar Leibovich, golan...@googlegroups.com

As far as I can tell by looking at the code, ReadRequest() will
return an io.ErrUnexpectedEOF if it can't read the Request line or an
io.EOF if it can't read a complete header line.

If it can read a complete request header it won't return any errors.

--
=====================
http://jessta.id.au

Andrew Gerrand

unread,
Mar 11, 2012, 9:18:39 PM3/11/12
to Elazar Leibovich, golan...@googlegroups.com
You should be able to rely on ReadRequest returning an error if it can't read the request correctly. If the reason for that is EOF, you should get an io.ErrUnexpectedEOF. In this case _you_ are expecting the EOF, even if ReadRequest isn't, so you can do the appropriate thing when that happens.

Generally it's better to attempt things and fail, rather than preemptively detect error conditions.

Andrew

Jessta

unread,
Mar 11, 2012, 9:38:08 PM3/11/12
to Andrew Gerrand, Elazar Leibovich, golan...@googlegroups.com
On Mon, Mar 12, 2012 at 12:18 PM, Andrew Gerrand <a...@google.com> wrote:
> You should be able to rely on ReadRequest returning an error if it can't
> read the request correctly. If the reason for that is EOF, you should get an
> io.ErrUnexpectedEOF.

Currently it's either an io.ErrUnexpectedEOF or an EOF depending on
where the EOF is encounted.
Perhaps it should just be always an io.ErrUnexpectedEOF?

--
=====================
http://jessta.id.au

Brad Fitzpatrick

unread,
Mar 11, 2012, 9:56:09 PM3/11/12
to Jessta, Andrew Gerrand, Elazar Leibovich, golan...@googlegroups.com
On Sun, Mar 11, 2012 at 6:38 PM, Jessta <jes...@jessta.id.au> wrote:
On Mon, Mar 12, 2012 at 12:18 PM, Andrew Gerrand <a...@google.com> wrote:
> You should be able to rely on ReadRequest returning an error if it can't
> read the request correctly. If the reason for that is EOF, you should get an
> io.ErrUnexpectedEOF.

Currently it's either an io.ErrUnexpectedEOF or an EOF depending on
where the EOF is encounted.
Perhaps it should just be always an io.ErrUnexpectedEOF?

Perhaps it should just always be one error without saying why?  The it could just return a bool: false for "didn't work".

What's wrong with it saying it saw EOF at a likely EOF spot vs an unexpected EOF spot?




Jessta

unread,
Mar 11, 2012, 10:15:56 PM3/11/12
to Brad Fitzpatrick, Andrew Gerrand, Elazar Leibovich, golan...@googlegroups.com
On Mon, Mar 12, 2012 at 12:56 PM, Brad Fitzpatrick <brad...@golang.org> wrote:
> What's wrong with it saying it saw EOF at a likely EOF spot vs an unexpected
> EOF spot?

I would think that getting an EOF while in the middle of reading a
header line would be unexpected.
The function never returns EOF in the case of an expected EOF(like a
valid end of input), it will only return EOF if the header is somehow
malformed or only partially sent.

--
=====================
http://jessta.id.au

Message has been deleted

Elazar Leibovich

unread,
Mar 12, 2012, 8:26:51 AM3/12/12
to golan...@googlegroups.com, Elazar Leibovich
Thanks!

I've seen this solution from the code, I could guess that io.ErrUnexpectedEOF would return if the stream is empty.

I have however two problems with that:

1) This behavior is not spec'ed, specifically, I'm not sure that someone won't return ErrUnexpectedEOF for some other error condition in the future. If this is expected, it should be in the documentation.
2) It is very difficult for me to understand that the behavior of

for ! eof(con) {
    req,err := http.ReadRequest(con)
    if err != nil {
        return err
    }
}

is equivalent to

for {
    req,err := http.ReadRequest(con) 
    if err ==  io.UnexpectedEOF {
        break // all is well? You said Unexpected didn't you?
    }
    if err != nil {
        return err
    }
}

Moreover, when I'm reading from an empty bufio.Reader, I'm getting an io.EOF, and not io.UnexpectedEOF, so the equivalent loop will be

for {
    nr,err := buf.Read(b)
    if err == io.EOF {
        return //done
    } 
}

http://play.golang.org/p/u_pcT40wu_

It looks so suspicious, and hard to understand I'm just checking for end of stream. Can't we add an alias which looks like io.EmptyReader, which all procedures should return when trying to read from an empty reader?

Brad Fitzpatrick

unread,
Mar 12, 2012, 11:25:02 AM3/12/12
to Peter Thrun, golan...@googlegroups.com, Jessta, Andrew Gerrand, Elazar Leibovich
On Sun, Mar 11, 2012 at 7:39 PM, Peter Thrun <peter...@ymail.com> wrote:
What's wrong with it saying it saw EOF at a likely EOF spot vs an unexpected EOF spot?

It does the opposite. See  http://play.golang.org/p/eYUX4vZzNB 

I expect EOF at request boundaries and ErrUnexpectedEOF for partial requests.

Yeah, okay, that's a bit weird.

Maybe open a bug?  I doubt it'll get changed before Go 1, but at least Go 1 doesn't specify the errors in these cases, so we're somewhat free to change it later.


Reply all
Reply to author
Forward
0 new messages