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 }