summaryrefslogtreecommitdiffhomepage
path: root/src/ruby/nxt_ruby.c
diff options
context:
space:
mode:
authorAndrew Clayton <a.clayton@nginx.com>2023-10-23 14:24:01 +0100
committerAndrew Clayton <a.clayton@nginx.com>2023-12-08 13:48:33 +0000
commitd9f5f1fb741109cc232cedd3574aa587626789c1 (patch)
tree4f6cc38617b11d85b9f81e3f30a1ab1938b1a353 /src/ruby/nxt_ruby.c
parent846a7f483643a00322f81a7848ca556722e5469a (diff)
downloadunit-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.c71
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 ( ;; ) {