github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/servermaster/http.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package servermaster
    15  
    16  import (
    17  	"net/http"
    18  	"net/http/pprof"
    19  	"strings"
    20  
    21  	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    22  	"github.com/pingcap/failpoint"
    23  	"github.com/pingcap/tiflow/engine/pkg/openapi"
    24  	"github.com/pingcap/tiflow/engine/pkg/promutil"
    25  	"github.com/pingcap/tiflow/pkg/util"
    26  )
    27  
    28  // registerRoutes registers the routes for the HTTP server.
    29  func registerRoutes(router *http.ServeMux, grpcMux *runtime.ServeMux, forwardJobAPI http.HandlerFunc) {
    30  	// Swagger UI
    31  	router.HandleFunc("/swagger", openapi.SwaggerUI)
    32  	router.HandleFunc("/swagger/v1/openapiv2.json", openapi.SwaggerAPIv1)
    33  
    34  	// Job API
    35  	// There are two types of job API:
    36  	// 1. The job API implemented by the framework.
    37  	// 2. The job API implemented by the job master.
    38  	// Both of them are registered in the same "/api/v1/jobs/" path.
    39  	// The job API implemented by the job master is registered in the "/api/v1/jobs/{job_id}/".
    40  	// But framework has a special APIs cancel will register in the "/api/v1/jobs/{job_id}/" path too.
    41  	// So we first check whether the request should be forwarded to the job master.
    42  	// If yes, forward the request to the job master. Otherwise, delegate the request to the framework.
    43  	router.HandleFunc("/api/v1/", func(w http.ResponseWriter, r *http.Request) {
    44  		if shouldForwardJobAPI(r) {
    45  			forwardJobAPI(w, r)
    46  		} else {
    47  			grpcMux.ServeHTTP(w, r)
    48  		}
    49  	})
    50  
    51  	// pprof debug API
    52  	router.HandleFunc("/debug/pprof/", pprof.Index)
    53  	router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
    54  	router.HandleFunc("/debug/pprof/profile", pprof.Profile)
    55  	router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
    56  	router.HandleFunc("/debug/pprof/trace", pprof.Trace)
    57  	router.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
    58  
    59  	// Failpoint API
    60  	if util.FailpointBuild {
    61  		// `http.StripPrefix` is needed because `failpoint.HttpHandler` assumes that it handles the prefix `/`.
    62  		router.Handle("/debug/fail/", http.StripPrefix("/debug/fail", &failpoint.HttpHandler{}))
    63  	}
    64  
    65  	// Prometheus metrics API
    66  	router.Handle("/metrics", promutil.HTTPHandlerForMetric())
    67  }
    68  
    69  // shouldForwardJobAPI indicates whether the request should be forwarded to the job master.
    70  func shouldForwardJobAPI(r *http.Request) bool {
    71  	if !strings.HasPrefix(r.URL.Path, openapi.JobAPIPrefix) {
    72  		return false
    73  	}
    74  	apiPath := strings.TrimPrefix(r.URL.Path, openapi.JobAPIPrefix)
    75  	fields := strings.SplitN(apiPath, "/", 2)
    76  	if len(fields) != 2 {
    77  		return false
    78  	}
    79  	// cancel is implemented by framework,
    80  	// don't forward them to the job master.
    81  	if fields[1] == "cancel" {
    82  		return false
    83  	}
    84  	return true
    85  }