triple request missed http header like scheme, host etc.
2456868764 opened this issue · 3 comments
2456868764 commented
Environment
- Server:
- Client:
- Protocol:
- Registry:
Issue description
The user story is to get if the current request is https or http.
there is dubbo filter demo code which just output attachments :
func (f *mtlsFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
// get request schema
attachments := ctx.Value(constant.AttachmentKey).(map[string]interface{})
for key, attachment := range attachments {
logger.Infof("get triple attachment key %s = %s", key, attachment.([]string)[0])
}
}
and output as follow:
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [retries ] = %!s(MISSING)
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [user-agent grpc-go-triple/0.1.0 (go1.21.6)] = %!s(MISSING)
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [te trailers] = %!s(MISSING)
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [content-type application/grpc+proto] = %!s(MISSING)
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [interface greet.GreetService] = %!s(MISSING)
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [grpc-accept-encoding gzip] = %!s(MISSING)
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [timeout ] = %!s(MISSING)
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [grpc-timeout 2999023u] = %!s(MISSING)
2024-03-22 02:15:34 INFO logger/logging.go:42 get triple attachment key [accept-encoding identity] = %!s(MISSING)
and miss some common http headers like scheme ,host etc.
Logs
Click me to check logs
Copy logs to here.
chickenlj commented
Solution by @2456868764 in #2643
setHTTPSHeaders := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Set http scheme header
r.Header.Set(":x-scheme", "https")
r.Header.Set(":x-host", r.Host)
r.Header.Set(":x-path", r.RequestURI)
r.Header.Set(":x-method", r.Method)
certs := r.TLS.PeerCertificates
if len(certs) > 0 {
peerCert := certs[0]
if len(peerCert.URIs) > 0 {
spiffeURI := peerCert.URIs[0].String()
// Set spiffe scheme header
r.Header.Set(":x-spiffe", spiffeURI)
}
}
h.ServeHTTP(w, r)
})
}
2456868764 commented
这个设置头部做法在 http2下有问题,一开始有个 method = PRI 协商协议,这个时候是不能设置头部,否则这个协商协议就挂, 要看是否有更合适解决方案 @chickenlj
2456868764 commented
我现在做法:
dubbo-go/protocol/triple/triple_protocol/server.go 启动两个端口,一个http, 一个 HTTPS
代码如下 :
func (s *Server) Run() error {
// todo(DMwangnima): deal with TLS
// Check if both listeners are nil
// todo http and https port can be different based on mutual tls mode and tls config provider existed or not
httpAddr := s.addr
httpsAddr := s.getHTTPSAddress(s.addr)
httpOn := true
httpsOn := false
if s.tlsConfigProvider != nil {
httpsOn = true
}
handler := h2c.NewHandler(s.mux, &http2.Server{})
setHTTPHeaders := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
headers := make(map[string]interface{}, 0)
headers[constant.HttpHeaderXSchemeName] = "http"
headers[constant.HttpHeaderXHostName] = r.Host
headers[constant.HttpHeaderXPathName] = r.RequestURI
headers[constant.HttpHeaderXMethodName] = "POST"
ctx := context.WithValue(r.Context(), constant.AttachmentKey, headers)
request := r.WithContext(ctx)
h.ServeHTTP(w, request)
})
}
setHTTPSHeaders := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
headers := make(map[string]interface{}, 0)
headers[constant.HttpHeaderXSchemeName] = "https"
headers[constant.HttpHeaderXHostName] = r.Host
headers[constant.HttpHeaderXPathName] = r.RequestURI
headers[constant.HttpHeaderXMethodName] = r.Method
certs := r.TLS.PeerCertificates
if len(certs) > 0 {
peerCert := certs[0]
if len(peerCert.URIs) > 0 {
spiffeURI := peerCert.URIs[0].String()
// Set spiffe scheme header
headers[constant.HttpHeaderXSpiffeName] = spiffeURI
}
}
ctx := context.WithValue(r.Context(), constant.AttachmentKey, headers)
request := r.WithContext(ctx)
h.ServeHTTP(w, request)
})
}
if s.httpLn == nil && httpOn {
httpLn, err := net.Listen("tcp", httpAddr)
if err != nil {
httpLn.Close()
return err
}
s.httpLn = httpLn
s.httpSrv = &http.Server{Handler: setHTTPHeaders(handler)}
}
if s.httpsLn == nil && httpsOn {
tlsCfg, err := s.tlsConfigProvider()
if err != nil {
logger.Error("can not get tls config")
}
httpsLn, err := tls.Listen("tcp", httpsAddr, tlsCfg)
if err != nil {
httpsLn.Close()
return err
}
s.httpsLn = httpsLn
s.httpsSrv = &http.Server{Handler: setHTTPSHeaders(handler)}
}
if httpsOn {
go s.httpsSrv.Serve(s.httpsLn)
}
// http should be on now
if err := s.httpSrv.Serve(s.httpLn); err != nil {
return err
}
return nil
}
HTTPS 可以设置自定义头, HTTP不可以,因为http 一进来就是走了 r.Method == "PRI",这个时候不能设置自定义头。
func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Handle h2c with prior knowledge (RFC 7540 Section 3.4)
if r.Method == "PRI" && len(r.Header) == 0 && r.URL.Path == "*" && r.Proto == "HTTP/2.0" {
if http2VerboseLogs {
log.Print("h2c: attempting h2c with prior knowledge.")
}
....
}
也做了其他trick做法,我现在trick做法 HTTP不设置定义头,HTTPS设置,后续在 dubbo filter 判断再补全,