From c746ba3270ba641ff06d98ede68db3080029423e Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 17 Aug 2026 13:45:29 +1200 Subject: [PATCH 1/4] Cover core interface contracts. Assisted-By: devx/cbdeae41-9308-4071-ad53-58cd92db2946 --- lib/utopia/request.rb | 6 +----- test/utopia/application.rb | 11 +++++++++++ test/utopia/middleware.rb | 8 +++++++- test/utopia/request.rb | 8 ++++++++ test/utopia/response.rb | 8 ++++++++ 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/utopia/request.rb b/lib/utopia/request.rb index 6685a0c6..a1c7425e 100644 --- a/lib/utopia/request.rb +++ b/lib/utopia/request.rb @@ -122,11 +122,7 @@ def query_parameters return cookies unless cookie_header - if cookie_header.respond_to?(:to_str) - cookie_header = cookie_header.to_str - else - cookie_header = cookie_header.to_s - end + cookie_header = cookie_header.to_s cookie_header.split(/;\s*/).each do |pair| key, value = pair.split("=", 2) diff --git a/test/utopia/application.rb b/test/utopia/application.rb index 906bf59d..902d8670 100644 --- a/test/utopia/application.rb +++ b/test/utopia/application.rb @@ -33,6 +33,17 @@ expect(response.headers["content-type"]).to be == "text/plain; charset=utf-8" end + it "yields the builder to blocks accepting arguments" do + application = subject.build do |builder| + builder.run Protocol::HTTP::Middleware.for{|request| Utopia::Response.text("Hello")} + end + + response = application.call(http_request) + + expect(response.status).to be == 200 + expect(response.read).to be == "Hello" + end + it "normalizes protocol response objects" do response_object = Object.new diff --git a/test/utopia/middleware.rb b/test/utopia/middleware.rb index a9692b22..52afbe92 100644 --- a/test/utopia/middleware.rb +++ b/test/utopia/middleware.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Released under the MIT License. -# Copyright, 2015-2025, by Samuel Williams. +# Copyright, 2015-2026, by Samuel Williams. require "utopia/middleware" @@ -9,4 +9,10 @@ it "should give a default path relative to the cwd" do expect(File).to be(:exist?, Utopia.default_root(".content", __dir__)) end + + it "constructs the default application path" do + path = Utopia.default_path(".content", __dir__) + + expect(path).to be == Utopia::Path[Utopia.default_root(".content", __dir__)] + end end diff --git a/test/utopia/request.rb b/test/utopia/request.rb index 3e63ec3c..8c711609 100644 --- a/test/utopia/request.rb +++ b/test/utopia/request.rb @@ -52,6 +52,14 @@ expect(request.post?).to be == false end + it "identifies QUERY requests" do + request.method = "QUERY" + expect(request.query?).to be == true + + request.method = "GET" + expect(request.query?).to be == false + end + it "provides decoded query arguments" do expect(request.query_parameters).to be == { "q" => "utopia", diff --git a/test/utopia/response.rb b/test/utopia/response.rb index d8f8094e..2e1fbe18 100644 --- a/test/utopia/response.rb +++ b/test/utopia/response.rb @@ -20,6 +20,14 @@ expect(response.headers["location"]).to be == "/target" end + it "builds HTML responses" do + response = subject.html("

Hello

", 201) + + expect(response.status).to be == 201 + expect(response.headers["content-type"]).to be == "text/html; charset=utf-8" + expect(response.read).to be == "

Hello

" + end + it "passes through protocol responses" do response = Protocol::HTTP::Response[204] From 6a8ed0c279566941aed928b8a9fbde8778538a20 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 17 Aug 2026 14:05:41 +1200 Subject: [PATCH 2/4] Use typed cookie headers. Assisted-By: devx/cbdeae41-9308-4071-ad53-58cd92db2946 --- lib/utopia/request.rb | 21 +++++---------------- test/utopia/request.rb | 3 ++- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/lib/utopia/request.rb b/lib/utopia/request.rb index a1c7425e..f087cc37 100644 --- a/lib/utopia/request.rb +++ b/lib/utopia/request.rb @@ -117,24 +117,13 @@ def query_parameters @query_parameters ||= parse_query_parameters(self.url.query) end - private def parse_cookies(cookie_header) - cookies = {} - - return cookies unless cookie_header - - cookie_header = cookie_header.to_s - - cookie_header.split(/;\s*/).each do |pair| - key, value = pair.split("=", 2) - cookies[key] = value || "" - end - - return cookies - end - # Decoded request cookies. def cookies - @cookies ||= parse_cookies(self.headers["cookie"]) + @cookies ||= if cookie_header = self.headers["cookie"] + cookie_header.to_h.transform_values(&:value) + else + {} + end end # The request user agent. diff --git a/test/utopia/request.rb b/test/utopia/request.rb index 8c711609..d447ff98 100644 --- a/test/utopia/request.rb +++ b/test/utopia/request.rb @@ -98,7 +98,8 @@ expect(request).not.to be(:respond_to?, :parsed_body) end - it "provides decoded cookies" do + it "provides cookie values" do + expect(request.headers["cookie"]).to be_a(Protocol::HTTP::Header::Cookie) expect(request.cookies).to be == {"a" => "1", "b" => "2"} end From 10f299920753f41f0e1e2167cb63778e5e30a85c Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 17 Aug 2026 16:31:08 +1200 Subject: [PATCH 3/4] Use predicate matcher for QUERY requests. Assisted-By: devx/cbdeae41-9308-4071-ad53-58cd92db2946 --- test/utopia/request.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utopia/request.rb b/test/utopia/request.rb index d447ff98..0e12629e 100644 --- a/test/utopia/request.rb +++ b/test/utopia/request.rb @@ -54,10 +54,10 @@ it "identifies QUERY requests" do request.method = "QUERY" - expect(request.query?).to be == true + expect(request).to be(:query?) request.method = "GET" - expect(request.query?).to be == false + expect(request).not.to be(:query?) end it "provides decoded query arguments" do From 63b63ff960ee4e524058fc50a3115d1358136a1f Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 17 Aug 2026 16:31:08 +1200 Subject: [PATCH 4/4] Require protocol-http 0.71. Assisted-By: devx/cbdeae41-9308-4071-ad53-58cd92db2946 --- utopia.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utopia.gemspec b/utopia.gemspec index cda1c90e..8db5da26 100644 --- a/utopia.gemspec +++ b/utopia.gemspec @@ -33,7 +33,7 @@ Gem::Specification.new do |spec| spec.add_dependency "msgpack" spec.add_dependency "net-smtp" spec.add_dependency "protocol-content", "~> 0.1" - spec.add_dependency "protocol-http", "~> 0.70" + spec.add_dependency "protocol-http", "~> 0.71" spec.add_dependency "protocol-media", "~> 0.3" spec.add_dependency "protocol-media-registry", "~> 0.1" spec.add_dependency "protocol-url", "~> 0.18"