added xml transcoder

capabilities to encod/decode xml, expects nokogiri.
This commit is contained in:
HoneyryderChuck 2022-08-13 14:55:07 +01:00
parent 49d6cc4da4
commit c70209db4b
9 changed files with 73 additions and 3 deletions

View File

@ -23,6 +23,7 @@ group :test do
else
gem "webmock"
end
gem "nokogiri"
gem "websocket-driver"
gem "net-ssh", "~> 4.2.0" if RUBY_VERSION < "2.2.0"

View File

@ -201,7 +201,7 @@ module HTTPX
end
%i[
params form json body ssl http2_settings
params form json xml body ssl http2_settings
request_class response_class headers_class request_body_class
response_body_class connection_class options_class
io fallback_protocol debug debug_level transport_options resolver_class resolver_options
@ -210,7 +210,7 @@ module HTTPX
def_option(method_name)
end
REQUEST_IVARS = %i[@params @form @json @body].freeze
REQUEST_IVARS = %i[@params @form @xml @json @body].freeze
private_constant :REQUEST_IVARS
def ==(other)

View File

@ -162,6 +162,8 @@ module HTTPX
Transcoder.registry("form").encode(options.form)
elsif options.json
Transcoder.registry("json").encode(options.json)
elsif options.xml
Transcoder.registry("xml").encode(options.xml)
end
return if @body.nil?

View File

@ -94,6 +94,10 @@ module HTTPX
decode("form")
end
def xml
decode("xml")
end
private
def decode(format, *args)

View File

@ -90,4 +90,5 @@ end
require "httpx/transcoder/body"
require "httpx/transcoder/form"
require "httpx/transcoder/json"
require "httpx/transcoder/xml"
require "httpx/transcoder/chunker"

View File

@ -0,0 +1,49 @@
# frozen_string_literal: true
require "delegate"
require "forwardable"
require "uri"
module HTTPX::Transcoder
module Xml
using HTTPX::RegexpExtensions
module_function
MIME_TYPES = %r{\b(application|text)/(.+\+)?xml\b}.freeze
class Encoder < SimpleDelegator
def content_type
charset = respond_to?(:encoding) ? encoding.to_s.downcase : "utf-8"
"application/xml; charset=#{charset}"
end
def bytesize
to_s.bytesize
end
end
def encode(xml)
Encoder.new(xml)
end
begin
require "nokogiri"
# rubocop:disable Lint/DuplicateMethods
def decode(response)
content_type = response.content_type.mime_type
raise HTTPX::Error, "invalid form mime type (#{content_type})" unless MIME_TYPES.match?(content_type)
Nokogiri::XML.method(:parse)
end
rescue LoadError
def decode(_response)
raise HTTPX::Error, "\"nokogiri\" is required in order to decode XML"
end
end
# rubocop:enable Lint/DuplicateMethods
end
register "xml", Xml
end

View File

@ -45,7 +45,7 @@ class OptionsTest < Minitest::Test
assert opt2.body == "fat", "body was not set"
end
%i[form json].each do |meth|
%i[form json xml].each do |meth|
define_method :"test_options_#{meth}" do
opt1 = Options.new
assert opt1.public_send(meth).nil?, "#{meth} shouldn't be set by default"
@ -98,6 +98,7 @@ class OptionsTest < Minitest::Test
:debug_level => 1,
:params => nil,
:json => nil,
:xml => nil,
:body => nil,
:window_size => 16_384,
:body_threshold_size => 114_688,

View File

@ -77,6 +77,13 @@ class RequestTest < Minitest::Test
assert req.headers["content-length"] == "13", "content length is wrong"
end
def test_request_body_xml
req = Request.new(:post, "http://example.com/", xml: "<xml></xml>")
assert !req.body.empty?, "body should exist"
assert req.headers["content-type"] == "application/xml; charset=utf-8", "content type is wrong"
assert req.headers["content-length"] == "11", "content length is wrong"
end
private
def resource

View File

@ -156,6 +156,11 @@ class ResponseTest < Minitest::Test
form_response << "богус"
assert_raises(ArgumentError) { form_response.form }
xml_response = Response.new(request, 200, "2.0", { "content-type" => "application/xml; charset=utf-8" })
xml_response << "<xml></xml>"
xml = xml_response.xml
assert xml.is_a?(Nokogiri::XML::Node)
form2_response = Response.new(request, 200, "2.0", { "content-type" => "application/x-www-form-urlencoded" })
form2_response << "a[]=b&a[]=c&d[e]=f&g[h][i][j]=k&l[m][][n]=o&l[m][][p]=q&l[m][][n]=r&s[=t"
assert form2_response.form == {