diff options
author | Andrew Clayton <a.clayton@nginx.com> | 2023-10-23 14:24:01 +0100 |
---|---|---|
committer | Andrew Clayton <a.clayton@nginx.com> | 2023-12-08 13:48:33 +0000 |
commit | d9f5f1fb741109cc232cedd3574aa587626789c1 (patch) | |
tree | 4f6cc38617b11d85b9f81e3f30a1ab1938b1a353 /src/ruby/nxt_ruby.c | |
parent | 846a7f483643a00322f81a7848ca556722e5469a (diff) | |
download | unit-d9f5f1fb741109cc232cedd3574aa587626789c1.tar.gz unit-d9f5f1fb741109cc232cedd3574aa587626789c1.tar.bz2 |
Ruby: Handle response field arrays
@xeron on GitHub reported an issue whereby with a Rails 7.1 application
they were getting the following error
2023/10/22 20:57:28 [error] 56#56 [unit] #8: Ruby: Wrong header entry 'value' from application
2023/10/22 20:57:28 [error] 56#56 [unit] #8: Ruby: Failed to run ruby script
After some back and forth debugging it turns out rack was trying to send
back a header comprised of an array of values. E.g
app = Proc.new do |env|
["200", {
"Content-Type" => "text/plain",
"X-Array-Header" => ["Item-1", "Item-2"],
}, ["Hello World\n"]]
end
run app
It seems this became a possibility in rack v3.0[0]
So along with a header value type of T_STRING we need to also allow
T_ARRAY.
If we get a T_ARRAY we need to build up the header field using the given
values.
E.g
"X-Array-Header" => ["Item-1", "", "Item-3", "Item-4"],
becomes
X-Array-Header: Item-1; ; Item-3; Item-4
[0]: <https://github.com/rack/rack/blob/main/UPGRADE-GUIDE.md?plain=1#L26>
Reported-by: Ivan Larionov <xeron.oskom@gmail.com>
Closes: <https://github.com/nginx/unit/issues/974>
Link: <https://github.com/nginx/unit/pull/998>
Tested-by: Timo Stark <t.stark@nginx.com>
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
Diffstat (limited to 'src/ruby/nxt_ruby.c')
-rw-r--r-- | src/ruby/nxt_ruby.c | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c index bcb48f6b..3a019c36 100644 --- a/src/ruby/nxt_ruby.c +++ b/src/ruby/nxt_ruby.c @@ -889,13 +889,37 @@ nxt_ruby_hash_info(VALUE r_key, VALUE r_value, VALUE arg) goto fail; } - if (nxt_slow_path(TYPE(r_value) != T_STRING)) { + if (nxt_slow_path(TYPE(r_value) != T_STRING && TYPE(r_value) != T_ARRAY)) { nxt_unit_req_error(headers_info->req, "Ruby: Wrong header entry 'value' from application"); goto fail; } + if (TYPE(r_value) == T_ARRAY) { + int i; + int arr_len = RARRAY_LEN(r_value); + VALUE item; + size_t len = 0; + + for (i = 0; i < arr_len; i++) { + item = rb_ary_entry(r_value, i); + if (TYPE(item) != T_STRING) { + nxt_unit_req_error(headers_info->req, + "Ruby: Wrong header entry in 'value' array " + "from application"); + goto fail; + } + + len += RSTRING_LEN(item) + 2; /* +2 for '; ' */ + } + + headers_info->fields++; + headers_info->size += RSTRING_LEN(r_key) + len - 2; + + return ST_CONTINUE; + } + value = RSTRING_PTR(r_value); value_end = value + RSTRING_LEN(r_value); @@ -941,11 +965,52 @@ nxt_ruby_hash_add(VALUE r_key, VALUE r_value, VALUE arg) headers_info = (void *) (uintptr_t) arg; rc = &headers_info->rc; + key_len = RSTRING_LEN(r_key); + + if (TYPE(r_value) == T_ARRAY) { + int i; + int arr_len = RARRAY_LEN(r_value); + char *field, *p; + VALUE item; + size_t len = 0; + + for (i = 0; i < arr_len; i++) { + item = rb_ary_entry(r_value, i); + + len += RSTRING_LEN(item) + 2; /* +2 for '; ' */ + } + + field = nxt_unit_malloc(NULL, len); + if (field == NULL) { + goto fail; + } + + p = field; + + for (i = 0; i < arr_len; i++) { + item = rb_ary_entry(r_value, i); + + p = nxt_cpymem(p, RSTRING_PTR(item), RSTRING_LEN(item)); + p = nxt_cpymem(p, "; ", 2); + } + + len -= 2; + + *rc = nxt_unit_response_add_field(headers_info->req, + RSTRING_PTR(r_key), key_len, + field, len); + nxt_unit_free(NULL, field); + + if (nxt_slow_path(*rc != NXT_UNIT_OK)) { + goto fail; + } + + return ST_CONTINUE; + } + value = RSTRING_PTR(r_value); value_end = value + RSTRING_LEN(r_value); - key_len = RSTRING_LEN(r_key); - pos = value; for ( ;; ) { |