| 766 | } |
| 767 | |
| 768 | int64_t |
| 769 | hpack_encode_header_block(HpackIndexingTable &indexing_table, uint8_t *out_buf, const size_t out_buf_len, HTTPHdr *hdr, |
| 770 | int32_t maximum_table_size) |
| 771 | { |
| 772 | uint8_t *cursor = out_buf; |
| 773 | const uint8_t *const out_buf_end = out_buf + out_buf_len; |
| 774 | |
| 775 | ink_assert(http_hdr_type_get(hdr->m_http) != HTTP_TYPE_UNKNOWN); |
| 776 | |
| 777 | // Update dynamic table size |
| 778 | if (maximum_table_size >= 0) { |
| 779 | indexing_table.update_maximum_size(maximum_table_size); |
| 780 | int64_t written = encode_dynamic_table_size_update(cursor, out_buf_end, maximum_table_size); |
| 781 | if (written == HPACK_ERROR_COMPRESSION_ERROR) { |
| 782 | return HPACK_ERROR_COMPRESSION_ERROR; |
| 783 | } |
| 784 | cursor += written; |
| 785 | } |
| 786 | |
| 787 | for (auto &field : *hdr) { |
| 788 | // Convert field name to lower case to follow HTTP2 spec |
| 789 | // This conversion is needed because WKSs in MIMEFields is old fashioned |
| 790 | std::string_view original_name = field.name_get(); |
| 791 | int name_len = original_name.size(); |
| 792 | ts::LocalBuffer<char> local_buffer(name_len); |
| 793 | char *lower_name = local_buffer.data(); |
| 794 | for (int i = 0; i < name_len; i++) { |
| 795 | lower_name[i] = ParseRules::ink_tolower(original_name[i]); |
| 796 | } |
| 797 | |
| 798 | std::string_view name{lower_name, static_cast<size_t>(name_len)}; |
| 799 | std::string_view value = field.value_get(); |
| 800 | |
| 801 | // Choose field representation (See RFC7541 7.1.3) |
| 802 | // - Authorization header obviously should not be indexed |
| 803 | // - Short Cookie header should not be indexed because of low entropy |
| 804 | HpackField field_type; |
| 805 | if ((value.size() < 20 && match(name.data(), name.length(), HPACK_HDR_FIELD_COOKIE.data(), HPACK_HDR_FIELD_COOKIE.length())) || |
| 806 | match(name.data(), name.length(), HPACK_HDR_FIELD_AUTHORIZATION.data(), HPACK_HDR_FIELD_AUTHORIZATION.length())) { |
| 807 | field_type = HpackField::NEVERINDEX_LITERAL; |
| 808 | } else { |
| 809 | field_type = HpackField::INDEXED_LITERAL; |
| 810 | } |
| 811 | |
| 812 | HpackHeaderField header{name, value}; |
| 813 | const HpackLookupResult result = indexing_table.lookup(header); |
| 814 | |
| 815 | int64_t written = 0; |
| 816 | switch (result.match_type) { |
| 817 | case HpackMatch::NONE: |
| 818 | written = encode_literal_header_field_with_new_name(cursor, out_buf_end, header, indexing_table, field_type); |
| 819 | break; |
| 820 | case HpackMatch::NAME: |
| 821 | written = |
| 822 | encode_literal_header_field_with_indexed_name(cursor, out_buf_end, header, result.index, indexing_table, field_type); |
| 823 | break; |
| 824 | case HpackMatch::EXACT: |
| 825 | written = encode_indexed_header_field(cursor, out_buf_end, result.index); |