I have a server net.Conn
, and I'd like to peek into it before reading out bytes, to check if it's a plain text protocol the client is trying to use, or SSL/TLS.
Checking http://golang.org/pkg/net/, it seems the Conn
interface does not have anything like that. I know I could use an iobuf.Reader
, but I'd like to get a TLS Conn via tls.Conn(conn, config)
if it turns out the client is using SSL/TLS, and iobuf.Reader
would read from the original Conn
, thus the handshake in tls.Conn
would fail.
So is there any way to peek into a Conn
in Go (something like MSG_PEEK
in C/C++ sockets)? Or, to create a tls.Conn
after I had read out the first few bytes from the underlying Conn
?
You're very close to a solution - the only thing you got wrong was reading from the
Conn
itself first. You are right thatbufio.Reader
'sPeek
method is the way to go. The trick is to make the buffered reader first and callPeek
on the buffered reader rather than reading from the originalConn
. Here's abufferedConn
type that will do what you need:What this does is allow you to access all of the normal
net.Conn
methods (by embedding thenet.Conn
- you could also write wrapper functions, but this is a lot easier and cleaner), and additionally provide access to thebufferedReader
'sPeek
andRead
methods (it's important thatRead
be called on thebufferedReader
, not directly on thenet.Conn
becausePeek
stores data in a buffer, so subsequent calls toRead
need to be able to first read any data out of this buffer before falling back to the underlyingnet.Conn
).The
newBufferedConnSize
function is probably unnecessary given that the current default buffer size is 4096 bytes, but technically if you're going to rely on being able to callPeek
with a given size and not have it return an error (specificallyErrBufferFull
), you should set it explicitly to a size that's at least as big as the number of bytes you intend to peek.Check it out on the Go Playground.