| /** @file |
| |
| [RFC 7541] HPACK: Header Compression for HTTP/2 |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include "tscore/ink_platform.h" |
| #include "tscore/Diags.h" |
| #include "HTTP.h" |
| #include "../hdrs/XPACK.h" |
| |
| #include <deque> |
| #include <string_view> |
| |
| // It means that any header field can be compressed/decompressed by ATS |
| const static int HPACK_ERROR_COMPRESSION_ERROR = -1; |
| const static int HPACK_ERROR_SIZE_EXCEEDED_ERROR = -2; |
| |
| enum class HpackField { |
| INDEX, // [RFC 7541] 6.1. Indexed Header Field Representation |
| INDEXED_LITERAL, // [RFC 7541] 6.2.1. Literal Header Field with Incremental Indexing |
| NOINDEX_LITERAL, // [RFC 7541] 6.2.2. Literal Header Field without Indexing |
| NEVERINDEX_LITERAL, // [RFC 7541] 6.2.3. Literal Header Field never Indexed |
| TABLESIZE_UPDATE, // [RFC 7541] 6.3. Dynamic Table Size Update |
| }; |
| |
| enum class HpackIndex { |
| NONE, |
| STATIC, |
| DYNAMIC, |
| }; |
| |
| enum class HpackMatch { |
| NONE, |
| NAME, |
| EXACT, |
| }; |
| |
| // Result of looking for a header field in IndexingTable |
| struct HpackLookupResult { |
| uint32_t index = 0; |
| HpackIndex index_type = HpackIndex::NONE; |
| HpackMatch match_type = HpackMatch::NONE; |
| }; |
| |
| struct HpackHeaderField { |
| std::string_view name; |
| std::string_view value; |
| }; |
| |
| class MIMEFieldWrapper |
| { |
| public: |
| MIMEFieldWrapper(MIMEField *f, HdrHeap *hh, MIMEHdrImpl *impl) : _field(f), _heap(hh), _mh(impl) {} |
| void |
| name_set(const char *name, int name_len) |
| { |
| _field->name_set(_heap, _mh, name, name_len); |
| } |
| |
| void |
| value_set(const char *value, int value_len) |
| { |
| _field->value_set(_heap, _mh, value, value_len); |
| } |
| |
| const char * |
| name_get(int *length) const |
| { |
| return _field->name_get(length); |
| } |
| |
| const char * |
| value_get(int *length) const |
| { |
| return _field->value_get(length); |
| } |
| |
| const MIMEField * |
| field_get() const |
| { |
| return _field; |
| } |
| |
| private: |
| MIMEField *_field; |
| HdrHeap *_heap; |
| MIMEHdrImpl *_mh; |
| }; |
| |
| // [RFC 7541] 2.3.2. Dynamic Table |
| class HpackDynamicTable |
| { |
| public: |
| explicit HpackDynamicTable(uint32_t size); |
| ~HpackDynamicTable(); |
| |
| // noncopyable |
| HpackDynamicTable(HpackDynamicTable &) = delete; |
| HpackDynamicTable &operator=(const HpackDynamicTable &) = delete; |
| |
| const MIMEField *get_header_field(uint32_t index) const; |
| void add_header_field(const HpackHeaderField &header); |
| |
| HpackLookupResult lookup(const HpackHeaderField &header) const; |
| uint32_t maximum_size() const; |
| uint32_t size() const; |
| void update_maximum_size(uint32_t new_size); |
| |
| uint32_t length() const; |
| |
| private: |
| void _evict_overflowed_entries(); |
| void _mime_hdr_gc(); |
| |
| uint32_t _current_size = 0; |
| uint32_t _maximum_size = 0; |
| |
| MIMEHdr *_mhdr = nullptr; |
| MIMEHdr *_mhdr_old = nullptr; |
| std::deque<MIMEField *> _headers; |
| }; |
| |
| // [RFC 7541] 2.3. Indexing Table |
| class HpackIndexingTable |
| { |
| public: |
| explicit HpackIndexingTable(uint32_t size) : _dynamic_table(size){}; |
| ~HpackIndexingTable() {} |
| |
| // noncopyable |
| HpackIndexingTable(HpackIndexingTable &) = delete; |
| HpackIndexingTable &operator=(const HpackIndexingTable &) = delete; |
| |
| HpackLookupResult lookup(const HpackHeaderField &header) const; |
| int get_header_field(uint32_t index, MIMEFieldWrapper &header_field) const; |
| |
| void add_header_field(const HpackHeaderField &header); |
| uint32_t maximum_size() const; |
| uint32_t size() const; |
| void update_maximum_size(uint32_t new_size); |
| |
| private: |
| HpackDynamicTable _dynamic_table; |
| }; |
| |
| // Low level interfaces |
| int64_t encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index); |
| int64_t encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const uint8_t *buf_end, const HpackHeaderField &header, |
| uint32_t index, HpackIndexingTable &indexing_table, HpackField type); |
| int64_t encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t *buf_end, const HpackHeaderField &header, |
| HpackIndexingTable &indexing_table, HpackField type); |
| |
| int64_t decode_indexed_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end, |
| HpackIndexingTable &indexing_table); |
| int64_t decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end, |
| HpackIndexingTable &indexing_table); |
| int64_t update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_end, HpackIndexingTable &indexing_table, |
| uint32_t maximum_table_size); |
| |
| // High level interfaces |
| typedef HpackIndexingTable HpackHandle; |
| int64_t hpack_decode_header_block(HpackHandle &handle, HTTPHdr *hdr, const uint8_t *in_buf, const size_t in_buf_len, |
| uint32_t max_header_size, uint32_t maximum_table_size); |
| int64_t hpack_encode_header_block(HpackHandle &handle, uint8_t *out_buf, const size_t out_buf_len, HTTPHdr *hdr, |
| int32_t maximum_table_size = -1); |
| int32_t hpack_get_maximum_table_size(HpackHandle &handle); |