getOffer return valid offer for header negotiation.
(header []byte, isAccepted func(spec, offer string, specParams headerParams) bool, offers ...string)
| 539 | |
| 540 | // getOffer return valid offer for header negotiation. |
| 541 | func getOffer(header []byte, isAccepted func(spec, offer string, specParams headerParams) bool, offers ...string) string { |
| 542 | if len(offers) == 0 { |
| 543 | return "" |
| 544 | } |
| 545 | if len(header) == 0 { |
| 546 | return offers[0] |
| 547 | } |
| 548 | |
| 549 | acceptedTypes := make([]acceptedType, 0, 8) |
| 550 | order := 0 |
| 551 | |
| 552 | // Parse header and get accepted types with their quality and specificity |
| 553 | // See: https://www.rfc-editor.org/rfc/rfc9110#name-content-negotiation-fields |
| 554 | forEachMediaRange(header, func(accept []byte) { |
| 555 | order++ |
| 556 | spec, quality := accept, 1.0 |
| 557 | var params headerParams |
| 558 | |
| 559 | if i := bytes.IndexByte(accept, ';'); i != -1 { |
| 560 | spec = accept[:i] |
| 561 | |
| 562 | // Optimized quality parsing |
| 563 | qIndex := i + 3 |
| 564 | if bytes.HasPrefix(accept[i:], semicolonQEquals) && bytes.IndexByte(accept[qIndex:], ';') == -1 { |
| 565 | if q, err := fasthttp.ParseUfloat(accept[qIndex:]); err == nil { |
| 566 | quality = q |
| 567 | } |
| 568 | } else { |
| 569 | params, _ = headerParamPool.Get().(headerParams) //nolint:errcheck // only contains headerParams |
| 570 | for k := range params { |
| 571 | delete(params, k) |
| 572 | } |
| 573 | fasthttp.VisitHeaderParams(accept[i:], func(key, value []byte) bool { |
| 574 | if len(key) == 1 && key[0] == 'q' { |
| 575 | if q, err := fasthttp.ParseUfloat(value); err == nil { |
| 576 | quality = q |
| 577 | } |
| 578 | return false |
| 579 | } |
| 580 | lowerKey := utils.UnsafeString(utilsbytes.UnsafeToLower(key)) |
| 581 | val, err := unescapeHeaderValue(value) |
| 582 | if err != nil { |
| 583 | return true |
| 584 | } |
| 585 | params[lowerKey] = val |
| 586 | return true |
| 587 | }) |
| 588 | } |
| 589 | |
| 590 | // Skip this accept type if quality is 0.0 |
| 591 | // See: https://www.rfc-editor.org/rfc/rfc9110#quality.values |
| 592 | if quality == 0.0 { |
| 593 | return |
| 594 | } |
| 595 | } |
| 596 | |
| 597 | spec = utils.TrimSpace(spec) |
| 598 |