Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

triple request missed http header like scheme, host etc. #2642

Open
2456868764 opened this issue Mar 22, 2024 · 3 comments
Open

triple request missed http header like scheme, host etc. #2642

2456868764 opened this issue Mar 22, 2024 · 3 comments

Comments

@2456868764
Copy link

2456868764 commented Mar 22, 2024

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
Copy link
Contributor

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
Copy link
Author

2456868764 commented Apr 3, 2024

这个设置头部做法在 http2下有问题,一开始有个 method = PRI 协商协议,这个时候是不能设置头部,否则这个协商协议就挂, 要看是否有更合适解决方案 @chickenlj

@2456868764
Copy link
Author

我现在做法:

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 判断再补全,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants