gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/go-control-plane/pkg/server/v3/gateway.go (about)

     1  // Copyright 2018 Envoyproxy Authors
     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  //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //   See the License for the specific language governing permissions and
    13  //   limitations under the License.
    14  
    15  package server
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"gitee.com/ks-custle/core-gm/go-control-plane/pkg/resource/v3"
    21  	"io/ioutil"
    22  	"net/http"
    23  	"path"
    24  
    25  	"github.com/golang/protobuf/jsonpb"
    26  
    27  	discovery "gitee.com/ks-custle/core-gm/go-control-plane/envoy/service/discovery/v3"
    28  	"gitee.com/ks-custle/core-gm/go-control-plane/pkg/cache/types"
    29  	"gitee.com/ks-custle/core-gm/go-control-plane/pkg/log"
    30  )
    31  
    32  // HTTPGateway is a custom implementation of [gRPC gateway](https://github.com/grpc-ecosystem/grpc-gateway)
    33  // specialized to Envoy xDS API.
    34  type HTTPGateway struct {
    35  	// Log is an optional log for errors in response write
    36  	Log log.Logger
    37  
    38  	// Server is the underlying gRPC server
    39  	Server Server
    40  }
    41  
    42  func (h *HTTPGateway) ServeHTTP(req *http.Request) ([]byte, int, error) {
    43  	p := path.Clean(req.URL.Path)
    44  
    45  	typeURL := ""
    46  	switch p {
    47  	case resource.FetchEndpoints:
    48  		typeURL = resource.EndpointType
    49  	case resource.FetchClusters:
    50  		typeURL = resource.ClusterType
    51  	case resource.FetchListeners:
    52  		typeURL = resource.ListenerType
    53  	case resource.FetchRoutes:
    54  		typeURL = resource.RouteType
    55  	case resource.FetchSecrets:
    56  		typeURL = resource.SecretType
    57  	case resource.FetchRuntimes:
    58  		typeURL = resource.RuntimeType
    59  	case resource.FetchExtensionConfigs:
    60  		typeURL = resource.ExtensionConfigType
    61  	default:
    62  		return nil, http.StatusNotFound, fmt.Errorf("no endpoint")
    63  	}
    64  
    65  	if req.Body == nil {
    66  		return nil, http.StatusBadRequest, fmt.Errorf("empty body")
    67  	}
    68  
    69  	body, err := ioutil.ReadAll(req.Body)
    70  	if err != nil {
    71  		return nil, http.StatusBadRequest, fmt.Errorf("cannot read body")
    72  	}
    73  
    74  	// parse as JSON
    75  	out := &discovery.DiscoveryRequest{}
    76  	err = jsonpb.UnmarshalString(string(body), out)
    77  	if err != nil {
    78  		return nil, http.StatusBadRequest, fmt.Errorf("cannot parse JSON body: " + err.Error())
    79  	}
    80  	out.TypeUrl = typeURL
    81  
    82  	// fetch results
    83  	res, err := h.Server.Fetch(req.Context(), out)
    84  	if err != nil {
    85  		// SkipFetchErrors will return a 304 which will signify to the envoy client that
    86  		// it is already at the latest version; all other errors will 500 with a message.
    87  		if _, ok := err.(*types.SkipFetchError); ok {
    88  			return nil, http.StatusNotModified, nil
    89  		}
    90  		return nil, http.StatusInternalServerError, fmt.Errorf("fetch error: " + err.Error())
    91  	}
    92  
    93  	buf := &bytes.Buffer{}
    94  	if err := (&jsonpb.Marshaler{OrigName: true}).Marshal(buf, res); err != nil {
    95  		return nil, http.StatusInternalServerError, fmt.Errorf("marshal error: " + err.Error())
    96  	}
    97  
    98  	return buf.Bytes(), http.StatusOK, nil
    99  }