-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
encoding/base64: SetReadDeadline fails to set deadline on socket when piped thru base64 decoder #3577
Labels
Milestone
Comments
Owner changed to @bradfitz. Status changed to Started. |
Proposed fix: http://golang.org/cl/6137054 |
This issue was closed by revision ed90fbc. Status changed to Fixed. |
Comment 6 by branimirkaradzic: I integrated change and still doesn't appear fixed. I stripped down code and got better repro case. See line with conn.decode = true (in func NewConn), change it to false to get expected behavior. Let me know if I need to better describe the problem. package main import ( "code.google.com/p/go.net/websocket" "encoding/base64" "fmt" "io" "net" "net/http" "syscall" "time" ) const ( DefaultTimeout time.Duration = 8e9 ) type Conn struct { rw net.Conn dec io.Reader decode bool } func NewConn(rw net.Conn) (conn *Conn) { conn = new(Conn) conn.rw = rw conn.dec = base64.NewDecoder(base64.StdEncoding, rw) conn.decode = true // change this to false to see expected results. return } func (conn *Conn) Read(b []byte) (n int, err error) { conn.rw.SetReadDeadline(time.Now().Add(DefaultTimeout)) if conn.decode { n, err = conn.dec.Read(b) } else { n, err = conn.rw.Read(b) } if err != syscall.EAGAIN { err2, ok := err.(*net.OpError) if !ok || !err2.Temporary() { return } return n, nil } return } func webSocketHandler(rw *websocket.Conn) { defer rw.Close() fmt.Print("server: incoming\n") conn := NewConn(rw, ) var ( err error n int ) nowNs := time.Now().UnixNano() nextNs := nowNs + 4e9 var calls uint64 for err == nil && n == 0 { b := make([]byte, 1024) n, err = conn.Read(b) calls++ nowNs = time.Now().UnixNano() if nowNs > nextNs { nextNs += 4e9 fmt.Print("Calls in 4 secs: ", calls, "\n") } } fmt.Print("server: client left\n") } func client() { for { <-time.After(4e9) fmt.Print("client: connect attempt\n") ws, err := websocket.Dial("ws://localhost:1234/ws", "", "http://localhost/") if err == nil { conn := NewConn(ws) var ( err error n int ) for err == nil && n == 0 { b := make([]byte, 1024) n, err = conn.Read(b) } ws.Close() fmt.Print("client: left\n") } else { fmt.Print("client: ", err, "\n") } } } func main() { go client() http.Handle("/ws", websocket.Handler(webSocketHandler)) err := http.ListenAndServe(":1234", nil) if err != nil { panic("ListenAndServe: " + err.Error()) } } |
Could you cut it down to a single unit test: func TestWhatever(t *testing.T) { ... } ... and one that doesn't sleep for 8+ seconds? I looked at your code for awhile and didn't understand what it was trying to do. I could observe differences, but I wasn't convinced that your code was even correct to begin with. I wrapped the readers with printing wrappers and it just looked like your code was spinning. Probably due to those EAGAIN checks. This bug did fix a real issue, but I don't see another issue. |
Your code is never hitting that syscall.EAGAIN code path. That's a distraction and has nothing to do with this bug. The problem with your code is that you're assuming you can continue to use a base64 Decoder after it's encountered a ReadError (an I/O timeout from SetReadDeadline). You can not. Once the base64 decoder hits a read error, the decoder is permanently busted. Don't set a deadline if you don't want one, or if you want to mask the read error, do it in a wrapped reader that you give to the base64 decoder. Just don't like base64 see an error. Anyway, this isn't a bug in the base64 code. |
I'm not frustrated, but I still think your design is wrong. Forking base64 does not seem like the answer. But like I said: you can make your own Reader type and give that to base64 to mask errors if that was actually the answer, but I still think it's not. You shouldn't be setting a deadline if that's not an error. And if you're not setting the deadline, then something else is broken. |
bradfitz
added a commit
that referenced
this issue
May 11, 2015
…ead error in decode ««« backport 69c9477136d3 encoding/base64: don't ignore underlying souce read error in decode Fixes #3577 R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/6137054 »»»
mikioh
changed the title
SetReadDeadline fails to set deadline on socket when piped thru base64 decoder
encoding/base64: SetReadDeadline fails to set deadline on socket when piped thru base64 decoder
Jul 30, 2015
This issue was closed.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
by branimirkaradzic:
The text was updated successfully, but these errors were encountered: