github.com/cloudwego/hertz@v0.9.3/pkg/protocol/suite/server.go (about)

     1  /*
     2   * Copyright 2022 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package suite
    18  
    19  import (
    20  	"context"
    21  	"sync"
    22  
    23  	"github.com/cloudwego/hertz/pkg/app"
    24  	"github.com/cloudwego/hertz/pkg/common/errors"
    25  	"github.com/cloudwego/hertz/pkg/common/hlog"
    26  	"github.com/cloudwego/hertz/pkg/common/tracer"
    27  	"github.com/cloudwego/hertz/pkg/protocol"
    28  	"github.com/cloudwego/hertz/pkg/protocol/consts"
    29  )
    30  
    31  const (
    32  	// must be the same with the ALPN nextProto values
    33  	HTTP1 = "http/1.1"
    34  	HTTP2 = "h2"
    35  	// HTTP3Draft29 is the ALPN protocol negotiated during the TLS handshake, for QUIC draft 29.
    36  	HTTP3Draft29 = "h3-29"
    37  	// HTTP3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2.
    38  	HTTP3 = "h3"
    39  )
    40  
    41  // Core is the core interface that promises to be provided for the protocol layer extensions
    42  type Core interface {
    43  	// IsRunning Check whether engine is running or not
    44  	IsRunning() bool
    45  	// A RequestContext pool ready for protocol server impl
    46  	GetCtxPool() *sync.Pool
    47  	// Business logic entrance
    48  	// After pre-read works, protocol server may call this method
    49  	// to introduce the middlewares and handlers
    50  	ServeHTTP(c context.Context, ctx *app.RequestContext)
    51  	// GetTracer for tracing requirement
    52  	GetTracer() tracer.Controller
    53  }
    54  
    55  type ServerFactory interface {
    56  	New(core Core) (server protocol.Server, err error)
    57  }
    58  
    59  type StreamServerFactory interface {
    60  	New(core Core) (server protocol.StreamServer, err error)
    61  }
    62  
    63  type Config struct {
    64  	altServerConfig *altServerConfig
    65  	configMap       map[string]ServerFactory
    66  	streamConfigMap map[string]StreamServerFactory
    67  }
    68  
    69  type ServerMap map[string]protocol.Server
    70  
    71  type StreamServerMap map[string]protocol.StreamServer
    72  
    73  type altServerConfig struct {
    74  	targetProtocol   string
    75  	setAltHeaderFunc func(ctx context.Context, reqCtx *app.RequestContext)
    76  }
    77  
    78  type coreWrapper struct {
    79  	Core
    80  	beforeHandler func(c context.Context, ctx *app.RequestContext)
    81  }
    82  
    83  func (c *coreWrapper) ServeHTTP(ctx context.Context, reqCtx *app.RequestContext) {
    84  	c.beforeHandler(ctx, reqCtx)
    85  	c.Core.ServeHTTP(ctx, reqCtx)
    86  }
    87  
    88  // SetAltHeader will set response header "Alt-Svc" for the target protocol, altHeader will be the value of the header.
    89  // Protocols other than the target protocol will carry the altHeader in the request header.
    90  func (c *Config) SetAltHeader(target, altHeader string) {
    91  	c.altServerConfig = &altServerConfig{
    92  		targetProtocol: target,
    93  		setAltHeaderFunc: func(ctx context.Context, reqCtx *app.RequestContext) {
    94  			reqCtx.Response.Header.Add(consts.HeaderAltSvc, altHeader)
    95  		},
    96  	}
    97  }
    98  
    99  func (c *Config) Add(protocol string, factory interface{}) {
   100  	switch factory := factory.(type) {
   101  	case ServerFactory:
   102  		if fac := c.configMap[protocol]; fac != nil {
   103  			hlog.SystemLogger().Warnf("ServerFactory of protocol: %s will be overridden by customized function", protocol)
   104  		}
   105  		c.configMap[protocol] = factory
   106  	case StreamServerFactory:
   107  		if fac := c.streamConfigMap[protocol]; fac != nil {
   108  			hlog.SystemLogger().Warnf("StreamServerFactory of protocol: %s will be overridden by customized function", protocol)
   109  		}
   110  		c.streamConfigMap[protocol] = factory
   111  	default:
   112  		hlog.SystemLogger().Fatalf("Unsupported factory type: %T", factory)
   113  	}
   114  }
   115  
   116  func (c *Config) Get(name string) ServerFactory {
   117  	return c.configMap[name]
   118  }
   119  
   120  func (c *Config) Delete(protocol string) {
   121  	delete(c.configMap, protocol)
   122  }
   123  
   124  func (c *Config) Load(core Core, protocol string) (server protocol.Server, err error) {
   125  	if c.configMap[protocol] == nil {
   126  		return nil, errors.NewPrivate("HERTZ: Load server error, not support protocol: " + protocol)
   127  	}
   128  	if c.altServerConfig == nil || c.altServerConfig.targetProtocol == protocol {
   129  		return c.configMap[protocol].New(core)
   130  	}
   131  	return c.configMap[protocol].New(&coreWrapper{Core: core, beforeHandler: c.altServerConfig.setAltHeaderFunc})
   132  }
   133  
   134  func (c *Config) LoadAll(core Core) (serverMap ServerMap, streamServerMap StreamServerMap, err error) {
   135  	serverMap = make(ServerMap)
   136  	var wrappedCore *coreWrapper
   137  	if c.altServerConfig != nil {
   138  		wrappedCore = &coreWrapper{Core: core, beforeHandler: c.altServerConfig.setAltHeaderFunc}
   139  	}
   140  	var server protocol.Server
   141  	for proto := range c.configMap {
   142  		if c.altServerConfig != nil && c.altServerConfig.targetProtocol != proto {
   143  			core = wrappedCore
   144  		}
   145  		if server, err = c.configMap[proto].New(core); err != nil {
   146  			return nil, nil, err
   147  		} else {
   148  			serverMap[proto] = server
   149  		}
   150  	}
   151  	streamServerMap = make(StreamServerMap)
   152  	var streamServer protocol.StreamServer
   153  	for proto := range c.streamConfigMap {
   154  		if c.altServerConfig != nil && c.altServerConfig.targetProtocol != proto {
   155  			core = wrappedCore
   156  		}
   157  		if streamServer, err = c.streamConfigMap[proto].New(core); err != nil {
   158  			return nil, nil, err
   159  		} else {
   160  			streamServerMap[proto] = streamServer
   161  		}
   162  	}
   163  	return serverMap, streamServerMap, nil
   164  }
   165  
   166  // New return an empty Config suite, use .Add() to add protocol impl
   167  func New() *Config {
   168  	c := &Config{
   169  		configMap:       make(map[string]ServerFactory),
   170  		streamConfigMap: make(map[string]StreamServerFactory),
   171  	}
   172  
   173  	return c
   174  }