Skip to content
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

Grab hangs when server sends unexpected TCP RST packet #48

Open
bts-dido opened this issue Dec 20, 2018 · 4 comments
Open

Grab hangs when server sends unexpected TCP RST packet #48

bts-dido opened this issue Dec 20, 2018 · 4 comments

Comments

@bts-dido
Copy link

I'm trying to download larger files using grab. Sometimes it works as expected, but sometimes it's hanging. After debugging, it seems server sends unexpected TCP RST packet when downloading and causing grab to hang. Is it possible to catch TCP RST packet inside grab.(*transfer).copy ?

I know, setting timeout on http client will solve hanging issue, but it's not desirable, since we don't know how long will it take to download file. Also if server sends TCP RST, there's no point waiting for timeout, it would be nice if grab performs fail-fast for us.

Download failed: net/http: request canceled (Client.Timeout exceeded while reading body)

I'm able to simulate server sending unexpected TCP RST packets, so happy to lending a hand if debugging is needed.

Here's the stacktrace when grab is hanging. For ease of read, newlines are inserted between frames.

goroutine 22 [IO wait, 6 minutes]:
internal/poll.runtime_pollWait
/usr/lib/go-1.10/src/runtime/netpoll.go:173 +0x57

internal/poll.(*pollDesc).wait
/usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85 +0x9b

internal/poll.(*pollDesc).waitRead
/usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90 +0x3d

internal/poll.(*FD).Read
/usr/lib/go-1.10/src/internal/poll/fd_unix.go:157 +0x17d

net.(*netFD).Read
/usr/lib/go-1.10/src/net/fd_unix.go:202 +0x4f

net.(*conn).Read
/usr/lib/go-1.10/src/net/net.go:176 +0x6a

crypto/tls.(*block).readFromUntil
/usr/lib/go-1.10/src/crypto/tls/conn.go:493 +0x96

crypto/tls.(*Conn).readRecord
/usr/lib/go-1.10/src/crypto/tls/conn.go:640 +0x1fa

crypto/tls.(*Conn).Read
/usr/lib/go-1.10/src/crypto/tls/conn.go:1156 +0x100

net/http.(*persistConn).Read
/usr/lib/go-1.10/src/net/http/transport.go:1453 +0x136

bufio.(*Reader).Read
/usr/lib/go-1.10/src/bufio/bufio.go:202 +0x12c

io.(*LimitedReader).Read
/usr/lib/go-1.10/src/io/io.go:446 +0x63

net/http.(*body).readLocked
/usr/lib/go-1.10/src/net/http/transfer.go:778 +0x61

net/http.(*body).Read
/usr/lib/go-1.10/src/net/http/transfer.go:770 +0xdd

net/http.(*bodyEOFSignal).Read
/usr/lib/go-1.10/src/net/http/transport.go:2187 +0xdc

github.com/cavaliercoder/grab.(*transfer).copy
/home/bat/go/src/github.com/cavaliercoder/grab/transfer.go:48 +0xf0

github.com/cavaliercoder/grab.(*Client).copyFile
/home/bat/go/src/github.com/cavaliercoder/grab/client.go:457 +0x93

github.com/cavaliercoder/grab.(*Client).(github.com/cavaliercoder/grab.copyFile)-fm
/home/bat/go/src/github.com/cavaliercoder/grab/client.go:88 +0x34

github.com/cavaliercoder/grab.(*Client).run
/home/bat/go/src/github.com/cavaliercoder/grab/client.go:175 +0x6e

created by github.com/cavaliercoder/grab.(*Client).Do
/home/bat/go/src/github.com/cavaliercoder/grab/client.go:88 +0x229

@cavaliercoder
Copy link
Collaborator

Apologies for late response on this. I'm hoping to solve this ASAP.

I'm able to simulate server sending unexpected TCP RST packets, so happy to lending a hand if debugging is needed.

This would be super helpful, yes please! Do you have a gist or article somewhere to demonstrate this?

@cavaliercoder
Copy link
Collaborator

I'm struggling to replicate this issue. It seems sending a random RST is harder than hoped. I'm looking at sending raw socket data which seems a step too far. Do you have a code sample?

As I look into this problem, I'm forming the opinion that handling resets should be covered by Go's HTTP reader returning an error: https://golang.org/src/net/http/response.go?#L54

	// The response body is streamed on demand as the Body field
	// is read. If the network connection fails or the server
	// terminates the response, Body.Read calls return an error.

If your program is hanging, I suspect there is a more subtle bug in my error handling or the http package.

@cavaliercoder
Copy link
Collaborator

Last commit at the time of stack trace: https://github.com/cavaliercoder/grab/tree/2c8601de6d9ac140430fd4c9de28509a0b855af5

And line 48 in transfer.go:

nr, er := c.r.Read(c.b)

@bts-dido
Copy link
Author

bts-dido commented Aug 5, 2019

@cavaliercoder Sorry for late response. Let me test again with latest commit and get back to you with the result.

I'm using iptables to simulate TCP RST packet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants