Skip to content

Commit

Permalink
Enable full-duplex for HTTP/1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
francislavoie committed Jul 26, 2023
1 parent a05c5b6 commit dce9fe1
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 0 deletions.
8 changes: 8 additions & 0 deletions caddyconfig/httpcaddyfile/serveroptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type serverOptions struct {
IdleTimeout caddy.Duration
KeepAliveInterval caddy.Duration
MaxHeaderBytes int
EnableFullDuplex bool
Protocols []string
StrictSNIHost *bool
TrustedProxiesRaw json.RawMessage
Expand Down Expand Up @@ -157,6 +158,12 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
}
serverOpts.MaxHeaderBytes = int(size)

case "enable_full_duplex":
if d.NextArg() {
return nil, d.ArgErr()
}
serverOpts.EnableFullDuplex = true

case "log_credentials":
if d.NextArg() {
return nil, d.ArgErr()
Expand Down Expand Up @@ -327,6 +334,7 @@ func applyServerOptions(
server.IdleTimeout = opts.IdleTimeout
server.KeepAliveInterval = opts.KeepAliveInterval
server.MaxHeaderBytes = opts.MaxHeaderBytes
server.EnableFullDuplex = opts.EnableFullDuplex
server.Protocols = opts.Protocols
server.StrictSNIHost = opts.StrictSNIHost
server.TrustedProxiesRaw = opts.TrustedProxiesRaw
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
idle 30s
}
max_header_size 100MB
enable_full_duplex
log_credentials
protocols h1 h2 h2c h3
strict_sni_host
Expand Down Expand Up @@ -45,6 +46,7 @@ foo.com {
"write_timeout": 30000000000,
"idle_timeout": 30000000000,
"max_header_bytes": 100000000,
"enable_full_duplex": true,
"routes": [
{
"match": [
Expand Down
25 changes: 25 additions & 0 deletions modules/caddyhttp/duplex_go120.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !go1.21

package caddyhttp

import (
"net/http"
)

func enableFullDuplex(w http.ResponseWriter) {
// Do nothing, Go 1.20 and earlier do not support full duplex
}
25 changes: 25 additions & 0 deletions modules/caddyhttp/duplex_go121.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build go1.21

package caddyhttp

import (
"net/http"
)

func enableFullDuplex(w http.ResponseWriter) {
http.NewResponseController(w).EnableFullDuplex()
}
14 changes: 14 additions & 0 deletions modules/caddyhttp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ type Server struct {
// HTTP request headers.
MaxHeaderBytes int `json:"max_header_bytes,omitempty"`

// Enable full-duplex communication for HTTP/1.1 requests.
// Only has an effect if Caddy was built with Go 1.21 or later.
//
// TODO: This is an EXPERIMENTAL feature. Subject to change or removal.
EnableFullDuplex bool `json:"enable_full_duplex,omitempty"`

// Routes describes how this server will handle requests.
// Routes are executed sequentially. First a route's matchers
// are evaluated, then its grouping. If it matches and has
Expand Down Expand Up @@ -264,6 +270,14 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
repl := caddy.NewReplacer()
r = PrepareRequest(r, repl, w, s)

// enable full-duplex for HTTP/1, ensuring the entire
// request body gets consumed before writing the response
if s.EnableFullDuplex {
// TODO: Remove duplex_go12*.go abstraction once our
// minimum Go version is 1.21 or later
enableFullDuplex(w)
}

// encode the request for logging purposes before
// it enters any handler chain; this is necessary
// to capture the original request in case it gets
Expand Down

0 comments on commit dce9fe1

Please sign in to comment.