Skip to content

Commit

Permalink
optimize: idle timeout zero acts the same under different network lib
Browse files Browse the repository at this point in the history
  • Loading branch information
welkeyever committed Nov 10, 2022
1 parent c89d7ac commit 6be28d4
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 2 deletions.
4 changes: 4 additions & 0 deletions pkg/common/test/mock/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ func (m *Conn) Release() error {
func (m *Conn) Peek(i int) ([]byte, error) {
b, err := m.zr.Peek(i)
if err != nil || len(b) != i {
if m.readTimeout <= 0 {
// simulate timeout forever
select {}
}
time.Sleep(m.readTimeout)
return nil, errs.ErrTimeout
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/protocol/http1/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,8 @@ func (s Server) Serve(c context.Context, conn network.Conn) (err error) {
if connectionClose {
return errShortConnection
}

// Back to network layer to trigger.
// For now, only netpoll network mode has this feature.
if s.IdleTimeout == 0 {
return
}
Expand Down
8 changes: 7 additions & 1 deletion pkg/route/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ func iterate(method string, routes RoutesInfo, root *node) RoutesInfo {

// for built-in http1 impl only.
func newHttp1OptionFromEngine(engine *Engine) *http1.Option {
return &http1.Option{
opt := &http1.Option{
StreamRequestBody: engine.options.StreamRequestBody,
GetOnly: engine.options.GetOnly,
DisablePreParseMultipartForm: engine.options.DisablePreParseMultipartForm,
Expand All @@ -970,4 +970,10 @@ func newHttp1OptionFromEngine(engine *Engine) *http1.Option {
EnableTrace: engine.IsTraceEnable(),
HijackConnHandle: engine.HijackConnHandle,
}
// Idle timeout of standard network must not be zero. Set it to -1 seconds if it is zero.
// Due to the different triggering ways of the network library, see the actual use of this value for the detailed reasons.
if opt.IdleTimeout == 0 && engine.GetTransporterName() == "standard" {
opt.IdleTimeout = -1
}
return opt
}
33 changes: 33 additions & 0 deletions pkg/route/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,39 @@ func TestIdleTimeout01(t *testing.T) {
}
}

func TestIdleTimeout03(t *testing.T) {
engine := NewEngine(config.NewOptions(nil))
engine.options.IdleTimeout = 0
engine.transport = standard.NewTransporter(engine.options)
atomic.StoreUint32(&engine.status, statusRunning)
engine.Init()
atomic.StoreUint32(&engine.status, statusRunning)
engine.GET("/foo", func(c context.Context, ctx *app.RequestContext) {
time.Sleep(50 * time.Millisecond)
ctx.String(200, "ok")
})

conn := mock.NewConn("GET /foo HTTP/1.1\r\nHost: google.com\r\n\r\n" +
"GET /foo HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n")

ch := make(chan error)
startCh := make(chan error)
go func() {
<-startCh
ch <- engine.Serve(context.Background(), conn)
}()
close(startCh)
select {
case err := <-ch:
if !errors.Is(err, errs.ErrShortConnection) {
t.Errorf("err should be ErrShortConnection, but got %s", err)
}
return
case <-time.Tick(120 * time.Millisecond):
t.Errorf("timeout! should have been finished in 120ms...")
}
}

func TestEngine_Routes(t *testing.T) {
engine := NewEngine(config.NewOptions(nil))
engine.GET("/", handlerTest1)
Expand Down

0 comments on commit 6be28d4

Please sign in to comment.