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

fix(requestid): fix condition for setting default value of ContextKey… #2731

Closed
wants to merge 1 commit into from

Conversation

gopkg-dev
Copy link
Contributor

… in configDefault function

The condition for setting the default value of ContextKey in the configDefault function has been fixed. Previously, it only checked if cfg.ContextKey was an empty string, but now it also checks if it is nil. This ensures that the default value is set correctly even if cfg.ContextKey is not explicitly provided.

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
Explain the details for making this change. What existing problem does the pull request solve?

Fixes # (issue)

⚠️ For changes specific to v3, please switch to the v3 Pull Request Template.

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist:

  • For new functionalities I follow the inspiration of the express js framework and built them similar in usage
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation - /docs/ directory for https://docs.gofiber.io/
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • If new dependencies exist, I have checked that they are really necessary and agreed with the maintainers/community (we want to have as few dependencies as possible)
  • I tried to make my code as fast as possible with as few allocations as possible
  • For new code I have written benchmarks so that they can be analyzed and improved

Commit formatting:

Use emojis on commit messages so it provides an easy way of identifying the purpose or intention of a commit. Check out the emoji cheatsheet here: https://gitmoji.carloscuesta.me/

… in configDefault function

The condition for setting the default value of ContextKey in the configDefault function has been fixed. Previously, it only checked if cfg.ContextKey was an empty string, but now it also checks if it is nil. This ensures that the default value is set correctly even if cfg.ContextKey is not explicitly provided.
Copy link

welcome bot commented Nov 18, 2023

Thanks for opening this pull request! 🎉 Please check out our contributing guidelines. If you need help or want to chat with us, join us on Discord https://gofiber.io/discord

@@ -57,7 +57,7 @@ func configDefault(config ...Config) Config {
if cfg.Generator == nil {
cfg.Generator = ConfigDefault.Generator
}
if cfg.ContextKey == "" {
if cfg.ContextKey == nil || cfg.ContextKey == "" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ContextKey will only ever be "" if the user explicitly sets it to that value. In that case, overriding it to be "requestid" might be surprising.
Though I suppose changing it to accept "" now might break someone's code out there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be fine, check this #2731 (comment)

@ReneWerner87
Copy link
Member

thanks for the fix
image

due to the underlying locals customization of fasthttp, we have changed the type to interface to also allow numbers etc, this customization is correct
image
image

@ReneWerner87 ReneWerner87 linked an issue Nov 22, 2023 that may be closed by this pull request
3 tasks
@ReneWerner87
Copy link
Member

@gaby @efectn @gopkg-dev @Z3NTL3 @nickajacks1 @sixcolors
should we rather revert this pull request instead of this customization? meanwhile my opinion has changed and normally there is no reason for other types instead of strings if this should be a key
#2369

@benjajaja sorry for that, but i think it would be better to go back to the previous state

@nickajacks1
Copy link
Member

I feel like I've seen context keys as types/global vars before, something like

type contextKey int
const (
    contextKeyRequestId contextKey = iota
    contextKeySession
    // etc...
)

For this PR, if it was me, I'd probably keep it as an interface, do a nil check and leave it at that.
But even so, it's probably perfectly valid for Fiber to only support strings if that's a desired direction.
Cf. #2684

@sixcolors
Copy link
Member

Will review tonight or tomorrow night.

@Z3NTL3
Copy link
Contributor

Z3NTL3 commented Nov 23, 2023

I have looked on GoDoc and I've seen that ContextKey is an inteface{} type and not a string. So this change would be valid.

But there is one more thing, I've looked into the middleware code. And I've seen there is no appropiate type checking. Because an interface{} type in Go can be anything, when the users passes an object thats very off, like a struct or map it will put this object as a key to c.Locals which will result in unexpected behaviour and leak something bad off. There should be a check with reflect package to check if the given ContextKey is a string or int, anything else should set configuration to default.

https://github.com/valyala/fasthttp/blob/master/userdata.go#L14
This check here for setting, it's not enough in my opinion, Fiber uses this of fasthttp under the hood for c.Locals
This will leak something bad in the memory when the key is anything else than int or string

@ReneWerner87
Copy link
Member

@Z3NTL3 whats your opinion on this #2731 (comment)

@Z3NTL3
Copy link
Contributor

Z3NTL3 commented Nov 23, 2023

@Z3NTL3 whats your opinion on this #2731 (comment)

revert

@sixcolors
Copy link
Member

sixcolors commented Nov 23, 2023

Revert. String zero value used for default is behavior elsewhere too.

And follow up discussions can be held to adopt a universal approach when agreed upon.

@gopkg-dev
Copy link
Contributor Author

If the ContextKey parameter is not passed, it defaults to nil. This can cause the default configuration to lose its effect and prevent the use of the default ContextKey value. Therefore, I believe this is a bug. Currently, I am using it as follows:

package main

import (
	"log"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/requestid"
)

func main() {
	app := fiber.New()

	// Current implementation
	app.Use(requestid.New(requestid.Config{
		ContextKey: requestid.ConfigDefault.ContextKey,
		Generator:  util.NewXID,
	}))
	
	// Expected behavior
	app.Use(requestid.New(requestid.Config{
		Generator:  util.NewXID,
	}))

	log.Fatal(app.Listen(":3000"))
}

@Z3NTL3
Copy link
Contributor

Z3NTL3 commented Nov 27, 2023

@gopkg-dev

When viewing the GoDoc we can see ContextKey is an interface{}, which has to be again a string for the following reason:

I've looked into the middleware source. And I've seen there is no appropiate type checking. Because an ``interface{} type in Go can be anything, when the users passes an object thats very off, like a struct or map it will put this object as a key to c.Locals which will result in unexpected behaviour and leak something bad off. There should be a check with reflect package to check if the given ContextKey is a string or int, anything else should set configuration to default.

The reason for this is - Explained

https://github.com/valyala/fasthttp/blob/master/userdata.go#L14
This is used by c.Locals (also the middleware for setting ContextKey)
It will leak something bad in the memory when the key is anything else than int or string, so passing an interface{} is very much illegal

So its better to revert it back to be a string instead of an interface, to avoid overloads in different validating parts and memory leaks. In that matter, your PR becomes sadly said invalid. Idk what the maintainers will do.

@Z3NTL3
Copy link
Contributor

Z3NTL3 commented Nov 27, 2023

@gopkg-dev @ReneWerner87

ContextKey is set using:

https://github.com/valyala/fasthttp/blob/master/userdata.go#L14.

When we examine this method from fasthttp which is also being used byc.Locals under the hood

We can see that this method converts anything to a byte representation. So when we allow an interface the user may pass anything. When a struct or map is passed for example then it will be represented like:

In request Context object representation:
ContextKey: string= "struct{Test bool} {Test true}"

So this is the ContextKey, a string including the byte representation of the struct

Thats so illegal, the performance will tear down so hard. Some very illegal behaviour.

For those reasons, reverting the ContextKey back to be a string is valid.

@efectn
Copy link
Member

efectn commented Nov 27, 2023

@gopkg-dev @ReneWerner87

ContextKey is set using:

https://github.com/valyala/fasthttp/blob/master/userdata.go#L14.

When we examine this method from fasthttp which is also being used byc.Locals under the hood

We can see that this method converts anything to a byte representation. So when we allow an interface the user may pas anything. When a struct or map is passed for example then it will be represented like:

In request Context object representation:
ContextKey: string= "struct{Test bool} {Test true}"

So this is the ContextKey, a string including the byte representation of the struct

Thats so illegal, the performance will tear down so hard. Some very illegal behaviour.

For those reasons, reverting the ContextKey back to be a string is valid.

I do agree. We should keep parameters/fields as type-safe as possible.

@ReneWerner87
Copy link
Member

closed because of #2742

@benjajaja
Copy link
Contributor

@gopkg-dev @ReneWerner87

ContextKey is set using:

https://github.com/valyala/fasthttp/blob/master/userdata.go#L14.

When we examine this method from fasthttp which is also being used byc.Locals under the hood

We can see that this method converts anything to a byte representation.
[...]

This is not correct, at all: *userData.Set(k,v) ONLY converts keys of type []byte to string (because comparing []bytes behind any would panic on line 22).

The std package context says the following about keys:

A key can be any type that supports equality; packages should define keys as an unexported type to avoid collisions.

So context keys should never be restricted to strings by libraries, and both fiber and fasthttp correctly follow this and allow any for their abstractions over context.Context.


The requestid middleware cannot not be an exception to the any key rule. If you make this exception, you disallow the key type that is recommended by the standard library: type key int.


The revert should be reverted, but the condition should be changed to a simple nil check, and the default value should not be of an unexported type.

@ReneWerner87
Copy link
Member

Just because the methodic which is used inside supports all types, this does not have to be used outside for the key
How useful is it, for example, to use a struct as a key, which is also possible there?
Keys are usually strings or ints, but in this case strings make more sense and if numbers are to be used, this can also be done as a string number
By allowing only one type from the outside, we prevent possible errors or incorrect use

@benjajaja benjajaja mentioned this pull request Dec 2, 2023
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

🐛 [Bug]: Missing ContextKey in requestid middleware configuration
7 participants