mirror of
https://github.com/golang/go
synced 2024-11-26 21:31:32 -07:00
internal/poll: netpollcheckerr before sendfile
In net/http package, the ServeContent/ServeFile doesn't check the I/O timeout error from chunkWriter or *net.TCPConn, which means that both HTTP status and headers might be missing when WriteTimeout happens. If the poll.SendFile() doesn't check the *poll.FD state before sending data, the client will only receive the response body with status and report "malformed http response/status code". This patch is to enable netpollcheckerr before sendfile, which should align with normal *poll.FD.Write() and Splice(). Fixes #43822 Change-Id: I32517e3f261bab883a58b577b813ef189214b954 Reviewed-on: https://go-review.googlesource.com/c/go/+/285914 Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> Trust: Emmanuel Odeke <emmanuel@orijtech.com> Trust: Bryan C. Mills <bcmills@google.com> Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com>
This commit is contained in:
parent
0cb3415154
commit
f0d23c9dbb
@ -18,6 +18,10 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
defer dstFD.writeUnlock()
|
defer dstFD.writeUnlock()
|
||||||
|
if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
dst := int(dstFD.Sysfd)
|
dst := int(dstFD.Sysfd)
|
||||||
var written int64
|
var written int64
|
||||||
var err error
|
var err error
|
||||||
|
@ -16,6 +16,9 @@ func SendFile(dstFD *FD, src int, remain int64) (int64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
defer dstFD.writeUnlock()
|
defer dstFD.writeUnlock()
|
||||||
|
if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
dst := int(dstFD.Sysfd)
|
dst := int(dstFD.Sysfd)
|
||||||
var written int64
|
var written int64
|
||||||
|
@ -20,6 +20,9 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
defer dstFD.writeUnlock()
|
defer dstFD.writeUnlock()
|
||||||
|
if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
dst := int(dstFD.Sysfd)
|
dst := int(dstFD.Sysfd)
|
||||||
var written int64
|
var written int64
|
||||||
|
@ -10,8 +10,10 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
@ -313,3 +315,66 @@ func TestSendfilePipe(t *testing.T) {
|
|||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue 43822: tests that returns EOF when conn write timeout.
|
||||||
|
func TestSendfileOnWriteTimeoutExceeded(t *testing.T) {
|
||||||
|
ln, err := newLocalListener("tcp")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
errc := make(chan error, 1)
|
||||||
|
go func(ln Listener) (retErr error) {
|
||||||
|
defer func() {
|
||||||
|
errc <- retErr
|
||||||
|
close(errc)
|
||||||
|
}()
|
||||||
|
|
||||||
|
conn, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// Set the write deadline in the past(1h ago). It makes
|
||||||
|
// sure that it is always write timeout.
|
||||||
|
if err := conn.SetWriteDeadline(time.Now().Add(-1 * time.Hour)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(newton)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(conn, f)
|
||||||
|
if errors.Is(err, os.ErrDeadlineExceeded) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
err = fmt.Errorf("expected ErrDeadlineExceeded, but got nil")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}(ln)
|
||||||
|
|
||||||
|
conn, err := Dial("tcp", ln.Addr().String())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
n, err := io.Copy(ioutil.Discard, conn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected nil error, but got %v", err)
|
||||||
|
}
|
||||||
|
if n != 0 {
|
||||||
|
t.Fatalf("expected receive zero, but got %d byte(s)", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := <-errc; err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user