You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kg...@apache.org on 2020/10/29 18:12:34 UTC
[qpid-dispatch] branch dev-protocol-adaptors-2 updated:
DISPATCH-1784: allow parsing of folded headers
This is an automated email from the ASF dual-hosted git repository.
kgiusti pushed a commit to branch dev-protocol-adaptors-2
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git
The following commit(s) were added to refs/heads/dev-protocol-adaptors-2 by this push:
new 483add8 DISPATCH-1784: allow parsing of folded headers
483add8 is described below
commit 483add8d3c7a58da9af5d258675c05934ec5eec9
Author: Kenneth Giusti <kg...@apache.org>
AuthorDate: Wed Oct 28 15:10:19 2020 -0400
DISPATCH-1784: allow parsing of folded headers
This closes #904
---
src/adaptors/http1/http1_codec.c | 139 +++++++++++++++++++++++-------------
tests/system_tests_http1_adaptor.py | 33 +++++++++
2 files changed, 123 insertions(+), 49 deletions(-)
diff --git a/src/adaptors/http1/http1_codec.c b/src/adaptors/http1/http1_codec.c
index 5cb16b3..b9558b4 100644
--- a/src/adaptors/http1/http1_codec.c
+++ b/src/adaptors/http1/http1_codec.c
@@ -889,76 +889,117 @@ static int process_header(h1_codec_connection_t *conn, struct decoder_t *decoder
}
-// Parse out the header key and value
+// Parse an HTTP header line.
+// See RFC7230 for details. If header line folding (obs-folding) is detected,
+// replace the folding with spaces.
//
static bool parse_header(h1_codec_connection_t *conn, struct decoder_t *decoder)
{
- qd_iterator_pointer_t *rptr = &decoder->read_ptr;
- qd_iterator_pointer_t line;
+ qd_iterator_pointer_t end_ptr = decoder->read_ptr;
h1_codec_request_state_t *hrs = decoder->hrs;
+ qd_iterator_pointer_t line;
+
assert(hrs); // else state machine busted
- if (read_line(rptr, &line)) {
- debug_print_iterator_pointer("header:", &line);
+ if (!read_line(&end_ptr, &line))
+ // need more data
+ return false;
+ if (is_empty_line(&line)) {
+ decoder->read_ptr = end_ptr;
hrs->in_octets += line.remaining;
+ return process_headers_done(conn, decoder);
+ }
- if (is_empty_line(&line)) {
- // end of headers
- return process_headers_done(conn, decoder);
- }
+ // check for header line folding
- qd_iterator_pointer_t key = {0};
+ bool obs_fold = false;
+ while (true) {
+ qd_iterator_pointer_t peek = end_ptr;
+ uint8_t octet;
+ if (!get_octet(&peek, &octet))
+ // need more data
+ return false;
- if (!parse_token(&line, &key)) {
- decoder->error_msg = "Malformed Header";
- decoder->error = (decoder->is_request) ? HTTP1_STATUS_BAD_REQ
- : HTTP1_STATUS_SERVER_ERR;
+ if (octet != ' ' && octet != '\t')
+ break;
+
+ obs_fold = true;
+
+ if (!read_line(&end_ptr, &line))
return false;
- }
+ }
- // advance line past the ':'
- uint8_t octet;
- while (get_octet(&line, &octet) && octet != ':')
- ;
+ // end_ptr now points past the header line, advance decoder past header
+ // line and set 'line' to hold header
- // line now contains the value. convert to C strings and post callback
- ensure_scratch_size(&decoder->scratch, key.remaining + line.remaining + 2);
- uint8_t *ptr = decoder->scratch.buf;
- size_t avail = decoder->scratch.size;
-
- uint8_t *key_str = ptr;
- size_t offset = pointer_2_str(&key, key_str, avail);
- ptr += offset;
- avail -= offset;
-
- uint8_t *value_str = ptr;
- pointer_2_str(&line, value_str, avail);
-
- // trim whitespace on both ends of value
- while (isspace(*value_str))
- ++value_str;
- ptr = value_str + strlen((char*) value_str);
- while (ptr-- > value_str) {
- if (!isspace(*ptr))
- break;
- *ptr = 0;
- }
+ line = decoder->read_ptr;
+ decoder->read_ptr = end_ptr;
+ line.remaining -= end_ptr.remaining;
- process_header(conn, decoder, key_str, value_str);
+ debug_print_iterator_pointer("header:", &line);
- if (!decoder->error) {
- decoder->error = conn->config.rx_header(hrs, (char *)key_str, (char *)value_str);
- if (decoder->error)
- decoder->error_msg = "hrs_rx_header callback error";
- }
+ hrs->in_octets += line.remaining;
- return !!rptr->remaining;
+ // convert field to key and value strings
+
+ qd_iterator_pointer_t key;
+ if (!parse_token(&line, &key)) {
+ decoder->error_msg = "Malformed Header";
+ decoder->error = (decoder->is_request) ? HTTP1_STATUS_BAD_REQ
+ : HTTP1_STATUS_SERVER_ERR;
+ return false;
+ }
+
+ // advance line past the ':'
+ uint8_t octet;
+ while (get_octet(&line, &octet) && octet != ':')
+ ;
+
+ // line now contains the value. convert to C strings and post callback
+ ensure_scratch_size(&decoder->scratch, key.remaining + line.remaining + 2);
+ uint8_t *ptr = decoder->scratch.buf;
+ size_t avail = decoder->scratch.size;
+
+ uint8_t *key_str = ptr;
+ size_t offset = pointer_2_str(&key, key_str, avail);
+ ptr += offset;
+ avail -= offset;
+
+ uint8_t *value_str = ptr;
+ pointer_2_str(&line, value_str, avail);
+
+ // trim whitespace on both ends of value
+ while (isspace(*value_str))
+ ++value_str;
+ ptr = value_str + strlen((char*) value_str);
+ while (ptr-- > value_str) {
+ if (!isspace(*ptr))
+ break;
+ *ptr = 0;
+ }
+
+ // remove header line folding by overwriting all <CR> and <LF> chars with
+ // spaces as per RFC7230
+
+ if (obs_fold) {
+ ptr = value_str;
+ while ((ptr = (uint8_t*) strpbrk((char*) ptr, CRLF)) != 0)
+ *ptr = ' ';
}
- return false; // pend for more data
+ process_header(conn, decoder, key_str, value_str);
+
+ if (!decoder->error) {
+ decoder->error = conn->config.rx_header(hrs, (char *)key_str, (char *)value_str);
+ if (decoder->error)
+ decoder->error_msg = "hrs_rx_header callback error";
+ }
+
+ return !!decoder->read_ptr.remaining;
}
+
//
// Chunked body encoding parser
//
diff --git a/tests/system_tests_http1_adaptor.py b/tests/system_tests_http1_adaptor.py
index 3e83279..9e7468f 100644
--- a/tests/system_tests_http1_adaptor.py
+++ b/tests/system_tests_http1_adaptor.py
@@ -532,6 +532,39 @@ class Http1AdaptorOneRouterTest(TestCase):
body=b'?')],
ResponseValidator(expect_headers={'Content-Type': "text/plain;charset=utf-8"},
expect_body=b'?')),
+
+ # test support for "folded headers"
+
+ (RequestMsg("GET", "/GET/folded_header_01",
+ headers={"Content-Length": 0}),
+ ResponseMsg(200, reason="OK",
+ headers={"Content-Type": "text/plain;charset=utf-8",
+ "Content-Length": 1,
+ "folded-header": "One\r\n \r\n\tTwo"},
+ body=b'X'),
+ ResponseValidator(expect_headers={"Content-Type":
+ "text/plain;charset=utf-8",
+ "folded-header":
+ "One \tTwo"},
+ expect_body=b'X')),
+
+ (RequestMsg("GET", "/GET/folded_header_02",
+ headers={"Content-Length": 0}),
+ ResponseMsg(200, reason="OK",
+ headers={"Content-Type": "text/plain;charset=utf-8",
+ "Content-Length": 1,
+ "folded-header": "\r\n \r\n\tTwo",
+ "another-header": "three"},
+ body=b'X'),
+ ResponseValidator(expect_headers={"Content-Type":
+ "text/plain;charset=utf-8",
+ # trim leading and
+ # trailing ws:
+ "folded-header":
+ "Two",
+ "another-header":
+ "three"},
+ expect_body=b'X')),
],
#
# HEAD
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org