[ 
https://issues.apache.org/jira/browse/TS-4092?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15153615#comment-15153615
 ] 

ASF GitHub Bot commented on TS-4092:
------------------------------------

Github user masaori335 commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/460#discussion_r53417506
  
    --- Diff: proxy/http2/HTTP2.cc ---
    @@ -484,246 +498,162 @@ convert_from_2_to_1_1_header(HTTPHdr *headers)
       return PARSE_DONE;
     }
     
    -static int64_t
    -http2_write_header_field(uint8_t *out, const uint8_t *end, 
MIMEFieldWrapper &header, Http2IndexingTable &indexing_table)
    -{
    -  HpackFieldType field_type = HPACK_FIELD_INDEXED_LITERAL;
    -
    -  // Cookie less that 20 bytes and Authorization are never indexed
    -  // This policy is refer to Firefox and nghttp2
    -  int name_len = 0, value_len = 0;
    -  const char *name = header.name_get(&name_len);
    -  header.value_get(&value_len);
    -  if ((ptr_len_casecmp(name, name_len, MIME_FIELD_COOKIE, MIME_LEN_COOKIE) 
== 0 && value_len < 20) ||
    -      (ptr_len_casecmp(name, name_len, MIME_FIELD_AUTHORIZATION, 
MIME_LEN_AUTHORIZATION) == 0)) {
    -    field_type = HPACK_FIELD_NEVERINDEX_LITERAL;
    -  }
    -
    -  // TODO Enable to configure selecting header field representation
    +void
    +http2_convert_header_from_1_1_to_2(HTTPHdr *headers)
    +{
    +  HTTPHdr tmp;
    +  tmp.create(http_hdr_type_get(headers->m_http));
    +  tmp.copy(headers);
    +  headers->fields_clear();
    +
    +  if (http_hdr_type_get(tmp.m_http) == HTTP_TYPE_RESPONSE) {
    +    char status_str[HTTP2_LEN_STATUS_VALUE_STR + 1];
    +    snprintf(status_str, sizeof(status_str), "%d", tmp.status_get());
    +
    +    // Add ':status' header field
    +    MIMEField *status_field = headers->field_create(HTTP2_VALUE_STATUS, 
HTTP2_LEN_STATUS);
    +    status_field->value_set(headers->m_heap, headers->m_mime, status_str, 
HTTP2_LEN_STATUS_VALUE_STR);
    +    headers->field_attach(status_field);
    +
    +    MIMEFieldIter field_iter;
    +    for (MIMEField *field = tmp.iter_get_first(&field_iter); field != 
NULL; field = tmp.iter_get_next(&field_iter)) {
    +      // Intermediaries SHOULD remove connection-specific header fields.
    +      const char *name;
    +      int name_len;
    +      const char *value;
    +      int value_len;
    +      name = field->name_get(&name_len);
    +      if ((name_len == MIME_LEN_CONNECTION && strncasecmp(name, 
MIME_FIELD_CONNECTION, name_len) == 0) ||
    +          (name_len == MIME_LEN_KEEP_ALIVE && strncasecmp(name, 
MIME_FIELD_KEEP_ALIVE, name_len) == 0) ||
    +          (name_len == MIME_LEN_PROXY_CONNECTION && strncasecmp(name, 
MIME_FIELD_PROXY_CONNECTION, name_len) == 0) ||
    +          (name_len == MIME_LEN_TRANSFER_ENCODING && strncasecmp(name, 
MIME_FIELD_TRANSFER_ENCODING, name_len) == 0) ||
    +          (name_len == MIME_LEN_UPGRADE && strncasecmp(name, 
MIME_FIELD_UPGRADE, name_len) == 0)) {
    +        continue;
    +      }
     
    -  const Http2LookupIndexResult &result = indexing_table.get_index(header);
    -  if (result.index > 0) {
    -    if (result.value_is_indexed) {
    -      return encode_indexed_header_field(out, end, result.index);
    -    } else {
    -      return encode_literal_header_field_with_indexed_name(out, end, 
header, result.index, indexing_table, field_type);
    +      MIMEField *newfield;
    +      name = field->name_get(&name_len);
    +      newfield = headers->field_create(name, name_len);
    +      value = field->value_get(&value_len);
    +      newfield->value_set(headers->m_heap, headers->m_mime, value, 
value_len);
    +      tmp.field_delete(field);
    +      headers->field_attach(newfield);
    +      // Set sensitive flag (See RFC7541 7.1.3)
    +      // - Authorization header obviously should not be indexed
    +      // - Short Cookie header should not be indexed because of low entropy
    +      if ((ptr_len_casecmp(name, name_len, MIME_FIELD_COOKIE, 
MIME_LEN_COOKIE) == 0 && value_len < 20) ||
    +          (ptr_len_casecmp(name, name_len, MIME_FIELD_AUTHORIZATION, 
MIME_LEN_AUTHORIZATION) == 0)) {
    +        newfield->m_sensitive = 1;
    +      }
         }
    -  } else {
    -    return encode_literal_header_field_with_new_name(out, end, header, 
indexing_table, field_type);
       }
    +  tmp.destroy();
     }
     
     int64_t
    -http2_write_psuedo_headers(HTTPHdr *in, uint8_t *out, uint64_t out_len, 
Http2IndexingTable &indexing_table)
    +http2_encode_header_blocks(HTTPHdr *in, uint8_t *out, uint32_t out_len, 
HpackHandle &handle)
     {
    -  uint8_t *p = out;
    -  uint8_t *end = out + out_len;
    -  int64_t len;
    -
    -  ink_assert(http_hdr_type_get(in->m_http) != HTTP_TYPE_UNKNOWN);
    -
    -  // TODO Check whether buffer size is enough
    -
    -  // Set psuedo header
    -  if (http_hdr_type_get(in->m_http) == HTTP_TYPE_RESPONSE) {
    -    char status_str[HPACK_LEN_STATUS_VALUE_STR + 1];
    -    snprintf(status_str, sizeof(status_str), "%d", in->status_get());
    -
    -    // Add 'Status:' dummy header field
    -    MIMEField *status_field = mime_field_create(in->m_heap, 
in->m_http->m_fields_impl);
    -    mime_field_name_value_set(in->m_heap, in->m_mime, status_field, -1, 
HPACK_VALUE_STATUS, HPACK_LEN_STATUS, status_str,
    -                              HPACK_LEN_STATUS_VALUE_STR, 0, 
HPACK_LEN_STATUS + HPACK_LEN_STATUS_VALUE_STR, true);
    -    mime_hdr_field_attach(in->m_mime, status_field, 1, NULL);
    -
    -    // Encode psuedo headers by HPACK
    -    MIMEFieldWrapper header(status_field, in->m_heap, 
in->m_http->m_fields_impl);
    -
    -    len = http2_write_header_field(p, end, header, indexing_table);
    -    if (len == -1)
    -      return -1;
    -    p += len;
    -
    -    // Remove dummy header field
    -    in->field_delete(HPACK_VALUE_STATUS, HPACK_LEN_STATUS);
    -  }
    -
    -  return p - out;
    -}
    -
    -int64_t
    -http2_write_header_fragment(HTTPHdr *in, MIMEFieldIter &field_iter, 
uint8_t *out, uint64_t out_len,
    -                            Http2IndexingTable &indexing_table, bool &cont)
    -{
    -  uint8_t *p = out;
    -  uint8_t *end = out + out_len;
    -  int64_t len;
    -
    -  ink_assert(http_hdr_type_get(in->m_http) != HTTP_TYPE_UNKNOWN);
    -  ink_assert(in);
    -
    -  // TODO Get a index value from the tables for the header field, and then
    -  // choose a representation type.
    -  // TODO Each indexing types per field should be passed by a caller, 
HTTP/2
    -  // implementation.
    -
    -  // Get first header field which is required encoding
    -  MIMEField *field;
    -  if (!field_iter.m_block) {
    -    field = in->iter_get_first(&field_iter);
    -  } else {
    -    field = in->iter_get(&field_iter);
    -  }
    -
    -  // Set mime headers
    -  cont = false;
    -  for (; field != NULL; field = in->iter_get_next(&field_iter)) {
    -    // Intermediaries SHOULD remove connection-specific header fields.
    -    int name_len;
    -    const char *name = field->name_get(&name_len);
    -    if ((name_len == MIME_LEN_CONNECTION && strncasecmp(name, 
MIME_FIELD_CONNECTION, name_len) == 0) ||
    -        (name_len == MIME_LEN_KEEP_ALIVE && strncasecmp(name, 
MIME_FIELD_KEEP_ALIVE, name_len) == 0) ||
    -        (name_len == MIME_LEN_PROXY_CONNECTION && strncasecmp(name, 
MIME_FIELD_PROXY_CONNECTION, name_len) == 0) ||
    -        (name_len == MIME_LEN_TRANSFER_ENCODING && strncasecmp(name, 
MIME_FIELD_TRANSFER_ENCODING, name_len) == 0) ||
    -        (name_len == MIME_LEN_UPGRADE && strncasecmp(name, 
MIME_FIELD_UPGRADE, name_len) == 0)) {
    -      continue;
    -    }
    -
    -    MIMEFieldWrapper header(field, in->m_heap, in->m_http->m_fields_impl);
    -    if ((len = http2_write_header_field(p, end, header, indexing_table)) 
== -1) {
    -      if (p == out) {
    -        // no progress was made, header was too big for the buffer, 
skipping for now
    -        continue;
    -      }
    -      if (!cont) {
    -        // Parsing a part of headers is done
    -        cont = true;
    -        return p - out;
    -      } else {
    -        // Parse error
    -        return -1;
    -      }
    -    }
    -    p += len;
    -  }
    -
    -  // Parsing all headers is done
    -  return p - out;
    +  // TODO: It would be better to split Cookie header value
    +  return hpack_encode_header_block(handle, out, out_len, in);
     }
     
     /*
      * Decode Header Blocks to Header List.
      */
     int64_t
    -http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const 
uint8_t *buf_end, Http2IndexingTable &indexing_table,
    +http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const 
uint32_t buf_len, HpackHandle &handle,
                                bool &trailing_header)
     {
    -  const uint8_t *cursor = buf_start;
    -  HdrHeap *heap = hdr->m_heap;
    -  HTTPHdrImpl *hh = hdr->m_http;
    -  bool header_field_started = false;
    +  const MIMEField *field;
    +  const char *value;
    +  int len;
       bool is_trailing_header = trailing_header;
    +  int64_t result = hpack_decode_header_block(handle, hdr, buf_start, 
buf_len);
     
    -  while (cursor < buf_end) {
    -    int64_t read_bytes = 0;
    +  if (result < 0) {
    +    return result;
    +  }
     
    -    // decode a header field encoded by HPACK
    -    MIMEField *field = mime_field_create(heap, hh->m_fields_impl);
    -    MIMEFieldWrapper header(field, heap, hh->m_fields_impl);
    -    HpackFieldType ftype = hpack_parse_field_type(*cursor);
     
    -    switch (ftype) {
    -    case HPACK_FIELD_INDEX:
    -      read_bytes = decode_indexed_header_field(header, cursor, buf_end, 
indexing_table);
    -      if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
    -        return HPACK_ERROR_COMPRESSION_ERROR;
    -      }
    -      cursor += read_bytes;
    -      header_field_started = true;
    -      break;
    -    case HPACK_FIELD_INDEXED_LITERAL:
    -    case HPACK_FIELD_NOINDEX_LITERAL:
    -    case HPACK_FIELD_NEVERINDEX_LITERAL:
    -      read_bytes = decode_literal_header_field(header, cursor, buf_end, 
indexing_table);
    -      if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
    -        return HPACK_ERROR_COMPRESSION_ERROR;
    -      }
    -      cursor += read_bytes;
    -      header_field_started = true;
    -      break;
    -    case HPACK_FIELD_TABLESIZE_UPDATE:
    -      if (header_field_started) {
    -        return HPACK_ERROR_COMPRESSION_ERROR;
    +  MIMEFieldIter iter;
    +  unsigned int expected_pseudo_header_count = 4;
    +  unsigned int pseudo_header_count = 0;
    +
    +  if (is_trailing_header) {
    +    expected_pseudo_header_count = 0;
    +  }
    +  for (field = hdr->iter_get_first(&iter); field != NULL; field = 
hdr->iter_get_next(&iter)) {
    +    value = field->name_get(&len);
    +    // Pseudo headers must appear before regular headers
    +    if (len && value[0] == ':') {
    +      ++pseudo_header_count;
    +      if (pseudo_header_count > expected_pseudo_header_count) {
    +        return -result;
    --- End diff --
    
    Is it necessary to return this? Those values are used in 
`decode_header_blocks` in Http2Stream.h to detect COMPRESSION_ERROR or 
PROTOCOL_ERROR.
    How about returning Http2ErrorCode directly?



> Decouple HPACK from HTTP/2
> --------------------------
>
>                 Key: TS-4092
>                 URL: https://issues.apache.org/jira/browse/TS-4092
>             Project: Traffic Server
>          Issue Type: Improvement
>          Components: HTTP/2
>            Reporter: Masakazu Kitajo
>            Assignee: Masakazu Kitajo
>             Fix For: 6.2.0
>
>
> Our HTTP/2 implementation and HPACK implementation are coupled tightly. This 
> is bad. It makes things complicated.
> I tried to write a test runner which uses [hpack-test-case 
> |https://github.com/http2jp/hpack-test-case], however, I had to call 
> functions in HTTP2.cc. Because HPACK.cc has only primitive encoder and 
> decoder, and doesn't handle header blocks. HTTP2.cc covers not only RFC7540 
> but also some part of RFC7541.
> On the other hand, HPACK.h exports pseudo header names as constants. They 
> should be in HTTP2.h or MIME.h as WKS. We don't need them in HPACK 
> implementation.
> Also, HPACK is used with QUIC (at least in current draft). We should decouple 
> HPACK from HTTP/2 so that we can use the module with QUIC in the future.
> Once we have done this, we can write tests for these improvements more easily.
> TS-4002, TS-4061, TS-4014 and TS-3478



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to