forEachMediaRange parses an Accept or Content-Type header, calling functor on each media range. See: https://www.rfc-editor.org/rfc/rfc9110#name-content-negotiation-fields
(header []byte, functor func([]byte))
| 483 | // on each media range. |
| 484 | // See: https://www.rfc-editor.org/rfc/rfc9110#name-content-negotiation-fields |
| 485 | func forEachMediaRange(header []byte, functor func([]byte)) { |
| 486 | hasDQuote := bytes.IndexByte(header, '"') != -1 |
| 487 | |
| 488 | for len(header) > 0 { |
| 489 | n := 0 |
| 490 | header = utils.TrimLeft(header, ' ') |
| 491 | quotes := 0 |
| 492 | escaping := false |
| 493 | |
| 494 | if hasDQuote { |
| 495 | // Complex case. We need to keep track of quotes and quoted-pairs (i.e., characters escaped with \ ) |
| 496 | loop: |
| 497 | for n < len(header) { |
| 498 | switch header[n] { |
| 499 | case ',': |
| 500 | if quotes%2 == 0 { |
| 501 | break loop |
| 502 | } |
| 503 | case '"': |
| 504 | if !escaping { |
| 505 | quotes++ |
| 506 | } |
| 507 | case '\\': |
| 508 | if quotes%2 == 1 { |
| 509 | escaping = !escaping |
| 510 | } |
| 511 | default: |
| 512 | // all other characters are ignored |
| 513 | } |
| 514 | n++ |
| 515 | } |
| 516 | } else { |
| 517 | // Simple case. Just look for the next comma. |
| 518 | if n = bytes.IndexByte(header, ','); n == -1 { |
| 519 | n = len(header) |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | functor(header[:n]) |
| 524 | |
| 525 | if n >= len(header) { |
| 526 | return |
| 527 | } |
| 528 | header = header[n+1:] |
| 529 | } |
| 530 | } |
| 531 | |
| 532 | // Pool for headerParams instances. The headerParams object *must* |
| 533 | // be cleared before being returned to the pool. |