package runtime

import (
	
	
	
	
	
	
	

	
	
	
	
	
	
	
)

// UnescapingMode defines the behavior of ServeMux when unescaping path parameters.
type UnescapingMode int

const (
	// UnescapingModeLegacy is the default V2 behavior, which escapes the entire
	// path string before doing any routing.
	UnescapingModeLegacy UnescapingMode = iota

	// UnescapingModeAllExceptReserved unescapes all path parameters except RFC 6570
	// reserved characters.
	UnescapingModeAllExceptReserved

	// UnescapingModeAllExceptSlash unescapes URL path parameters except path
	// separators, which will be left as "%2F".
	UnescapingModeAllExceptSlash

	// UnescapingModeAllCharacters unescapes all URL path parameters.
	UnescapingModeAllCharacters

	// UnescapingModeDefault is the default escaping type.
	// TODO(v3): default this to UnescapingModeAllExceptReserved per grpc-httpjson-transcoding's
	// reference implementation
	UnescapingModeDefault = UnescapingModeLegacy
)

var encodedPathSplitter = regexp.MustCompile("(/|%2F)")

// A HandlerFunc handles a specific pair of path pattern and HTTP method.
type HandlerFunc func(w http.ResponseWriter, r *http.Request, pathParams map[string]string)

// A Middleware handler wraps another HandlerFunc to do some pre- and/or post-processing of the request. This is used as an alternative to gRPC interceptors when using the direct-to-implementation
// registration methods. It is generally recommended to use gRPC client or server interceptors instead
// where possible.
type Middleware func(HandlerFunc) HandlerFunc

// ServeMux is a request multiplexer for grpc-gateway.
// It matches http requests to patterns and invokes the corresponding handler.
type ServeMux struct {
	// handlers maps HTTP method to a list of handlers.
	handlers                  map[string][]handler
	middlewares               []Middleware
	forwardResponseOptions    []func(context.Context, http.ResponseWriter, proto.Message) error
	forwardResponseRewriter   ForwardResponseRewriter
	marshalers                marshalerRegistry
	incomingHeaderMatcher     HeaderMatcherFunc
	outgoingHeaderMatcher     HeaderMatcherFunc
	outgoingTrailerMatcher    HeaderMatcherFunc
	metadataAnnotators        []func(context.Context, *http.Request) metadata.MD
	errorHandler              ErrorHandlerFunc
	streamErrorHandler        StreamErrorHandlerFunc
	routingErrorHandler       RoutingErrorHandlerFunc
	disablePathLengthFallback bool
	unescapingMode            UnescapingMode
	writeContentLength        bool
}

// ServeMuxOption is an option that can be given to a ServeMux on construction.
type ServeMuxOption func(*ServeMux)

// ForwardResponseRewriter is the signature of a function that is capable of rewriting messages
// before they are forwarded in a unary, stream, or error response.
type ForwardResponseRewriter func(ctx context.Context, response proto.Message) (any, error)

// WithForwardResponseRewriter returns a ServeMuxOption that allows for implementers to insert logic
// that can rewrite the final response before it is forwarded.
//
// The response rewriter function is called during unary message forwarding, stream message
// forwarding and when errors are being forwarded.
//
// NOTE: Using this option will likely make what is generated by `protoc-gen-openapiv2` incorrect.
// Since this option involves making runtime changes to the response shape or type.
func ( ForwardResponseRewriter) ServeMuxOption {
	return func( *ServeMux) {
		.forwardResponseRewriter = 
	}
}

// WithForwardResponseOption returns a ServeMuxOption representing the forwardResponseOption.
//
// forwardResponseOption is an option that will be called on the relevant context.Context,
// http.ResponseWriter, and proto.Message before every forwarded response.
//
// The message may be nil in the case where just a header is being sent.
func ( func(context.Context, http.ResponseWriter, proto.Message) error) ServeMuxOption {
	return func( *ServeMux) {
		.forwardResponseOptions = append(.forwardResponseOptions, )
	}
}

// WithUnescapingMode sets the escaping type. See the definitions of UnescapingMode
// for more information.
func ( UnescapingMode) ServeMuxOption {
	return func( *ServeMux) {
		.unescapingMode = 
	}
}

// WithMiddlewares sets server middleware for all handlers. This is useful as an alternative to gRPC
// interceptors when using the direct-to-implementation registration methods and cannot rely
// on gRPC interceptors. It's recommended to use gRPC interceptors instead if possible.
func ( ...Middleware) ServeMuxOption {
	return func( *ServeMux) {
		.middlewares = append(.middlewares, ...)
	}
}

// SetQueryParameterParser sets the query parameter parser, used to populate message from query parameters.
// Configuring this will mean the generated OpenAPI output is no longer correct, and it should be
// done with careful consideration.
func ( QueryParameterParser) ServeMuxOption {
	return func( *ServeMux) {
		currentQueryParser = 
	}
}

// HeaderMatcherFunc checks whether a header key should be forwarded to/from gRPC context.
type HeaderMatcherFunc func(string) (string, bool)

// DefaultHeaderMatcher is used to pass http request headers to/from gRPC context. This adds permanent HTTP header
// keys (as specified by the IANA, e.g: Accept, Cookie, Host) to the gRPC metadata with the grpcgateway- prefix. If you want to know which headers are considered permanent, you can view the isPermanentHTTPHeader function.
// HTTP headers that start with 'Grpc-Metadata-' are mapped to gRPC metadata after removing the prefix 'Grpc-Metadata-'.
// Other headers are not added to the gRPC metadata.
func ( string) (string, bool) {
	switch  = textproto.CanonicalMIMEHeaderKey(); {
	case isPermanentHTTPHeader():
		return MetadataPrefix + , true
	case strings.HasPrefix(, MetadataHeaderPrefix):
		return [len(MetadataHeaderPrefix):], true
	}
	return "", false
}

func defaultOutgoingHeaderMatcher( string) (string, bool) {
	return fmt.Sprintf("%s%s", MetadataHeaderPrefix, ), true
}

func defaultOutgoingTrailerMatcher( string) (string, bool) {
	return fmt.Sprintf("%s%s", MetadataTrailerPrefix, ), true
}

// WithIncomingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for incoming request to gateway.
//
// This matcher will be called with each header in http.Request. If matcher returns true, that header will be
// passed to gRPC context. To transform the header before passing to gRPC context, matcher should return the modified header.
func ( HeaderMatcherFunc) ServeMuxOption {
	for ,  := range .matchedMalformedHeaders() {
		grpclog.Warningf("The configured forwarding filter would allow %q to be sent to the gRPC server, which will likely cause errors. See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more information.", )
	}

	return func( *ServeMux) {
		.incomingHeaderMatcher = 
	}
}

// matchedMalformedHeaders returns the malformed headers that would be forwarded to gRPC server.
func ( HeaderMatcherFunc) () []string {
	if  == nil {
		return nil
	}
	 := make([]string, 0)
	for  := range malformedHTTPHeaders {
		,  := ()
		if  && isMalformedHTTPHeader() {
			 = append(, )
		}
	}
	return 
}

// WithOutgoingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for outgoing response from gateway.
//
// This matcher will be called with each header in response header metadata. If matcher returns true, that header will be
// passed to http response returned from gateway. To transform the header before passing to response,
// matcher should return the modified header.
func ( HeaderMatcherFunc) ServeMuxOption {
	return func( *ServeMux) {
		.outgoingHeaderMatcher = 
	}
}

// WithOutgoingTrailerMatcher returns a ServeMuxOption representing a headerMatcher for outgoing response from gateway.
//
// This matcher will be called with each header in response trailer metadata. If matcher returns true, that header will be
// passed to http response returned from gateway. To transform the header before passing to response,
// matcher should return the modified header.
func ( HeaderMatcherFunc) ServeMuxOption {
	return func( *ServeMux) {
		.outgoingTrailerMatcher = 
	}
}

// WithMetadata returns a ServeMuxOption for passing metadata to a gRPC context.
//
// This can be used by services that need to read from http.Request and modify gRPC context. A common use case
// is reading token from cookie and adding it in gRPC context.
func ( func(context.Context, *http.Request) metadata.MD) ServeMuxOption {
	return func( *ServeMux) {
		.metadataAnnotators = append(.metadataAnnotators, )
	}
}

// WithErrorHandler returns a ServeMuxOption for configuring a custom error handler.
//
// This can be used to configure a custom error response.
func ( ErrorHandlerFunc) ServeMuxOption {
	return func( *ServeMux) {
		.errorHandler = 
	}
}

// WithStreamErrorHandler returns a ServeMuxOption that will use the given custom stream
// error handler, which allows for customizing the error trailer for server-streaming
// calls.
//
// For stream errors that occur before any response has been written, the mux's
// ErrorHandler will be invoked. However, once data has been written, the errors must
// be handled differently: they must be included in the response body. The response body's
// final message will include the error details returned by the stream error handler.
func ( StreamErrorHandlerFunc) ServeMuxOption {
	return func( *ServeMux) {
		.streamErrorHandler = 
	}
}

// WithRoutingErrorHandler returns a ServeMuxOption for configuring a custom error handler to  handle http routing errors.
//
// Method called for errors which can happen before gRPC route selected or executed.
// The following error codes: StatusMethodNotAllowed StatusNotFound StatusBadRequest
func ( RoutingErrorHandlerFunc) ServeMuxOption {
	return func( *ServeMux) {
		.routingErrorHandler = 
	}
}

// WithDisablePathLengthFallback returns a ServeMuxOption for disable path length fallback.
func () ServeMuxOption {
	return func( *ServeMux) {
		.disablePathLengthFallback = true
	}
}

// WithWriteContentLength returns a ServeMuxOption to enable writing content length on non-streaming responses
func () ServeMuxOption {
	return func( *ServeMux) {
		.writeContentLength = true
	}
}

// WithHealthEndpointAt returns a ServeMuxOption that will add an endpoint to the created ServeMux at the path specified by endpointPath.
// When called the handler will forward the request to the upstream grpc service health check (defined in the
// gRPC Health Checking Protocol).
//
// See here https://grpc-ecosystem.github.io/grpc-gateway/docs/operations/health_check/ for more information on how
// to setup the protocol in the grpc server.
//
// If you define a service as query parameter, this will also be forwarded as service in the HealthCheckRequest.
func ( grpc_health_v1.HealthClient,  string) ServeMuxOption {
	return func( *ServeMux) {
		// error can be ignored since pattern is definitely valid
		_ = .HandlePath(
			http.MethodGet, , func( http.ResponseWriter,  *http.Request,  map[string]string,
			) {
				,  := MarshalerForRequest(, )

				,  := .Check(.Context(), &grpc_health_v1.HealthCheckRequest{
					Service: .URL.Query().Get("service"),
				})
				if  != nil {
					.errorHandler(.Context(), , , , , )
					return
				}

				.Header().Set("Content-Type", "application/json")

				if .GetStatus() != grpc_health_v1.HealthCheckResponse_SERVING {
					switch .GetStatus() {
					case grpc_health_v1.HealthCheckResponse_NOT_SERVING, grpc_health_v1.HealthCheckResponse_UNKNOWN:
						 = status.Error(codes.Unavailable, .String())
					case grpc_health_v1.HealthCheckResponse_SERVICE_UNKNOWN:
						 = status.Error(codes.NotFound, .String())
					}

					.errorHandler(.Context(), , , , , )
					return
				}

				_ = .NewEncoder().Encode()
			})
	}
}

// WithHealthzEndpoint returns a ServeMuxOption that will add a /healthz endpoint to the created ServeMux.
//
// See WithHealthEndpointAt for the general implementation.
func ( grpc_health_v1.HealthClient) ServeMuxOption {
	return WithHealthEndpointAt(, "/healthz")
}

// NewServeMux returns a new ServeMux whose internal mapping is empty.
func ( ...ServeMuxOption) *ServeMux {
	 := &ServeMux{
		handlers:                make(map[string][]handler),
		forwardResponseOptions:  make([]func(context.Context, http.ResponseWriter, proto.Message) error, 0),
		forwardResponseRewriter: func( context.Context,  proto.Message) (any, error) { return , nil },
		marshalers:              makeMarshalerMIMERegistry(),
		errorHandler:            DefaultHTTPErrorHandler,
		streamErrorHandler:      DefaultStreamErrorHandler,
		routingErrorHandler:     DefaultRoutingErrorHandler,
		unescapingMode:          UnescapingModeDefault,
	}

	for ,  := range  {
		()
	}

	if .incomingHeaderMatcher == nil {
		.incomingHeaderMatcher = DefaultHeaderMatcher
	}
	if .outgoingHeaderMatcher == nil {
		.outgoingHeaderMatcher = defaultOutgoingHeaderMatcher
	}
	if .outgoingTrailerMatcher == nil {
		.outgoingTrailerMatcher = defaultOutgoingTrailerMatcher
	}

	return 
}

// Handle associates "h" to the pair of HTTP method and path pattern.
func ( *ServeMux) ( string,  Pattern,  HandlerFunc) {
	if len(.middlewares) > 0 {
		 = chainMiddlewares(.middlewares)()
	}
	.handlers[] = append([]handler{{pat: , h: }}, .handlers[]...)
}

// HandlePath allows users to configure custom path handlers.
// refer: https://grpc-ecosystem.github.io/grpc-gateway/docs/operations/inject_router/
func ( *ServeMux) ( string,  string,  HandlerFunc) error {
	,  := httprule.Parse()
	if  != nil {
		return fmt.Errorf("parsing path pattern: %w", )
	}
	 := .Compile()
	,  := NewPattern(.Version, .OpCodes, .Pool, .Verb)
	if  != nil {
		return fmt.Errorf("creating new pattern: %w", )
	}
	.Handle(, , )
	return nil
}

// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.URL.Path.
func ( *ServeMux) ( http.ResponseWriter,  *http.Request) {
	 := .Context()

	 := .URL.Path
	if !strings.HasPrefix(, "/") {
		,  := MarshalerForRequest(, )
		.routingErrorHandler(, , , , , http.StatusBadRequest)
		return
	}

	// TODO(v3): remove UnescapingModeLegacy
	if .unescapingMode != UnescapingModeLegacy && .URL.RawPath != "" {
		 = .URL.RawPath
	}

	if  := .Header.Get("X-HTTP-Method-Override");  != "" && .isPathLengthFallback() {
		if  := .ParseForm();  != nil {
			,  := MarshalerForRequest(, )
			 := status.Error(codes.InvalidArgument, .Error())
			.errorHandler(, , , , , )
			return
		}
		.Method = strings.ToUpper()
	}

	var  []string
	// since in UnescapeModeLegacy, the URL will already have been fully unescaped, if we also split on "%2F"
	// in this escaping mode we would be double unescaping but in UnescapingModeAllCharacters, we still do as the
	// path is the RawPath (i.e. unescaped). That does mean that the behavior of this function will change its default
	// behavior when the UnescapingModeDefault gets changed from UnescapingModeLegacy to UnescapingModeAllExceptReserved
	if .unescapingMode == UnescapingModeAllCharacters {
		 = encodedPathSplitter.Split([1:], -1)
	} else {
		 = strings.Split([1:], "/")
	}

	 := [len()-1]

	for ,  := range .handlers[.Method] {
		// If the pattern has a verb, explicitly look for a suffix in the last
		// component that matches a colon plus the verb. This allows us to
		// handle some cases that otherwise can't be correctly handled by the
		// former LastIndex case, such as when the verb literal itself contains
		// a colon. This should work for all cases that have run through the
		// parser because we know what verb we're looking for, however, there
		// are still some cases that the parser itself cannot disambiguate. See
		// the comment there if interested.

		var  string
		 := .pat.Verb()

		 := -1
		if  != "" && strings.HasSuffix(, ":"+) {
			 = len() - len() - 1
		}
		if  == 0 {
			,  := MarshalerForRequest(, )
			.routingErrorHandler(, , , , , http.StatusNotFound)
			return
		}

		 := make([]string, len())
		copy(, )

		if  > 0 {
			[len()-1],  = [:], [+1:]
		}

		,  := .pat.MatchAndEscape(, , .unescapingMode)
		if  != nil {
			var  MalformedSequenceError
			if  := errors.As(, &);  {
				,  := MarshalerForRequest(, )
				.errorHandler(, , , , , &HTTPStatusError{
					HTTPStatus: http.StatusBadRequest,
					Err:        ,
				})
			}
			continue
		}
		.handleHandler(, , , )
		return
	}

	// if no handler has found for the request, lookup for other methods
	// to handle POST -> GET fallback if the request is subject to path
	// length fallback.
	// Note we are not eagerly checking the request here as we want to return the
	// right HTTP status code, and we need to process the fallback candidates in
	// order to do that.
	for ,  := range .handlers {
		if  == .Method {
			continue
		}
		for ,  := range  {
			var  string
			 := .pat.Verb()

			 := -1
			if  != "" && strings.HasSuffix(, ":"+) {
				 = len() - len() - 1
			}

			 := make([]string, len())
			copy(, )

			if  > 0 {
				[len()-1],  = [:], [+1:]
			}

			,  := .pat.MatchAndEscape(, , .unescapingMode)
			if  != nil {
				var  MalformedSequenceError
				if  := errors.As(, &);  {
					,  := MarshalerForRequest(, )
					.errorHandler(, , , , , &HTTPStatusError{
						HTTPStatus: http.StatusBadRequest,
						Err:        ,
					})
				}
				continue
			}

			// X-HTTP-Method-Override is optional. Always allow fallback to POST.
			// Also, only consider POST -> GET fallbacks, and avoid falling back to
			// potentially dangerous operations like DELETE.
			if .isPathLengthFallback() &&  == http.MethodGet {
				if  := .ParseForm();  != nil {
					,  := MarshalerForRequest(, )
					 := status.Error(codes.InvalidArgument, .Error())
					.errorHandler(, , , , , )
					return
				}
				.handleHandler(, , , )
				return
			}
			,  := MarshalerForRequest(, )
			.routingErrorHandler(, , , , , http.StatusMethodNotAllowed)
			return
		}
	}

	,  := MarshalerForRequest(, )
	.routingErrorHandler(, , , , , http.StatusNotFound)
}

// GetForwardResponseOptions returns the ForwardResponseOptions associated with this ServeMux.
func ( *ServeMux) () []func(context.Context, http.ResponseWriter, proto.Message) error {
	return .forwardResponseOptions
}

func ( *ServeMux) ( *http.Request) bool {
	return !.disablePathLengthFallback && .Method == "POST" && .Header.Get("Content-Type") == "application/x-www-form-urlencoded"
}

type handler struct {
	pat Pattern
	h   HandlerFunc
}

func ( *ServeMux) ( handler,  http.ResponseWriter,  *http.Request,  map[string]string) {
	.h(, .WithContext(withHTTPPattern(.Context(), .pat)), )
}

func chainMiddlewares( []Middleware) Middleware {
	return func( HandlerFunc) HandlerFunc {
		for  := len();  > 0; -- {
			 = [-1]()
		}
		return 
	}
}