<commit_before>package powermux

import (
	"bytes"
	"context"
	"net/http"
	"strings"
)

// ServeMux is the multiplexer for http requests
type ServeMux struct {
	baseRoute     *Route
	hostRoutes    map[string]*Route
	executionPool *executionPool
}

// ctxKey is the key type used for path parameters in the request context
type ctxKey string

var (
	routeKey = ctxKey("route_name")
	paramKey = ctxKey("params")
)

// PathParam gets named path parameters and their values from the request
//
// the path '/users/:name' given '/users/andrew' will have `PathParam(r, "name")` => `"andrew"`
// unset values return an empty stringRoutes
func PathParam(req *http.Request, name string) (value string) {
	value = req.Context().Value(paramKey).(map[string]string)[name]
	return
}

// PathParams returns the map of all path parameters and their values from the request.
//
// Altering the values of this map will not affect future calls to PathParam and PathParams.
func PathParams(req *http.Request) (params map[string]string) {
	params = make(map[string]string)
	for k, v := range req.Context().Value(paramKey).(map[string]string) {
		params[k] = v
	}
	return
}

// RequestPath returns the path definition that the router used to serve this request,
// without any parameter substitution.
func RequestPath(req *http.Request) (value string) {
	value, _ = req.Context().Value(routeKey).(string)
	return value
}

// NewServeMux creates a new multiplexer, and sets up a default not found handler
func NewServeMux() *ServeMux {
	s := &ServeMux{
		baseRoute:     newRoute(),
		hostRoutes:    make(map[string]*Route),
		executionPool: newExecutionPool(),
	}
	s.NotFound(http.NotFoundHandler())
	return s
}

func (s *ServeMux) getAll(r *http.Request, ex *routeExecution) {
	path := r.URL.EscapedPath()

	// Check for redirect
	if path != "/" && strings.HasSuffix(path, "/") {
		r.URL.Path = strings.TrimRight(path, "/")
		ex.handler = http.RedirectHandler(r.URL.RequestURI(), http.StatusPermanentRedirect)
		ex.pattern = r.URL.EscapedPath()
		return
	}

	// fill it
	if route, ok := s.hostRoutes[r.URL.Host]; ok {
		route.execute(ex, r.Method, r.URL.EscapedPath())
	} else {
		s.baseRoute.execute(ex, r.Method, r.URL.EscapedPath())
	}

	// fall back on not found handler if necessary
	if ex.handler == nil {
		ex.handler = ex.notFound
	}

	return
}

// ServeHTTP dispatches the request to the handler whose pattern most closely matches the request URL.
func (s *ServeMux) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// Get a route execution from the pool
	ex := s.executionPool.Get()

	s.getAll(req, ex)

	// Save the route path
	ctx := context.WithValue(req.Context(), routeKey, ex.pattern)

	// set all the path params
	ctx = context.WithValue(ctx, paramKey, ex.params)

	// Save context into request
	req = req.WithContext(ctx)

	// Run a middleware/handler closure to nest all middleware
	f := getNextMiddleware(ex.middleware, ex.handler)
	f(rw, req)

	s.executionPool.Put(ex)
}
<commit_msg>Only save execution in context<commit_after>package powermux

import (
	"bytes"
	"context"
	"net/http"
	"strings"
)

// ServeMux is the multiplexer for http requests
type ServeMux struct {
	baseRoute     *Route
	hostRoutes    map[string]*Route
	executionPool *executionPool
}

// ctxKey is the key type used for path parameters in the request context
type ctxKey string

var (
	executionKey = ctxKey("ex")
)

func getRequestExecution(req *http.Request) *routeExecution {
	ex := req.Context().Value(executionKey).(*routeExecution)
	return ex
}

// PathParam gets named path parameters and their values from the request
//
// the path '/users/:name' given '/users/andrew' will have `PathParam(r, "name")` => `"andrew"`
// unset values return an empty stringRoutes
func PathParam(req *http.Request, name string) (value string) {
	ex := getRequestExecution(req)
	return ex.params[name]
}

// PathParams returns the map of all path parameters and their values from the request.
//
// Altering the values of this map will not affect future calls to PathParam and PathParams.
func PathParams(req *http.Request) (params map[string]string) {
	ex := getRequestExecution(req)
	params = make(map[string]string)
	for k, v := range ex.params {
		params[k] = v
	}
	return
}

// RequestPath returns the path definition that the router used to serve this request,
// without any parameter substitution.
func RequestPath(req *http.Request) (value string) {
	ex := getRequestExecution(req)
	return ex.pattern
}

// NewServeMux creates a new multiplexer, and sets up a default not found handler
func NewServeMux() *ServeMux {
	s := &ServeMux{
		baseRoute:     newRoute(),
		hostRoutes:    make(map[string]*Route),
		executionPool: newExecutionPool(),
	}
	s.NotFound(http.NotFoundHandler())
	return s
}

func (s *ServeMux) getAll(r *http.Request, ex *routeExecution) {
	path := r.URL.EscapedPath()

	// Check for redirect
	if path != "/" && strings.HasSuffix(path, "/") {
		r.URL.Path = strings.TrimRight(path, "/")
		ex.handler = http.RedirectHandler(r.URL.RequestURI(), http.StatusPermanentRedirect)
		ex.pattern = r.URL.EscapedPath()
		return
	}

	// fill it
	if route, ok := s.hostRoutes[r.URL.Host]; ok {
		route.execute(ex, r.Method, r.URL.EscapedPath())
	} else {
		s.baseRoute.execute(ex, r.Method, r.URL.EscapedPath())
	}

	// fall back on not found handler if necessary
	if ex.handler == nil {
		ex.handler = ex.notFound
	}

	return
}

// ServeHTTP dispatches the request to the handler whose pattern most closely matches the request URL.
func (s *ServeMux) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// Get a route execution from the pool
	ex := s.executionPool.Get()

	s.getAll(req, ex)

	// Save the execution
	ctx := context.WithValue(req.Context(), executionKey, ex)

	// Save context into request
	req = req.WithContext(ctx)

	// Run a middleware/handler closure to nest all middleware
	f := getNextMiddleware(ex.middleware, ex.handler)
	f(rw, req)

	s.executionPool.Put(ex)
}

{'fraction_non_alphanumeric': 0.12133891213389121, 'fraction_numerical': 0.0, 'mean_word_length': 4.060118543607112, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '445135', 'n_tokens_mistral': 2006, 'n_tokens_neox': 1928, 'n_words': 601}