From 0b3af3ec0ff71b99a09cdfe7829d689c05c18809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chary=C5=82o?= Date: Thu, 6 Nov 2025 19:51:47 +0100 Subject: [PATCH] feat: set default content type when processing body httparty used to properly set multipart content type when dealing with files or multipart url bodies. There was no default for urlencoded. net-http 0.7.0 stops defaulting content type to x-www-form-urlencoded (net-http PR #207), thus httparty's default behavior of urlencoding needs to set content type. Content type does not get set when passed or when using custom query_string_normalizer. If you use custom query_string_normalizer, return content_type as a second argument. --- lib/httparty/request.rb | 5 +---- lib/httparty/request/body.rb | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/httparty/request.rb b/lib/httparty/request.rb index 36b7d357..94ffc216 100644 --- a/lib/httparty/request.rb +++ b/lib/httparty/request.rb @@ -242,11 +242,8 @@ def setup_raw_request force_multipart: options[:multipart] ) - if body.multipart? - content_type = "multipart/form-data; boundary=#{body.boundary}" - @raw_request['Content-Type'] = content_type - end @raw_request.body = body.call + @raw_request['Content-Type'] ||= body.content_type end @raw_request.instance_variable_set(:@decode_content, decompress_content?) diff --git a/lib/httparty/request/body.rb b/lib/httparty/request/body.rb index 3fbd7af6..eadf480c 100644 --- a/lib/httparty/request/body.rb +++ b/lib/httparty/request/body.rb @@ -16,7 +16,12 @@ def initialize(params, query_string_normalizer: nil, force_multipart: false) def call if params.respond_to?(:to_hash) - multipart? ? generate_multipart : normalize_query(params) + if multipart? + @content_type = "multipart/form-data; boundary=#{boundary}" + generate_multipart + else + normalize_query_and_set_content_type(params) + end else params end @@ -30,6 +35,13 @@ def multipart? params.respond_to?(:to_hash) && (force_multipart || has_file?(params)) end + def content_type + return @content_type if defined?(@content_type) + return "multipart/form-data; boundary=#{boundary}" if multipart? + + "application/x-www-form-urlencoded" + end + private # https://html.spec.whatwg.org/#multipart-form-data @@ -54,7 +66,8 @@ def generate_multipart memo << content_body(value) memo << NEWLINE.b end - + + @content_type = "multipart/form-data; boundary=#{boundary}" multipart << "--#{boundary}--#{NEWLINE}".b end @@ -72,10 +85,12 @@ def file?(object) object.respond_to?(:path) && object.respond_to?(:read) end - def normalize_query(query) + def normalize_query_and_set_content_type(query) if query_string_normalizer - query_string_normalizer.call(query) + query, @content_type = query_string_normalizer.call(query) + query else + @content_type = 'application/x-www-form-urlencoded' HashConversions.to_params(query) end end @@ -91,8 +106,9 @@ def content_body(object) end end - def content_type(object) + def object_content_type(object) return object.content_type if object.respond_to?(:content_type) + require 'mini_mime' mime = MiniMime.lookup_by_filename(object.path) mime ? mime.content_type : 'application/octet-stream'