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

ctx.Accepts() quality values and specificity #2387

Closed
sixcolors opened this issue Mar 27, 2023 · 18 comments · Fixed by #2486
Closed

ctx.Accepts() quality values and specificity #2387

sixcolors opened this issue Mar 27, 2023 · 18 comments · Fixed by #2486

Comments

@sixcolors
Copy link
Member

sixcolors commented Mar 27, 2023

This issue is a follow on to #2386 and #2383

          > i have reversed the loop for all accepts methods, so that the arguments are passed first and then the header values are checked

@efectn @sixcolors @derkan do you agree that this was the right thing to do ? the logic of express leading to the outputs implies this to me

@ReneWerner87 good job, this make the existing test cases behave as expected.

Reading the ctx.Accepts docs my understanding is that:

The Accepts function in the GoFiber context is used to check if the specified extensions or content types are acceptable based on the request's Accept HTTP header.

It takes one or more strings as input arguments representing the content types or extensions and returns the most preferred one based on the Accept header.

Therefore, if my understanding of the intent of the Accept function is correct, the following should hold true:

c.Request().Header.Set(HeaderAccept, "text/plain, application/json;q=0.5, text/html, */*;q=0.1")
	utils.AssertEqual(t, "txt", c.Accepts("json", "txt"))

	c.Request().Header.Set(HeaderAccept, "text/plain;charset=UTF-8;q=0.8,text/plain;charset=US-ASCII;q=0.4,text/plain;q=0.2,text/html")
	utils.AssertEqual(t, "text/plain;charset=US-ASCII", c.Accepts("text/plain", "text/plain;charset=US-ASCII"))
	utils.AssertEqual(t, "text/plain;charset=UTF-8", c.Accepts("text/plain;charset=US-ASCII", "text/plain;charset=UTF-8", "text/plain"))
	utils.AssertEqual(t, "text/html", c.Accepts("text/plain", "text/html"))

For example: It is possible that a browser could use the Accept header with the value text/plain;charset=UTF-8;q=0.8,text/plain;charset=US-ASCII;q=0.4,text/html. While text/html is typically assumed to have a default quality value of 1 if not specified, the browser could still explicitly specify it with a quality value of 1, as it is allowed by the HTTP specifications.

Furthermore, the browser could be indicating to the server that it prefers text/plain with a charset of UTF-8 over text/plain with a charset of US-ASCII, but it is still willing to accept both with different quality values. This could be useful in scenarios where the server has content in both character sets and wants to serve the content that is preferred by the client.

However, it is worth noting that the Accept header sent by the browser may vary depending on the user agent and its configuration. Therefore, it is important for the server to properly parse and interpret the Accept header to determine the preferred content type for the client.

Background/Refs

The relevant RFCs for the HTTP/1.1 specification are RFC 7231 and RFC 7232.

Regarding the q parameter and its default value of 1, Section 5.3.1 of RFC 7231 states:

If no "*" is present in an Accept header field, then all
media types are acceptable, assuming that any media range
syntax is understood by the recipient.  If an Accept header
field is present, and if the server cannot send a response
which is acceptable according to the combined Accept field
value, then the server SHOULD send a 406 (not acceptable)
response.

[...]

Each media-range might be followed by one or more accept-
params, beginning with the "q" parameter for indicating a
relative quality factor.  The first "q" parameter (if any)
separates the media-range parameter(s) from the accept-
params.  Quality factors allow the user or user agent to
indicate the relative degree of preference for that media-
type, on a scale of 0 to 1.

Regarding the order of the MIME types in the Accept header, Section 5.3.2 of RFC 7231 states:

The order in which the content-codings are listed in the
header field is significant.  Typically, the first encoding
that is applied is the one listed as the first content-coding;
subsequent encodings are applied in the order listed.  The
order of charset values in the header field is significant,
whereas the order of language-tag values is not.  Specifically,
it does not mean that the first charset listed is preferred,
but rather that it represents the default charset if none is
otherwise specified.

An "Accept" header field can be present in a request to
indicate the formats that are acceptable for the response.
Field content negotiation is described in Section 5.3.  An
origin server that is capable of generating a response
message which is subject to content negotiation MAY vary the
response that is sent, based on the value of the Accept header
field supplied in the request.  For example, the server might
include a different Content-Type header field, or might
omit the content entirely.

The order in which the media type values are listed is
significant.  The first media type that is listed as acceptable
determines the format of the entity-body that is returned.  A
more precise or generally usable media type listed earlier in
the Accept header field SHOULD be given preference over those
that are listed later.

MDN on Quality Values https://developer.mozilla.org/en-US/docs/Glossary/Quality_values

The importance of a value is marked by the suffix ';q=' immediately followed by a value between 0 and 1 included, with up to three decimal digits, the highest value denoting the highest priority. When not present, the default value is 1.

[Examples](https://developer.mozilla.org/en-US/docs/Glossary/Quality_values#examples)
The following syntax

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

indicates the order of priority:

[...]

If there is no priority defined for the first two values, the order in the list is irrelevant. Nevertheless, with the same quality, more specific values have priority over less specific ones:

text/html;q=0.8,text/*;q=0.8,*/*;q=0.8

Value	Priority
text/html	0.8 (but totally specified)
text/*	0.8 (partially specified)
*/*	0.8 (not specified)

Some syntax, like the one of Accept, allow additional specifiers like text/html;level=1. These increase the specificity of the value. Their use is extremely rare.

Originally posted by @sixcolors in #2386 (comment)

@sixcolors
Copy link
Member Author

Need to checkout express and other frameworks handling of q value and specificity, the code to solve this that immediately comes to mind will have impacts on performance and memory use.

Want to make sure🧃worth🪗

@sixcolors
Copy link
Member Author

@ReneWerner87
Copy link
Member

yes will definitely have a performance impact
since we have to go all the way to the end and remember all the values, then the other way which was used before makes sense again

then you go through the header values and not the arguments

@ReneWerner87
Copy link
Member

we could also split the header string and sort it so that we achieve the prioritization, but then we have one more allocation due to the created slice

but maybe this can be done with byte buffer pool or it is not important because it is only a temporary allocation

@sixcolors
Copy link
Member Author

ref x/net/http discussion on content negotiation golang/go#19307

@sixcolors
Copy link
Member Author

ref mdn docs on content negotiation https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation

@sixcolors
Copy link
Member Author

ref RFC 9110 HTTP Semantics 12.3. Request Content Negotiation

@sixcolors
Copy link
Member Author

sixcolors commented Mar 27, 2023

Note https://www.rfc-editor.org/rfc/rfc9110.html#field.accept which shows:

Accept: audio/*; q=0.2, audio/basic

is interpreted as "I prefer audio/basic, but send me any audio type if it is the best available after an 80% markdown in quality".

So that means we should prioritize sort by q value, and that the header order only matters if q is the same, or is unspecified in which case it is assumed to be 1.0

It also goes on to talk about specificity.

@sixcolors
Copy link
Member Author

@ReneWerner87

I'm working on fully cloning the express Accepts function, however I am seeing a behaviour difference from the assertions in Test_Ctx_Accepts in Fiber vs Express, specifically:

	c.Request().Header.Set(HeaderAccept, "text/html, application/json")
	utils.AssertEqual(t, "text/*", c.Accepts("text/*"))

Results in:

--- FAIL: Test_Ctx_Accepts (0.01s)
    /Users/sixcolors/Documents/GitHub/fiber/ctx_test.go:58: 
        Test:       Test_Ctx_Accepts
        Trace:      ctx_test.go:58
        Expect:     text/*     (string)
        Result:                (string)
FAIL
FAIL	github.com/gofiber/fiber/v2	0.029s
FAIL

The express / js function in the following sample

const express = require('express');
var accepts = require('accepts')
var Negotiator = require('negotiator')

const app = express();
const port = 3000;

const availableMediaTypes = ['text/*'];

app.use(express.json());

app.get('/', (req, res) => {
    negotiator = new Negotiator(req);
    console.log(negotiator.mediaTypes(availableMediaTypes));

    var accept = accepts(req)

    console.log(accept.types(availableMediaTypes) ? 'accepts' : 'does not accept');

    req.accepts(availableMediaTypes) ? console.log('express accepts') : console.log('express does not accept');
    res.send('Hello, world!');
});

app.post('/data', (req, res) => {
    if (req.accepts('json')) {
        res.json({ message: 'Received JSON data' });
    } else if (req.accepts('xml')) {
        res.send('<message>Received XML data</message>');
    } else {
        res.status(406).send('Not Acceptable');
    }
});

app.listen(port, () => {
    console.log(`Server listening on port ${port}`);
});
curl -v -H'Accept: text/html, application/json' http://localhost:3000/

Gives the console output:

[]
does not accept
express does not accept

@sixcolors
Copy link
Member Author

sixcolors commented May 28, 2023

Working on code pre-PR on this branch: https://github.com/sixcolors/fiber/tree/2387-ctx-accepts-quality-values-and-specificity

internal/negotiator package inspired by https://github.com/jshttp/negotiator which is what backs accepts, which is what express uses.

Initial Benchmark_Ctx_Accepts results

master:

goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24         	 4540623	       258.9 ns/op	       0 B/op	       0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24  	 4152066	       288.5 ns/op	       0 B/op	       0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24         	 5991992	       201.4 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	github.com/gofiber/fiber/v2	4.385s
goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24         	 4539039	       265.7 ns/op	       0 B/op	       0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24  	 4421416	       271.6 ns/op	       0 B/op	       0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24         	 6057902	       200.2 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	github.com/gofiber/fiber/v2	4.404s

2387-ctx-accepts-quality-values-and-specificity

goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24         	  224628	      5087 ns/op	    2136 B/op	      48 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24  	  188163	      6302 ns/op	    2632 B/op	      60 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24         	  196066	      6226 ns/op	    2632 B/op	      60 allocs/op
PASS
ok  	github.com/gofiber/fiber/v2	3.771s
goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24         	  228782	      5086 ns/op	    2136 B/op	      48 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24  	  186030	      6339 ns/op	    2632 B/op	      60 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24         	  185474	      6242 ns/op	    2632 B/op	      60 allocs/op
PASS
ok  	github.com/gofiber/fiber/v2	3.724s

@sixcolors
Copy link
Member Author

First round of improving Benchmark_Ctx_Accepts results

2387-ctx-accepts-quality-values-and-specificity

goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24         	  297885	      3920 ns/op	    1608 B/op	      36 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24  	  215049	      5191 ns/op	    2104 B/op	      48 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24         	  231255	      5119 ns/op	    2104 B/op	      48 allocs/op
PASS
ok  	github.com/gofiber/fiber/v2	3.658s
goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24         	  293320	      3920 ns/op	    1608 B/op	      36 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24  	  222104	      5221 ns/op	    2104 B/op	      48 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24         	  233214	      5167 ns/op	    2104 B/op	      48 allocs/op
PASS
ok  	github.com/gofiber/fiber/v2	3.703s

@sixcolors
Copy link
Member Author

Second round of improving Benchmark_Ctx_Accepts results

2387-ctx-accepts-quality-values-and-specificity

goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24         	  316141	      3569 ns/op	    1472 B/op	      33 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24  	  254371	      4868 ns/op	    1968 B/op	      45 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24         	  242386	      4798 ns/op	    1968 B/op	      45 allocs/op
PASS
ok  	github.com/gofiber/fiber/v2	3.705s
goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24         	  324574	      3570 ns/op	    1472 B/op	      33 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24  	  248742	      4840 ns/op	    1968 B/op	      45 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24         	  244814	      4759 ns/op	    1968 B/op	      45 allocs/op
PASS
ok  	github.com/gofiber/fiber/v2	3.703s

@sixcolors
Copy link
Member Author

sixcolors commented May 30, 2023

Okay I modified helpers.go getOffer to consider q values and specificity, it's much faster than my port of jshttp/negotiator

branch: https://github.com/sixcolors/fiber/tree/2387-ctx-accepts-get-offer-q-and-specificity

Benchmark_Ctx_Accepts results

master

goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts
Benchmark_Ctx_Accepts/run-[]string{".xml"}
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            4718739               248.1 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            4823197               247.4 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            4701520               246.7 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            4730023               246.4 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     4619944               258.9 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     4630816               259.1 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     4634599               259.9 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     4590058               260.3 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             6283534               193.6 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             6131330               193.5 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             6143854               193.3 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             6021658               197.3 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsCharsets
Benchmark_Ctx_AcceptsCharsets-24                                                        13285575                89.29 ns/op            0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                        12894056                88.99 ns/op            0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                        13402732                89.01 ns/op            0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                        13217695                89.30 ns/op            0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsEncodings
Benchmark_Ctx_AcceptsEncodings-24                                                       10083732               117.9 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                       10080361               117.8 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                       10078560               118.9 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                       10137867               117.3 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsLanguages
Benchmark_Ctx_AcceptsLanguages-24                                                       13242565                88.78 ns/op            0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                       13228040                89.09 ns/op            0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                       13319239                88.50 ns/op            0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                       13211436                88.96 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/gofiber/fiber/v2     32.674s

2387-ctx-accepts-get-offer-q-and-specificity

goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts
Benchmark_Ctx_Accepts/run-[]string{".xml"}
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            1523955               781.3 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            1509940               783.0 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            1535641               786.1 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            1518062               785.9 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     1320118               911.8 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     1326496               904.1 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     1322679               902.0 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     1332966               905.7 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             1703186               704.0 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             1700726               703.4 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             1697983               724.6 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             1703149               715.7 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_AcceptsCharsets
Benchmark_Ctx_AcceptsCharsets-24                                                         2777720               427.8 ns/op            96 B/op          2 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                         2841889               422.0 ns/op            96 B/op          2 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                         2825397               423.1 ns/op            96 B/op          2 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                         2842117               424.3 ns/op            96 B/op          2 allocs/op
Benchmark_Ctx_AcceptsEncodings
Benchmark_Ctx_AcceptsEncodings-24                                                        1747647               686.6 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                        1748542               680.2 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                        1748302               687.9 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                        1758098               685.1 ns/op           224 B/op          3 allocs/op
Benchmark_Ctx_AcceptsLanguages
Benchmark_Ctx_AcceptsLanguages-24                                                        1000000              1065 ns/op             480 B/op          4 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                        1000000              1066 ns/op             480 B/op          4 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                        1000000              1061 ns/op             480 B/op          4 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                        1000000              1062 ns/op             480 B/op          4 allocs/op
PASS
ok      github.com/gofiber/fiber/v2     42.648s

@ReneWerner87
Copy link
Member

ReneWerner87 commented May 30, 2023

I have a solution in my mind with the current getOffer method without allocations.
But unfortunately not much time, will try it this or next week after my daily business.

@sixcolors
Copy link
Member Author

sixcolors commented May 30, 2023

I have a solution in my mind with the current getOffer method without allocations.
But unfortunately not much time, will try it this or next week after my daily business.

Actually, I thought of a way to do it.... zero allocations:

2387-ctx-accepts-get-offer-q-and-specificity

edited: I further optimized the sort algo

goos: darwin
goarch: amd64
pkg: github.com/gofiber/fiber/v2
cpu: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz
Benchmark_Ctx_Accepts
Benchmark_Ctx_Accepts/run-[]string{".xml"}
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            2682642               444.9 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            2776354               441.5 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            2707746               442.8 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{".xml"}-24            2711558               435.8 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     2141143               565.3 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     2128267               559.7 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     2091757               567.7 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"json",_"xml"}-24     2131636               559.6 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             3336694               360.9 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             3337960               359.7 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             3291346               362.4 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_Accepts/run-[]string{"application/json",_"application/xml"}-24             3306898               359.3 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsCharsets
Benchmark_Ctx_AcceptsCharsets-24                                                         5187949               226.1 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                         5308161               227.7 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                         5307020               228.8 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsCharsets-24                                                         5356268               225.0 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsEncodings
Benchmark_Ctx_AcceptsEncodings-24                                                        3701896               326.2 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                        3664098               326.1 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                        3681938               325.8 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsEncodings-24                                                        3667440               326.8 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsLanguages
Benchmark_Ctx_AcceptsLanguages-24                                                        2441028               488.1 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                        2457464               488.6 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                        2418184               488.0 ns/op             0 B/op          0 allocs/op
Benchmark_Ctx_AcceptsLanguages-24                                                        2451204               489.4 ns/op             0 B/op          0 allocs/op
PASS
ok      github.com/gofiber/fiber/v2     38.648s

@ReneWerner87
Copy link
Member

But still much slower in some cases.
Will look at it in the next days.

@sixcolors
Copy link
Member Author

sixcolors commented May 30, 2023

But still much slower in some cases.
Will look at it in the next days.

True, however, now the function follows the spec for Content Negotiation Fields. I'll also look at those cases where it's much slower to see what I can do for them.

I'm not 100% sure I can make them as fast as they were while still being 'correct'; the benchmarks are an almost ideal case for the old implementation. Open to any help/suggestions you may have.

@sixcolors sixcolors self-assigned this May 30, 2023
@sixcolors
Copy link
Member Author

sixcolors commented May 30, 2023

But still much slower in some cases.
Will look at it in the next days.

True, however, now the function follows the spec for Content Negotiation Fields. I'll also look at those cases where it's much slower to see what I can do for them.

I'm not 100% sure I can make them as fast as they were while still being 'correct'; the benchmarks are an almost ideal case for the old implementation. Open to any help/suggestions you may have.

I should say it follows more of the spec, as media range parameters aren't supported in the master or #2486 implementations.

eg

Accept: text/*, text/plain, text/plain;format=flowed, */*

text/plain;format=flowed
text/plain
text/*
*/*

The ctx.Accepts() func does not provide for checking parameters. Doing so would likely incur undesirable performance and memory penalties. Thoughts?

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

Successfully merging a pull request may close this issue.

2 participants