Skip to content

proposal: net/http: ServeMux.Handler should set the pattern and matches on the request #74744

@SampsonCrowley

Description

@SampsonCrowley

Proposal Details

right now it's very inefficient to have wrappers that uses Handler because for some reason it refuses to set the pattern matches and items on the request itself

we should change it so ServeHTTP calls handler, and for people who want to use Handler directly for their own middleware building, they don't need to basically force the server to run pathmatching twice

e.g. Example code that adds a top level middleware around requests (where m is a ServeMux`)

h, matchedPattern := m.ServeMux.Handler(r)
if m.notFoundHandler != nil && (h == nil || matchedPattern == "") {
	m.notFoundHandler.ServeHTTP(w, r)
} else {
	if m.httpHandler != nil {
		h = m.httpHandler(h)
	}

	h.ServeHTTP(w, r)
}

This will fail because r doesn't have any of the pattern match data and we can't call it or set it ourselves because findMatch is private, and even if findMatch wasn't private r.pat and r.matches are private.

Honestly I don't see why any of these are private. if it's about foot-guns, my response would be it's not the packages responsibility to stop me from breaking things if I want to touch the low levels.

IMO we should have a public method that calls findMatch and does exactly what ServeHTTP does for assigning request data.

if changing Handler is out of the question because it would break something to assign the data, then maybe a new function PrepareHandler that does and ServeHTTP can also use that method so it's DRY

// PrepareHandler finds the handler that most closely matches
// the request and prepares the request with PathData
// then returns the handler
func (mux *ServeMux) PrepareHandler(r *Request) h Handler {
	if use121 {
		h, _ = mux.mux121.findHandler(r)
	} else {
		h, r.Pattern, r.pat, r.matches = mux.findHandler(r)
	}
	return h
}

// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
	if r.RequestURI == "*" {
		if r.ProtoAtLeast(1, 1) {
			w.Header().Set("Connection", "close")
		}
		w.WriteHeader(StatusBadRequest)
		return
	}
	h := PrepareHandler(r)
	h.ServeHTTP(w, r)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolProposal

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions