[pkg-uWSGI-devel] Bug#1125369: uwsgi-plugin-ruby: Incompatibility with ruby-rack 3.x causing some http headers to format wrong
Alexandre Rossi
niol at zincube.net
Tue Jan 13 13:23:37 GMT 2026
Control: reassign -1 src:uwsgi
Control: affects -1 uwsgi-plugin-ruby
Control: tag -1 patch
Control: forwarded -1 https://github.com/unbit/uwsgi/pull/2749
Hi,
> I've been running Redmine through uwsgi (better socket activation than
> Passenger) and noticed that some of the cookies being sent to the browser
> were wrong.
> I'd expect a header like:
>
> Set-Cookie: autologin=[secret];secure
>
> Instead I got a header like:
>
> Set-Cookie: ["autologin=[secret];secure"]
>
> > There is one changed feature in Rack 3 which is not backwards compatible:
> >
> > - Response header values can be an Array to handle multiple values (and no longer supports \n encoded headers).
> >
> > You can achieve compatibility by using Rack::Response#add_header which provides an interface for adding headers without concern for the underlying format.
>
>
> I've worked around this for my own purposes by adapting the code block
> suggested by 'pcantrell' in the above mentioned Passenger bug report:
> https://github.com/phusion/passenger/issues/2503#issuecomment-2370192659
> But as I understand it, this issue should be solved at the uwsgi/rack
> layer, not in the ruby application.
Thanks for the detailed bug report and analysis.
Here is a possible fix to this, can you confirm? Or do you need guidance
to rebuild the rack plugin?
Thanks,
Alex
diff --git i/plugins/rack/rack_plugin.c w/plugins/rack/rack_plugin.c
index 792cc4dc..c00ad022 100644
--- i/plugins/rack/rack_plugin.c
+++ w/plugins/rack/rack_plugin.c
@@ -739,14 +739,19 @@ VALUE send_header(VALUE obj, VALUE headers, int argc, const VALUE *argv, VALUE b
struct wsgi_request *wsgi_req = current_wsgi_req();
- VALUE hkey, hval;
+ VALUE hkey, hval, hval_raw;
//uwsgi_log("HEADERS %d\n", TYPE(obj));
if (TYPE(obj) == T_ARRAY) {
if (RARRAY_LEN(obj) >= 2) {
- hkey = rb_obj_as_string( RARRAY_PTR(obj)[0]);
- hval = rb_obj_as_string( RARRAY_PTR(obj)[1]);
-
+ hkey = rb_obj_as_string(RARRAY_PTR(obj)[0]);
+ hval_raw = RARRAY_PTR(obj)[1];
+ if (TYPE(hval_raw) == T_ARRAY) {
+ hval = rb_funcall(hval_raw, rb_intern("join"), 1, rb_str_new_static(", ", 2));
+ }
+ else {
+ hval = rb_obj_as_string( hval_raw);
+ }
}
else {
goto clear;
diff --git i/t/rack/app.ru w/t/rack/app.ru
index 4603375e..9344c4bc 100644
--- i/t/rack/app.ru
+++ w/t/rack/app.ru
@@ -1,7 +1,10 @@
class App
- def call(environ)
- [200, {"content-type" => "text/plain"}, ['Hello']]
+ def call(env)
+ headers = {"content-type" => "text/plain"}
+ Rack::Utils.set_cookie_header!(headers, "country", { :value => "UK", :path => "/"})
+ Rack::Utils.set_cookie_header!(headers, "autologin", { :value => "yes", :path => "/", :secure => true})
+ [200, headers, ["Hello"]]
end
end
diff --git i/t/runner w/t/runner
index b59966b5..c9957959 100755
--- i/t/runner
+++ w/t/runner
@@ -251,8 +251,14 @@ class UwsgiTest(unittest.TestCase):
]
)
- self.assert_GET_body("/", "Hello")
+ with requests.get(f"http://{UWSGI_HTTP}/") as r:
+ self.assertEqual(r.text, "Hello")
+ self.assertEqual(r.headers["Content-type"], "text/plain")
+ self.assertEqual(
+ r.headers["Set-Cookie"],
+ "country=UK; path=/, autologin=yes; path=/; secure",
+ )
if __name__ == "__main__":
- unittest.main()
+ unittest.main(verbosity=2)
More information about the pkg-uWSGI-devel
mailing list