Skip to content

Commit 078fa17

Browse files
Uladzimir Trehubenkajohanbrandhorst
authored andcommitted
Added WithDisablePathLengthFallback option (to fix issue #447) (#855)
1 parent 0353029 commit 078fa17

File tree

2 files changed

+65
-12
lines changed

2 files changed

+65
-12
lines changed

runtime/mux.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ type HandlerFunc func(w http.ResponseWriter, r *http.Request, pathParams map[str
2020
// It matches http requests to patterns and invokes the corresponding handler.
2121
type ServeMux struct {
2222
// handlers maps HTTP method to a list of handlers.
23-
handlers map[string][]handler
24-
forwardResponseOptions []func(context.Context, http.ResponseWriter, proto.Message) error
25-
marshalers marshalerRegistry
26-
incomingHeaderMatcher HeaderMatcherFunc
27-
outgoingHeaderMatcher HeaderMatcherFunc
28-
metadataAnnotators []func(context.Context, *http.Request) metadata.MD
29-
protoErrorHandler ProtoErrorHandlerFunc
23+
handlers map[string][]handler
24+
forwardResponseOptions []func(context.Context, http.ResponseWriter, proto.Message) error
25+
marshalers marshalerRegistry
26+
incomingHeaderMatcher HeaderMatcherFunc
27+
outgoingHeaderMatcher HeaderMatcherFunc
28+
metadataAnnotators []func(context.Context, *http.Request) metadata.MD
29+
protoErrorHandler ProtoErrorHandlerFunc
30+
disablePathLengthFallback bool
3031
}
3132

3233
// ServeMuxOption is an option that can be given to a ServeMux on construction.
@@ -102,6 +103,13 @@ func WithProtoErrorHandler(fn ProtoErrorHandlerFunc) ServeMuxOption {
102103
}
103104
}
104105

106+
// WithDisablePathLengthFallback returns a ServeMuxOption for disable path length fallback.
107+
func WithDisablePathLengthFallback() ServeMuxOption {
108+
return func(serveMux *ServeMux) {
109+
serveMux.disablePathLengthFallback = true
110+
}
111+
}
112+
105113
// NewServeMux returns a new ServeMux whose internal mapping is empty.
106114
func NewServeMux(opts ...ServeMuxOption) *ServeMux {
107115
serveMux := &ServeMux{
@@ -177,7 +185,7 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
177185
components[l-1], verb = c[:idx], c[idx+1:]
178186
}
179187

180-
if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && isPathLengthFallback(r) {
188+
if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) {
181189
r.Method = strings.ToUpper(override)
182190
if err := r.ParseForm(); err != nil {
183191
if s.protoErrorHandler != nil {
@@ -211,7 +219,7 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
211219
continue
212220
}
213221
// X-HTTP-Method-Override is optional. Always allow fallback to POST.
214-
if isPathLengthFallback(r) {
222+
if s.isPathLengthFallback(r) {
215223
if err := r.ParseForm(); err != nil {
216224
if s.protoErrorHandler != nil {
217225
_, outboundMarshaler := MarshalerForRequest(s, r)
@@ -250,8 +258,8 @@ func (s *ServeMux) GetForwardResponseOptions() []func(context.Context, http.Resp
250258
return s.forwardResponseOptions
251259
}
252260

253-
func isPathLengthFallback(r *http.Request) bool {
254-
return r.Method == "POST" && r.Header.Get("Content-Type") == "application/x-www-form-urlencoded"
261+
func (s *ServeMux) isPathLengthFallback(r *http.Request) bool {
262+
return !s.disablePathLengthFallback && r.Method == "POST" && r.Header.Get("Content-Type") == "application/x-www-form-urlencoded"
255263
}
256264

257265
type handler struct {

runtime/mux_test.go

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ func TestMuxServeHTTP(t *testing.T) {
2727

2828
respStatus int
2929
respContent string
30+
31+
disablePathLengthFallback bool
3032
}{
3133
{
3234
patterns: nil,
@@ -122,6 +124,45 @@ func TestMuxServeHTTP(t *testing.T) {
122124
respStatus: http.StatusOK,
123125
respContent: "GET /foo",
124126
},
127+
{
128+
patterns: []stubPattern{
129+
{
130+
method: "GET",
131+
ops: []int{int(utilities.OpLitPush), 0},
132+
pool: []string{"foo"},
133+
},
134+
},
135+
reqMethod: "POST",
136+
reqPath: "/foo",
137+
headers: map[string]string{
138+
"Content-Type": "application/x-www-form-urlencoded",
139+
},
140+
respStatus: http.StatusMethodNotAllowed,
141+
respContent: "Method Not Allowed\n",
142+
disablePathLengthFallback: true,
143+
},
144+
{
145+
patterns: []stubPattern{
146+
{
147+
method: "GET",
148+
ops: []int{int(utilities.OpLitPush), 0},
149+
pool: []string{"foo"},
150+
},
151+
{
152+
method: "POST",
153+
ops: []int{int(utilities.OpLitPush), 0},
154+
pool: []string{"foo"},
155+
},
156+
},
157+
reqMethod: "POST",
158+
reqPath: "/foo",
159+
headers: map[string]string{
160+
"Content-Type": "application/x-www-form-urlencoded",
161+
},
162+
respStatus: http.StatusOK,
163+
respContent: "POST /foo",
164+
disablePathLengthFallback: true,
165+
},
125166
{
126167
patterns: []stubPattern{
127168
{
@@ -199,7 +240,11 @@ func TestMuxServeHTTP(t *testing.T) {
199240
respContent: "GET /foo/{id=*}:verb",
200241
},
201242
} {
202-
mux := runtime.NewServeMux()
243+
var opts []runtime.ServeMuxOption
244+
if spec.disablePathLengthFallback {
245+
opts = append(opts, runtime.WithDisablePathLengthFallback())
246+
}
247+
mux := runtime.NewServeMux(opts...)
203248
for _, p := range spec.patterns {
204249
func(p stubPattern) {
205250
pat, err := runtime.NewPattern(1, p.ops, p.pool, p.verb)

0 commit comments

Comments
 (0)