Share Values Between Middlewares on net/http

Hello!!
I have a question about sharing values between middlewares.

I think we’ll be able to share values between middlewares in the following code by go 1.7.

func (a *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        user := GetUserFromRequestCookie(r)
        ctx := r.Context()
        ctx = context.WithValue(ctx, "user", user)

        r = r.WithContext(ctx)

        a.next.ServeHTTP(w, r) // next handler is ArticleHandle
}

func (a *ArticleHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context() 
    user := ctx.Value("user").(*User)
}

But r.WithContext(ctx) exec shallow copy for goroutine. I need not shallow copy for only sharing values. It is slow. right? I want to set context to Request. But now it cannot.

func (a *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        user := UserFromSession(r)
        ctx := r.Context()
        ctx = context.WithValue(ctx, "user", user)

        // r = r.WithContext(ctx)
        r.SetContext(ctx)

        a.next.ServeHTTP(w, r)
}

func (a *ArticleHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context() 
    user := ctx.Value("user").(*User)
}

Please tell me best way sharing values between middlewares using only net/http and context. I think we should not implement context wrapper like 3rd party framework impl for only sharing values.

Your first code looks reasonable. Do you have a specific reason to believe the context operation is a performance problem?

1 Like

I’m sorry that I mistook “deep copy” for “shallow copy” in first comment)

But r.WithContext(ctx) exec deep copy for goroutine. I need not deep
copy for only sharing values. It is slow. right? I want to set context to Request. But now it cannot.

I think WithContext() is slowly to exec http.request struct deep copy here.

And now I wonder if we should not use WithContext() for pass value from middleware to next middleware. WithContext() should be used only for goroutine? because I supposed to WithContext() made for goroutine in http server.

Is it better than first code?

The line of code you highlight *r2 = *r is a shallow copy, as most of the Request fields are pointers or maps. It’s essentially free as things go in computing nowadays. You should seriously not worry about it. :slight_smile:

1 Like

The line of code you highlight *r2 = *r is a shallow copy, as most of the Request fields are pointers or maps. It’s essentially free as things go in computing nowadays. You should seriously not worry about it.

http.Request is 240byte. It is not small.
If I use 2 middleware, 480byte copy per a http.request.

func main() {
	r := http.Request{}
	fmt.Println(unsafe.Sizeof(r))
}

result:

240

And I’m worried that Golang designer didn’t expected to use WithContext() for value pass between middleware. Now I don’t think that is best practice to use WithContext().

And I’m worried that Golang designer didn’t expected to use WithContext() for value pass between middleware. Now I don’t think that is best practice to use WithContext().

I found similar discussion. https://m.reddit.com/r/golang/comments/4sotnw/context/?utm_source=mweb_redirect&compact=true

https://twitter.com/peterbourgon/status/752022730812317696

Valid points. As the 1.7 docs say: “Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions.” (context package - context - Go Packages)

I think that’s in relation to proper design, not due to concerns about the cost of copying the request struct.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.