()
| 656 | } |
| 657 | |
| 658 | private buildHeaderValue(): void { |
| 659 | const p = this.llparse; |
| 660 | const span = this.span; |
| 661 | const callback = this.callback; |
| 662 | const n = (name: string): Match => this.node<Match>(name); |
| 663 | |
| 664 | const fallback = this.resetHeaderState('header_value'); |
| 665 | |
| 666 | n('header_value_discard_ws') |
| 667 | .match([ ' ', '\t' ], n('header_value_discard_ws')) |
| 668 | .match('\r', n('header_value_discard_ws_almost_done')) |
| 669 | .match('\n', this.testLenientFlags(LENIENT_FLAGS.OPTIONAL_CR_BEFORE_LF, { |
| 670 | 1: n('header_value_discard_lws'), |
| 671 | }, p.error(ERROR.INVALID_HEADER_TOKEN, 'Invalid header value char'))) |
| 672 | .otherwise(span.headerValue.start(n('header_value_start'))); |
| 673 | |
| 674 | n('header_value_discard_ws_almost_done') |
| 675 | .match('\n', n('header_value_discard_lws')) |
| 676 | .otherwise( |
| 677 | this.testLenientFlags(LENIENT_FLAGS.HEADERS, { |
| 678 | 1: n('header_value_discard_lws'), |
| 679 | }, p.error(ERROR.STRICT, 'Expected LF after CR')), |
| 680 | ); |
| 681 | |
| 682 | const onHeaderValueComplete = this.invokePausable( |
| 683 | 'on_header_value_complete', ERROR.CB_HEADER_VALUE_COMPLETE, n('header_field_start'), |
| 684 | ); |
| 685 | |
| 686 | const emptyContentLengthError = p.error( |
| 687 | ERROR.INVALID_CONTENT_LENGTH, 'Empty Content-Length'); |
| 688 | const checkContentLengthEmptiness = this.load('header_state', { |
| 689 | [HEADER_STATE.CONTENT_LENGTH]: emptyContentLengthError, |
| 690 | }, this.setHeaderFlags( |
| 691 | this.emptySpan(span.headerValue, onHeaderValueComplete))); |
| 692 | |
| 693 | n('header_value_discard_lws') |
| 694 | .match([ ' ', '\t' ], this.testLenientFlags(LENIENT_FLAGS.HEADERS, { |
| 695 | 1: n('header_value_discard_ws'), |
| 696 | }, p.error(ERROR.INVALID_HEADER_TOKEN, 'Invalid header value char'))) |
| 697 | .otherwise(checkContentLengthEmptiness); |
| 698 | |
| 699 | // Multiple `Transfer-Encoding` headers should be treated as one, but with |
| 700 | // values separate by a comma. |
| 701 | // |
| 702 | // See: https://tools.ietf.org/html/rfc7230#section-3.2.2 |
| 703 | const toTransferEncoding = this.unsetFlag( |
| 704 | FLAGS.CHUNKED, |
| 705 | 'header_value_te_chunked'); |
| 706 | |
| 707 | // Once chunked has been selected, no other encoding is possible in requests |
| 708 | // https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1 |
| 709 | const forbidAfterChunkedInRequest = (otherwise: Node) => { |
| 710 | return this.load('type', { |
| 711 | [TYPE.REQUEST]: this.testLenientFlags(LENIENT_FLAGS.TRANSFER_ENCODING, { |
| 712 | 0: span.headerValue.end().skipTo( |
| 713 | p.error(ERROR.INVALID_TRANSFER_ENCODING, 'Invalid `Transfer-Encoding` header value'), |
| 714 | ), |
| 715 | }).otherwise(otherwise), |
no test coverage detected