Hello community, here is the log from the commit of package rubygem-multipart-post for openSUSE:Factory checked in at 2019-08-06 15:10:06 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-multipart-post (Old) and /work/SRC/openSUSE:Factory/.rubygem-multipart-post.new.4126 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-multipart-post" Tue Aug 6 15:10:06 2019 rev:9 rq:717311 version:2.1.1 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-multipart-post/rubygem-multipart-post.changes 2014-10-24 10:48:33.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-multipart-post.new.4126/rubygem-multipart-post.changes 2019-08-06 15:10:08.535781731 +0200 @@ -1,0 +2,11 @@ +Fri Jul 19 09:24:08 UTC 2019 - Stephan Kulow <co...@suse.com> + +- updated to version 2.1.1 + see installed History.txt + + <!-- + # @markup rdoc + # @title CHANGELOG + --> + +------------------------------------------------------------------- Old: ---- multipart-post-2.0.0.gem New: ---- gem2rpm.yml multipart-post-2.1.1.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-multipart-post.spec ++++++ --- /var/tmp/diff_new_pack.iF6fUX/_old 2019-08-06 15:10:08.979781480 +0200 +++ /var/tmp/diff_new_pack.iF6fUX/_new 2019-08-06 15:10:08.979781480 +0200 @@ -1,7 +1,7 @@ # # spec file for package rubygem-multipart-post # -# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,28 +12,35 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # +# +# This file was generated with a gem2rpm.yml and not just plain gem2rpm. +# All sections marked as MANUAL, license headers, summaries and descriptions +# can be maintained in that file. Please consult this file before editing any +# of those fields +# + Name: rubygem-multipart-post -Version: 2.0.0 +Version: 2.1.1 Release: 0 %define mod_name multipart-post %define mod_full_name %{mod_name}-%{version} BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: %{rubygem gem2rpm} -BuildRequires: %{rubygem rdoc > 3.10} BuildRequires: %{ruby} BuildRequires: ruby-macros >= 5 Url: https://github.com/nicksieger/multipart-post -Source: http://rubygems.org/gems/%{mod_full_name}.gem +Source: https://rubygems.org/gems/%{mod_full_name}.gem +Source1: gem2rpm.yml Summary: A multipart form post accessory for Net::HTTP License: MIT Group: Development/Languages/Ruby %description -Use with Net::HTTP to do multipart form posts. IO values that have +Use with Net::HTTP to do multipart form postspec. IO values that have #content_type, #original_filename, and #local_path will be posted as a binary file. @@ -43,7 +50,7 @@ %install %gem_install \ - --doc-files="History.txt README.md" \ + --doc-files="History.txt LICENSE README.md" \ -f %gem_packages ++++++ gem2rpm.yml ++++++ # --- # ## used by gem2rpm # :summary: this is a custom summary # ## used by gem2rpm # :description: |- # this is a custom description # # it can be multiline # ## used by gem2rpm # :license: MIT or Ruby # ## used by gem2rpm and gem_packages # :version_suffix: -x_y # ## used by gem2rpm and gem_packages # :disable_docs: true # ## used by gem2rpm # :disable_automatic_rdoc_dep: true # ## used by gem2rpm # :preamble: |- # BuildRequires: foobar # Requires: foobar # ## used by gem2rpm # :patches: # foo.patch: -p1 # bar.patch: # :post_patch: # if you need to fiddle with the source dir before rebuilding the gem # ## used by gem2rpm :sources: # - foo.desktop # - bar.desktop # :gem_install_args: '....' # ## used by gem2rpm # :pre_install: |- # %if 0%{?use_system_libev} # export USE_VENDORED_LIBEV="no" # %endif # ## used by gem2rpm # :post_install: |- # # delete custom files here or do other fancy stuff # install -D -m 0644 %{S:1} %{buildroot}%{_bindir}/gem2rpm-opensuse # ## used by gem2rpm # :testsuite_command: |- # (pushd %{buildroot}%{gem_base}/gems/%{mod_full_name} && rake test) # ## used by gem2rpm # :filelist: |- # /usr/bin/gem2rpm-opensuse # ## used by gem2rpm # :scripts: # :post: |- # /bin/echo foo # ## used by gem_packages # :main: # :preamble: |- # Requires: util-linux # Recommends: pwgen # :filelist: |- # /usr/bin/gem2rpm-opensuse # ## used by gem_packages # :custom_pkgs: # apache: # :preamble: |- # Requires: ..... # :filelist: |- # /etc/apache2/conf.d/passenger.conf # :summary: Custom summary is optional # :description: |- # Custom description is optional # # bar # :post: |- # /bin/echo foo # :preamble: |- # %if 0%{?suse_version} && 0%{?suse_version} < 1330 # %define rb_build_versions ruby24 ruby25 # %define rb_default_ruby_abi ruby:2.4.0 ruby:2.5.0 # %endif ++++++ multipart-post-2.0.0.gem -> multipart-post-2.1.1.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.rspec new/.rspec --- old/.rspec 1970-01-01 01:00:00.000000000 +0100 +++ new/.rspec 2019-05-13 13:34:34.000000000 +0200 @@ -0,0 +1,5 @@ +--color +--format documentation +--backtrace +--require spec_helper +--warnings diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.travis.yml new/.travis.yml --- old/.travis.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/.travis.yml 2019-05-13 13:34:34.000000000 +0200 @@ -1,7 +1,20 @@ +language: ruby +cache: bundler + rvm: - - 1.9.3 - - 2.0.0 - - jruby -branches: - only: - - master + - 2.0 + - 2.1 + - 2.2 + - 2.3 + - 2.4 + - 2.5 + - 2.6 + - ruby-head + - jruby-head + - truffleruby + +matrix: + allow_failures: + - rvm: ruby-head + - rvm: jruby-head + - rvm: truffleruby diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.yardopts new/.yardopts --- old/.yardopts 1970-01-01 01:00:00.000000000 +0100 +++ new/.yardopts 2019-05-13 13:34:34.000000000 +0200 @@ -0,0 +1,6 @@ +--no-private +lib/**/*.rb +- +History.txt +LICENSE +README.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Gemfile new/Gemfile --- old/Gemfile 1970-01-01 01:00:00.000000000 +0100 +++ new/Gemfile 2019-05-13 13:34:34.000000000 +0200 @@ -1,14 +1,6 @@ source 'https://rubygems.org' gemspec -platforms :mri_19 do - gem 'ruby-debug19' -end - -platforms :mri_18 do - gem 'ruby-debug' -end - group :development, :test do gem 'rake' end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/History.txt new/History.txt --- old/History.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/History.txt 2019-05-13 13:34:34.000000000 +0200 @@ -1,3 +1,8 @@ +<!-- +# @markup rdoc +# @title CHANGELOG +--> + === 2.0.0 / 2013-12-21 - Drop Ruby 1.8 compatibility @@ -57,4 +62,3 @@ * 1 major enhancement * Birthday! - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/LICENSE new/LICENSE --- old/LICENSE 1970-01-01 01:00:00.000000000 +0100 +++ new/LICENSE 2019-05-13 13:34:34.000000000 +0200 @@ -0,0 +1,21 @@ +Copyright (c) 2007-2013 Nick Sieger n...@nicksieger.com +Copyright, 2017, by Samuel G. D. Williams. + +MIT license. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.md new/README.md --- old/README.md 1970-01-01 01:00:00.000000000 +0100 +++ new/README.md 2019-05-13 13:34:34.000000000 +0200 @@ -1,77 +1,127 @@ -## multipart-post +# Multipart::Post -* http://github.com/nicksieger/multipart-post +Adds a streamy multipart form post capability to `Net::HTTP`. Also supports other +methods besides `POST`. -![build status](https://travis-ci.org/nicksieger/multipart-post.png) +[![Build Status](https://secure.travis-ci.org/socketry/multipart-post.svg)](http://travis-ci.org/socketry/multipart-post) -#### DESCRIPTION: - -Adds a streamy multipart form post capability to Net::HTTP. Also -supports other methods besides POST. - -#### FEATURES/PROBLEMS: +## Features/Problems * Appears to actually work. A good feature to have. -* Encapsulates posting of file/binary parts and name/value parameter parts, similar to +* Encapsulates posting of file/binary parts and name/value parameter parts, similar to most browsers' file upload forms. -* Provides an UploadIO helper class to prepare IO objects for inclusion in the params +* Provides an `UploadIO` helper class to prepare IO objects for inclusion in the params hash of the multipart post object. -#### SYNOPSIS: - - require 'net/http/post/multipart' - - url = URI.parse('http://www.example.com/upload') - File.open("./image.jpg") do |jpg| - req = Net::HTTP::Post::Multipart.new url.path, - "file" => UploadIO.new(jpg, "image/jpeg", "image.jpg") - res = Net::HTTP.start(url.host, url.port) do |http| - http.request(req) - end - end - -To post multiple files or attachments, simply include multiple parameters with -UploadIO values: +## Installation - require 'net/http/post/multipart' + gem install multipart-post - url = URI.parse('http://www.example.com/upload') - req = Net::HTTP::Post::Multipart.new url.path, - "file1" => UploadIO.new(File.new("./image.jpg"), "image/jpeg", "image.jpg"), - "file2" => UploadIO.new(File.new("./image2.jpg"), "image/jpeg", "image2.jpg") - res = Net::HTTP.start(url.host, url.port) do |http| - http.request(req) - end +or in your Gemfile -#### REQUIREMENTS: + gem 'multipart-post' -None +## Usage -#### INSTALL: +```ruby +require 'net/http/post/multipart' - gem install multipart-post +url = URI.parse('http://www.example.com/upload') +File.open("./image.jpg") do |jpg| + req = Net::HTTP::Post::Multipart.new url.path, + "file" => UploadIO.new(jpg, "image/jpeg", "image.jpg") + res = Net::HTTP.start(url.host, url.port) do |http| + http.request(req) + end +end +``` -#### LICENSE: - -(The MIT License) +To post multiple files or attachments, simply include multiple parameters with +`UploadIO` values: -Copyright (c) 2007-2013 Nick Sieger <n...@nicksieger.com> +```ruby +require 'net/http/post/multipart' -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +url = URI.parse('http://www.example.com/upload') +req = Net::HTTP::Post::Multipart.new url.path, + "file1" => UploadIO.new(File.new("./image.jpg"), "image/jpeg", "image.jpg"), + "file2" => UploadIO.new(File.new("./image2.jpg"), "image/jpeg", "image2.jpg") +res = Net::HTTP.start(url.host, url.port) do |http| + http.request(req) +end +``` + +To post files with other normal, non-file params such as input values, you need to pass hashes to the `Multipart.new` method. + +In Rails 4 for example: + +```ruby +def model_params + require_params = params.require(:model).permit(:param_one, :param_two, :param_three, :avatar) + require_params[:avatar] = model_params[:avatar].present? ? UploadIO.new(model_params[:avatar].tempfile, model_params[:avatar].content_type, model_params[:avatar].original_filename) : nil + require_params +end + +require 'net/http/post/multipart' + +url = URI.parse('http://www.example.com/upload') +Net::HTTP.start(url.host, url.port) do |http| + req = Net::HTTP::Post::Multipart.new(url, model_params) + key = "authorization_key" + req.add_field("Authorization", key) #add to Headers + http.use_ssl = (url.scheme == "https") + http.request(req) +end +``` + +Or in plain ruby: + +```ruby +def params(file) + params = { "description" => "A nice picture!" } + params[:datei] = UploadIO.new(file, "image/jpeg", "image.jpg") + params +end + +url = URI.parse('http://www.example.com/upload') +File.open("./image.jpg") do |file| + req = Net::HTTP::Post::Multipart.new(url.path, params(file)) + res = Net::HTTP.start(url.host, url.port) do |http| + return http.request(req).body + end +end +``` + +### Debugging + +You can debug requests and responses (e.g. status codes) for all requests by adding the following code: + +```ruby +http = Net::HTTP.new(uri.host, uri.port) +http.set_debug_output($stdout) +``` + +## License + +Released under the MIT license. + +Copyright (c) 2007-2013 Nick Sieger <n...@nicksieger.com> +Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Rakefile new/Rakefile --- old/Rakefile 1970-01-01 01:00:00.000000000 +0100 +++ new/Rakefile 2019-05-13 13:34:34.000000000 +0200 @@ -1,9 +1,6 @@ require "bundler/gem_tasks" +require "rspec/core/rake_task" -task :default => :test +RSpec::Core::RakeTask.new(:test) -require 'rake/testtask' -Rake::TestTask.new do |t| - t.libs << "test" - t.test_files = FileList['test/**/test*.rb'] -end +task :default => :test Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/composite_io.rb new/lib/composite_io.rb --- old/lib/composite_io.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/composite_io.rb 2019-05-13 13:34:34.000000000 +0200 @@ -7,11 +7,11 @@ # Concatenate together multiple IO objects into a single, composite IO object # for purposes of reading as a single stream. # -# Usage: -# -# crio = CompositeReadIO.new(StringIO.new('one'), StringIO.new('two'), StringIO.new('three')) +# @example +# crio = CompositeReadIO.new(StringIO.new('one'), +# StringIO.new('two'), +# StringIO.new('three')) # puts crio.read # => "onetwothree" -# class CompositeReadIO # Create a new composite-read IO from the arguments, all of which should # respond to #read in a manner consistent with IO. @@ -56,6 +56,8 @@ # Convenience methods for dealing with files and IO that are to be uploaded. class UploadIO + attr_reader :content_type, :original_filename, :local_path, :io, :opts + # Create an upload IO suitable for including in the params hash of a # Net::HTTP::Post::Multipart. # @@ -67,13 +69,9 @@ # uploading directly from a form in a framework, which often save the file to # an arbitrarily named RackMultipart file in /tmp). # - # Usage: - # + # @example # UploadIO.new("file.txt", "text/plain") # UploadIO.new(file_io, "text/plain", "file.txt") - # - attr_reader :content_type, :original_filename, :local_path, :io, :opts - def initialize(filename_or_io, content_type, filename = nil, opts = {}) io = filename_or_io local_path = "" @@ -95,7 +93,9 @@ end def self.convert!(io, content_type, original_filename, local_path) - raise ArgumentError, "convert! has been removed. You must now wrap IOs using:\nUploadIO.new(filename_or_io, content_type, filename=nil)\nPlease update your code." + raise ArgumentError, "convert! has been removed. You must now wrap IOs " \ + "using:\nUploadIO.new(filename_or_io, content_type, " \ + "filename=nil)\nPlease update your code." end def method_missing(*args) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/multipart_post.rb new/lib/multipart_post.rb --- old/lib/multipart_post.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/multipart_post.rb 2019-05-13 13:34:34.000000000 +0200 @@ -5,5 +5,5 @@ #++ module MultipartPost - VERSION = "2.0.0" + VERSION = "2.1.1" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/multipartable.rb new/lib/multipartable.rb --- old/lib/multipartable.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/multipartable.rb 2019-05-13 13:34:34.000000000 +0200 @@ -5,25 +5,44 @@ #++ require 'parts' - module Multipartable - DEFAULT_BOUNDARY = "-----------RubyMultipartPost" - def initialize(path, params, headers={}, boundary = DEFAULT_BOUNDARY) - headers = headers.clone # don't want to modify the original variable - parts_headers = headers.delete(:parts) || {} - super(path, headers) - parts = params.map do |k,v| - case v - when Array - v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) } - else - Parts::Part.new(boundary, k, v, parts_headers[k]) - end - end.flatten - parts << Parts::EpiloguePart.new(boundary) - ios = parts.map {|p| p.to_io } - self.set_content_type(headers["Content-Type"] || "multipart/form-data", - { "boundary" => boundary }) - self.content_length = parts.inject(0) {|sum,i| sum + i.length } - self.body_stream = CompositeReadIO.new(*ios) - end +require 'securerandom' + +module Multipartable + def self.secure_boundary + # https://tools.ietf.org/html/rfc7230 + # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" + # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" + # / DIGIT / ALPHA + + # https://tools.ietf.org/html/rfc2046 + # bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / + # "+" / "_" / "," / "-" / "." / + # "/" / ":" / "=" / "?" + + "--#{SecureRandom.uuid}" + end + + def initialize(path, params, headers={}, boundary = Multipartable.secure_boundary) + headers = headers.clone # don't want to modify the original variable + parts_headers = headers.delete(:parts) || {} + super(path, headers) + parts = params.map do |k,v| + case v + when Array + v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) } + else + Parts::Part.new(boundary, k, v, parts_headers[k]) + end + end.flatten + parts << Parts::EpiloguePart.new(boundary) + ios = parts.map {|p| p.to_io } + self.set_content_type(headers["Content-Type"] || "multipart/form-data", + { "boundary" => boundary }) + self.content_length = parts.inject(0) {|sum,i| sum + i.length } + self.body_stream = CompositeReadIO.new(*ios) + + @boundary = boundary end + + attr :boundary +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/http/post/multipart.rb new/lib/net/http/post/multipart.rb --- old/lib/net/http/post/multipart.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/net/http/post/multipart.rb 2019-05-13 13:34:34.000000000 +0200 @@ -11,14 +11,15 @@ require 'multipartable' require 'parts' -module Net #:nodoc: - class HTTP #:nodoc: +module Net + class HTTP class Put class Multipart < Put include Multipartable end end - class Post #:nodoc: + + class Post class Multipart < Post include Multipartable end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/parts.rb new/lib/parts.rb --- old/lib/parts.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/parts.rb 2019-05-13 13:34:34.000000000 +0200 @@ -5,7 +5,7 @@ #++ module Parts - module Part #:nodoc: + module Part def self.new(boundary, name, value, headers = {}) headers ||= {} # avoid nil values if file?(value) @@ -28,8 +28,14 @@ end end + # Represents a parametric part to be filled with given value. class ParamPart include Part + + # @param boundary [String] + # @param name [#to_s] + # @param value [String] + # @param headers [Hash] Content-Type is used, if present. def initialize(boundary, name, value, headers = {}) @part = build_part(boundary, name, value, headers) @io = StringIO.new(@part) @@ -39,6 +45,10 @@ @part.bytesize end + # @param boundary [String] + # @param name [#to_s] + # @param value [String] + # @param headers [Hash] Content-Type is used, if present. def build_part(boundary, name, value, headers = {}) part = '' part << "--#{boundary}\r\n" @@ -52,7 +62,13 @@ # Represents a part to be filled from file IO. class FilePart include Part + attr_reader :length + + # @param boundary [String] + # @param name [#to_s] + # @param io [IO] + # @param headers [Hash] def initialize(boundary, name, io, headers = {}) file_length = io.respond_to?(:length) ? io.length : File.size(io.local_path) @head = build_head(boundary, name, io.original_filename, io.content_type, file_length, @@ -62,25 +78,38 @@ @io = CompositeReadIO.new(StringIO.new(@head), io, StringIO.new(@foot)) end - def build_head(boundary, name, filename, type, content_len, opts = {}, headers = {}) - trans_encoding = opts["Content-Transfer-Encoding"] || "binary" - content_disposition = opts["Content-Disposition"] || "form-data" + # @param boundary [String] + # @param name [#to_s] + # @param filename [String] + # @param type [String] + # @param content_len [Integer] + # @param opts [Hash] + def build_head(boundary, name, filename, type, content_len, opts = {}) + opts = opts.clone + + trans_encoding = opts.delete("Content-Transfer-Encoding") || "binary" + content_disposition = opts.delete("Content-Disposition") || "form-data" part = '' part << "--#{boundary}\r\n" part << "Content-Disposition: #{content_disposition}; name=\"#{name.to_s}\"; filename=\"#{filename}\"\r\n" part << "Content-Length: #{content_len}\r\n" - if content_id = opts["Content-ID"] + if content_id = opts.delete("Content-ID") part << "Content-ID: #{content_id}\r\n" end - if headers["Content-Type"] != nil - part << "Content-Type: " + headers["Content-Type"] + "\r\n" + if opts["Content-Type"] != nil + part << "Content-Type: " + opts["Content-Type"] + "\r\n" else part << "Content-Type: #{type}\r\n" end part << "Content-Transfer-Encoding: #{trans_encoding}\r\n" + + opts.each do |k, v| + part << "#{k}: #{v}\r\n" + end + part << "\r\n" end end @@ -88,8 +117,9 @@ # Represents the epilogue or closing boundary. class EpiloguePart include Part + def initialize(boundary) - @part = "--#{boundary}--\r\n\r\n" + @part = "--#{boundary}--\r\n" @io = StringIO.new(@part) end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 1970-01-01 01:00:00.000000000 +0100 +++ new/metadata 2019-05-13 13:34:34.000000000 +0200 @@ -1,28 +1,80 @@ --- !ruby/object:Gem::Specification name: multipart-post version: !ruby/object:Gem::Version - version: 2.0.0 - prerelease: + version: 2.1.1 platform: ruby authors: - Nick Sieger +- Samuel Williams autorequire: bindir: bin cert_chain: [] -date: 2013-12-21 00:00:00.000000000 Z -dependencies: [] -description: ! 'Use with Net::HTTP to do multipart form posts. IO values that have +date: 2019-05-13 00:00:00.000000000 Z +dependencies: +- !ruby/object:Gem::Dependency + name: bundler + requirement: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: '1.3' + - - "<" + - !ruby/object:Gem::Version + version: '3' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: '1.3' + - - "<" + - !ruby/object:Gem::Version + version: '3' +- !ruby/object:Gem::Dependency + name: rspec + requirement: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '3.4' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '3.4' +- !ruby/object:Gem::Dependency + name: rake + requirement: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: '0' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: '0' +description: 'Use with Net::HTTP to do multipart form postspec. IO values that have #content_type, #original_filename, and #local_path will be posted as a binary file.' email: - n...@nicksieger.com +- samuel.willi...@oriontransfer.co.nz executables: [] extensions: [] extra_rdoc_files: [] files: -- .gitignore -- .travis.yml +- ".gitignore" +- ".rspec" +- ".travis.yml" +- ".yardopts" - Gemfile - History.txt +- LICENSE - Manifest.txt - README.md - Rakefile @@ -32,48 +84,37 @@ - lib/net/http/post/multipart.rb - lib/parts.rb - multipart-post.gemspec -- test/multibyte.txt -- test/net/http/post/test_multipart.rb -- test/test_composite_io.rb -- test/test_parts.rb +- spec/composite_io_spec.rb +- spec/multibyte.txt +- spec/net/http/post/multipart_spec.rb +- spec/parts_spec.rb +- spec/spec_helper.rb homepage: https://github.com/nicksieger/multipart-post licenses: - MIT +metadata: {} post_install_message: -rdoc_options: -- --main -- README.md -- -SHN -- -f -- darkfish +rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement - none: false requirements: - - - ! '>=' + - - ">=" - !ruby/object:Gem::Version version: '0' - segments: - - 0 - hash: 3851181222699685043 required_rubygems_version: !ruby/object:Gem::Requirement - none: false requirements: - - - ! '>=' + - - ">=" - !ruby/object:Gem::Version version: '0' - segments: - - 0 - hash: 3851181222699685043 requirements: [] -rubyforge_project: caldersphere -rubygems_version: 1.8.23 +rubygems_version: 3.0.3 signing_key: -specification_version: 3 +specification_version: 4 summary: A multipart form post accessory for Net::HTTP. test_files: -- test/multibyte.txt -- test/net/http/post/test_multipart.rb -- test/test_composite_io.rb -- test/test_parts.rb +- spec/composite_io_spec.rb +- spec/multibyte.txt +- spec/net/http/post/multipart_spec.rb +- spec/parts_spec.rb +- spec/spec_helper.rb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/multipart-post.gemspec new/multipart-post.gemspec --- old/multipart-post.gemspec 1970-01-01 01:00:00.000000000 +0100 +++ new/multipart-post.gemspec 2019-05-13 13:34:34.000000000 +0200 @@ -2,21 +2,22 @@ $:.push File.expand_path("../lib", __FILE__) require "multipart_post" -Gem::Specification.new do |s| - s.name = "multipart-post" - s.version = MultipartPost::VERSION - s.authors = ["Nick Sieger"] - s.email = ["n...@nicksieger.com"] - s.homepage = "https://github.com/nicksieger/multipart-post" - s.summary = %q{A multipart form post accessory for Net::HTTP.} - s.license = "MIT" - s.description = %q{Use with Net::HTTP to do multipart form posts. IO values that have #content_type, #original_filename, and #local_path will be posted as a binary file.} - - s.rubyforge_project = "caldersphere" - - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } - s.rdoc_options = ["--main", "README.md", "-SHN", "-f", "darkfish"] - s.require_paths = ["lib"] +Gem::Specification.new do |spec| + spec.name = "multipart-post" + spec.version = MultipartPost::VERSION + spec.authors = ["Nick Sieger", "Samuel Williams"] + spec.email = ["n...@nicksieger.com", "samuel.willi...@oriontransfer.co.nz"] + spec.homepage = "https://github.com/nicksieger/multipart-post" + spec.summary = %q{A multipart form post accessory for Net::HTTP.} + spec.license = "MIT" + spec.description = %q{Use with Net::HTTP to do multipart form postspec. IO values that have #content_type, #original_filename, and #local_path will be posted as a binary file.} + + spec.files = `git ls-files`.split("\n") + spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.add_development_dependency 'bundler', ['>= 1.3', '< 3'] + spec.add_development_dependency 'rspec', '~> 3.4' + spec.add_development_dependency 'rake' end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/composite_io_spec.rb new/spec/composite_io_spec.rb --- old/spec/composite_io_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/spec/composite_io_spec.rb 2019-05-13 13:34:34.000000000 +0200 @@ -0,0 +1,138 @@ +# Copyright, 2012, by Nick Sieger. +# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com> +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +require 'composite_io' +require 'stringio' +require 'timeout' + +RSpec.shared_context "composite io" do + it "test_full_read_from_several_ios" do + expect(subject.read).to be == 'the quick brown fox' + end + + it "test_partial_read" do + expect(subject.read(9)).to be == 'the quick' + end + + it "test_partial_read_to_boundary" do + expect(subject.read(10)).to be == 'the quick ' + end + + it "test_read_with_size_larger_than_available" do + expect(subject.read(32)).to be == 'the quick brown fox' + end + + it "test_read_into_buffer" do + buf = '' + subject.read(nil, buf) + expect(buf).to be == 'the quick brown fox' + end + + it "test_multiple_reads" do + expect(subject.read(4)).to be == 'the ' + expect(subject.read(4)).to be == 'quic' + expect(subject.read(4)).to be == 'k br' + expect(subject.read(4)).to be == 'own ' + expect(subject.read(4)).to be == 'fox' + end + + it "test_read_after_end" do + subject.read + expect(subject.read).to be == "" + end + + it "test_read_after_end_with_amount" do + subject.read(32) + expect(subject.read(32)).to be_nil + end + + it "test_second_full_read_after_rewinding" do + subject.read + subject.rewind + expect(subject.read).to be == 'the quick brown fox' + end + + # Was apparently broken on JRuby due to http://jira.codehaus.org/browse/JRUBY-7109 + it "test_compatible_with_copy_stream" do + target_io = StringIO.new + Timeout.timeout(1) do # Not sure why we need this in the spec? + IO.copy_stream(subject, target_io) + end + expect(target_io.string).to be == "the quick brown fox" + end +end + +RSpec.describe CompositeReadIO do + describe "generic io" do + subject {StringIO.new('the quick brown fox')} + + include_context "composite io" + end + + describe "composite io" do + subject {CompositeReadIO.new(StringIO.new('the '), StringIO.new('quick '), StringIO.new('brown '), StringIO.new('fox'))} + + include_context "composite io" + end + + describe "nested composite io" do + subject {CompositeReadIO.new(CompositeReadIO.new(StringIO.new('the '), StringIO.new('quick ')), StringIO.new('brown '), StringIO.new('fox'))} + + include_context "composite io" + end + + describe "unicode composite io" do + let(:utf8_io) {File.open(File.dirname(__FILE__)+'/multibyte.txt')} + let(:binary_io) {StringIO.new("\x86")} + + subject {CompositeReadIO.new(binary_io, utf8_io)} + + it "test_read_from_multibyte" do + expect(subject.read).to be == "\x86\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\n".b + end + end + + it "test_convert_error" do + expect do + UploadIO.convert!('tmp.txt', 'text/plain', 'tmp.txt', 'tmp.txt') + end.to raise_error(ArgumentError, /convert! has been removed/) + end + + it "test_empty" do + expect(subject.read).to be == "" + end + + it "test_empty_limited" do + expect(subject.read(1)).to be_nil + end + + it "test_empty_parts" do + io = CompositeReadIO.new(StringIO.new, StringIO.new('the '), StringIO.new, StringIO.new('quick')) + expect(io.read(3)).to be == "the" + expect(io.read(3)).to be == " qu" + expect(io.read(3)).to be == "ick" + end + + it "test_all_empty_parts" do + io = CompositeReadIO.new(StringIO.new, StringIO.new) + expect(io.read(1)).to be_nil + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/multibyte.txt new/spec/multibyte.txt --- old/spec/multibyte.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/spec/multibyte.txt 2019-05-13 13:34:34.000000000 +0200 @@ -0,0 +1 @@ +ファイル diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/net/http/post/multipart_spec.rb new/spec/net/http/post/multipart_spec.rb --- old/spec/net/http/post/multipart_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/spec/net/http/post/multipart_spec.rb 2019-05-13 13:34:34.000000000 +0200 @@ -0,0 +1,123 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'net/http/post/multipart' + +RSpec.shared_context "net http multipart" do + let(:temp_file) {"temp.txt"} + let(:http_post) do + Struct.new("HTTPPost", :content_length, :body_stream, :content_type) do + def set_content_type(type, params = {}) + self.content_type = type + params.map{|k,v|"; #{k}=#{v}"}.join('') + end + end + end + + after(:each) do + File.delete(temp_file) rescue nil + end + + def assert_results(post) + expect(post.content_length).to be > 0 + expect(post.body_stream).to_not be_nil + + expect(post['content-type']).to be == "multipart/form-data; boundary=#{post.boundary}" + + body = post.body_stream.read + boundary_regex = Regexp.quote(post.boundary) + + expect(body).to be =~ /1234567890/ + + # ensure there is at least one boundary + expect(body).to be =~ /^--#{boundary_regex}\r\n/ + + # ensure there is an epilogue + expect(body).to be =~ /^--#{boundary_regex}--\r\n/ + expect(body).to be =~ /text\/plain/ + + if (body =~ /multivalueParam/) + expect(body.scan(/^.*multivalueParam.*$/).size).to be == 2 + end + end + + def assert_additional_headers_added(post, parts_headers) + post.body_stream.rewind + body = post.body_stream.read + parts_headers.each do |part, headers| + headers.each do |k,v| + expect(body).to be =~ /#{k}: #{v}/ + end + end + end +end + +RSpec.describe Net::HTTP::Post::Multipart do + include_context "net http multipart" + + it "test_form_multipart_body" do + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + @io = File.open(TEMP_FILE) + @io = UploadIO.new @io, "text/plain", TEMP_FILE + assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) + end + + it "test_form_multipart_body_with_stringio" do + @io = StringIO.new("1234567890") + @io = UploadIO.new @io, "text/plain", TEMP_FILE + assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) + end + + it "test_form_multiparty_body_with_parts_headers" do + @io = StringIO.new("1234567890") + @io = UploadIO.new @io, "text/plain", TEMP_FILE + parts = { :text => 'bar', :file => @io } + headers = { + :parts => { + :text => { "Content-Type" => "part/type" }, + :file => { "Content-Transfer-Encoding" => "part-encoding" } + } + } + + request = Net::HTTP::Post::Multipart.new("/foo/bar", parts, headers) + assert_results request + assert_additional_headers_added(request, headers[:parts]) + end + + it "test_form_multipart_body_with_array_value" do + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + @io = File.open(TEMP_FILE) + @io = UploadIO.new @io, "text/plain", TEMP_FILE + params = {:foo => ['bar', 'quux'], :file => @io} + headers = { :parts => { + :foo => { "Content-Type" => "application/json; charset=UTF-8" } } } + post = Net::HTTP::Post::Multipart.new("/foo/bar", params, headers) + + expect(post.content_length).to be > 0 + expect(post.body_stream).to_not be_nil + + body = post.body_stream.read + expect(body.lines.grep(/name="foo"/).length).to be == 2 + expect(body).to be =~ /Content-Type: application\/json; charset=UTF-8/ + end + + it "test_form_multipart_body_with_arrayparam" do + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + @io = File.open(TEMP_FILE) + @io = UploadIO.new @io, "text/plain", TEMP_FILE + assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :multivalueParam => ['bar','bah'], :file => @io) + end +end + +RSpec.describe Net::HTTP::Put::Multipart do + include_context "net http multipart" + + it "test_form_multipart_body_put" do + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + @io = File.open(TEMP_FILE) + @io = UploadIO.new @io, "text/plain", TEMP_FILE + assert_results Net::HTTP::Put::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/parts_spec.rb new/spec/parts_spec.rb --- old/spec/parts_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/spec/parts_spec.rb 2019-05-13 13:34:34.000000000 +0200 @@ -0,0 +1,102 @@ +# Copyright, 2012, by Nick Sieger. +# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com> +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +require 'parts' +require 'stringio' +require 'composite_io' +require 'tempfile' + +MULTIBYTE = File.dirname(__FILE__)+'/multibyte.txt' +TEMP_FILE = "temp.txt" + +module AssertPartLength + def assert_part_length(part) + bytes = part.to_io.read + bytesize = bytes.respond_to?(:bytesize) ? bytes.bytesize : bytes.length + expect(bytesize).to be == part.length + end +end + +RSpec.describe Parts do + let(:string_with_content_type) do + Class.new(String) do + def content_type; 'application/data'; end + end + end + + it "test_file_with_upload_io" do + expect(Parts::Part.file?(UploadIO.new(__FILE__, "text/plain"))).to be true + end + + it "test_file_with_modified_string" do + expect(Parts::Part.file?(string_with_content_type.new("Hello"))).to be false + end + + it "test_new_with_modified_string" do + expect(Parts::Part.new("boundary", "multibyte", string_with_content_type.new("Hello"))).to be_kind_of(Parts::ParamPart) + end +end + +RSpec.describe Parts::FilePart do + include AssertPartLength + + before(:each) do + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + io = UploadIO.new(TEMP_FILE, "text/plain") + @part = Parts::FilePart.new("boundary", "afile", io) + end + + after(:each) do + File.delete(TEMP_FILE) rescue nil + end + + it "test_correct_length" do + assert_part_length @part + end + + it "test_multibyte_file_length" do + assert_part_length Parts::FilePart.new("boundary", "multibyte", UploadIO.new(MULTIBYTE, "text/plain")) + end + + it "test_multibyte_filename" do + name = File.read(MULTIBYTE, 300) + file = Tempfile.new(name.respond_to?(:force_encoding) ? name.force_encoding("UTF-8") : name) + assert_part_length Parts::FilePart.new("boundary", "multibyte", UploadIO.new(file, "text/plain")) + file.close + end + + it "test_force_content_type_header" do + part = Parts::FilePart.new("boundary", "afile", UploadIO.new(TEMP_FILE, "text/plain"), { "Content-Type" => "application/pdf" }) + expect(part.to_io.read).to match(/Content-Type: application\/pdf/) + end +end + +RSpec.describe Parts::ParamPart do + include AssertPartLength + + before(:each) do + @part = Parts::ParamPart.new("boundary", "multibyte", File.read(MULTIBYTE)) + end + + it "test_correct_length" do + assert_part_length @part + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/spec_helper.rb new/spec/spec_helper.rb --- old/spec/spec_helper.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/spec/spec_helper.rb 2019-05-13 13:34:34.000000000 +0200 @@ -0,0 +1,29 @@ + +if ENV['COVERAGE'] + begin + require 'simplecov' + + SimpleCov.start do + add_filter "/spec/" + end + + if ENV['TRAVIS'] + require 'coveralls' + Coveralls.wear! + end + rescue LoadError + warn "Could not load simplecov: #{$!}" + end +end + +require "bundler/setup" +require "multipart_post" + +RSpec.configure do |config| + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + config.expect_with :rspec do |c| + c.syntax = :expect + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/multibyte.txt new/test/multibyte.txt --- old/test/multibyte.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/test/multibyte.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -ファイル diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/net/http/post/test_multipart.rb new/test/net/http/post/test_multipart.rb --- old/test/net/http/post/test_multipart.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/test/net/http/post/test_multipart.rb 1970-01-01 01:00:00.000000000 +0100 @@ -1,110 +0,0 @@ -#-- -# Copyright (c) 2007-2013 Nick Sieger. -# See the file README.txt included with the distribution for -# software license details. -#++ - -require 'net/http/post/multipart' -require 'test/unit' - -class Net::HTTP::Post::MultiPartTest < Test::Unit::TestCase - TEMP_FILE = "temp.txt" - - HTTPPost = Struct.new("HTTPPost", :content_length, :body_stream, :content_type) - HTTPPost.module_eval do - def set_content_type(type, params = {}) - self.content_type = type + params.map{|k,v|"; #{k}=#{v}"}.join('') - end - end - - def teardown - File.delete(TEMP_FILE) rescue nil - end - - def test_form_multipart_body - File.open(TEMP_FILE, "w") {|f| f << "1234567890"} - @io = File.open(TEMP_FILE) - @io = UploadIO.new @io, "text/plain", TEMP_FILE - assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) - end - def test_form_multipart_body_put - File.open(TEMP_FILE, "w") {|f| f << "1234567890"} - @io = File.open(TEMP_FILE) - @io = UploadIO.new @io, "text/plain", TEMP_FILE - assert_results Net::HTTP::Put::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) - end - - def test_form_multipart_body_with_stringio - @io = StringIO.new("1234567890") - @io = UploadIO.new @io, "text/plain", TEMP_FILE - assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) - end - - def test_form_multiparty_body_with_parts_headers - @io = StringIO.new("1234567890") - @io = UploadIO.new @io, "text/plain", TEMP_FILE - parts = { :text => 'bar', :file => @io } - headers = { - :parts => { - :text => { "Content-Type" => "part/type" }, - :file => { "Content-Transfer-Encoding" => "part-encoding" } - } - } - - request = Net::HTTP::Post::Multipart.new("/foo/bar", parts, headers) - assert_results request - assert_additional_headers_added(request, headers[:parts]) - end - - def test_form_multipart_body_with_array_value - File.open(TEMP_FILE, "w") {|f| f << "1234567890"} - @io = File.open(TEMP_FILE) - @io = UploadIO.new @io, "text/plain", TEMP_FILE - params = {:foo => ['bar', 'quux'], :file => @io} - headers = { :parts => { - :foo => { "Content-Type" => "application/json; charset=UTF-8" } } } - post = Net::HTTP::Post::Multipart.new("/foo/bar", params, headers, - Net::HTTP::Post::Multipart::DEFAULT_BOUNDARY) - - assert post.content_length && post.content_length > 0 - assert post.body_stream - - body = post.body_stream.read - assert_equal 2, body.lines.grep(/name="foo"/).length - assert body =~ /Content-Type: application\/json; charset=UTF-8/, body - end - - def test_form_multipart_body_with_arrayparam - File.open(TEMP_FILE, "w") {|f| f << "1234567890"} - @io = File.open(TEMP_FILE) - @io = UploadIO.new @io, "text/plain", TEMP_FILE - assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :multivalueParam => ['bar','bah'], :file => @io) - end - - def assert_results(post) - assert post.content_length && post.content_length > 0 - assert post.body_stream - assert_equal "multipart/form-data; boundary=#{Multipartable::DEFAULT_BOUNDARY}", post['content-type'] - body = post.body_stream.read - boundary_regex = Regexp.quote Multipartable::DEFAULT_BOUNDARY - assert body =~ /1234567890/ - # ensure there is at least one boundary - assert body =~ /^--#{boundary_regex}\r\n/ - # ensure there is an epilogue - assert body =~ /^--#{boundary_regex}--\r\n/ - assert body =~ /text\/plain/ - if (body =~ /multivalueParam/) - assert_equal 2, body.scan(/^.*multivalueParam.*$/).size - end - end - - def assert_additional_headers_added(post, parts_headers) - post.body_stream.rewind - body = post.body_stream.read - parts_headers.each do |part, headers| - headers.each do |k,v| - assert body =~ /#{k}: #{v}/ - end - end - end -end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/test_composite_io.rb new/test/test_composite_io.rb --- old/test/test_composite_io.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/test/test_composite_io.rb 1970-01-01 01:00:00.000000000 +0100 @@ -1,115 +0,0 @@ -#-- -# Copyright (c) 2007-2013 Nick Sieger. -# See the file README.txt included with the distribution for -# software license details. -#++ - -require 'composite_io' -require 'stringio' -require 'test/unit' -require 'timeout' - -class CompositeReadIOTest < Test::Unit::TestCase - def setup - @io = CompositeReadIO.new(CompositeReadIO.new(StringIO.new('the '), StringIO.new('quick ')), - StringIO.new('brown '), StringIO.new('fox')) - end - - def test_full_read_from_several_ios - assert_equal 'the quick brown fox', @io.read - end - - unless RUBY_VERSION < '1.9' - def test_read_from_multibyte - utf8 = File.open(File.dirname(__FILE__)+'/multibyte.txt') - binary = StringIO.new("\x86") - @io = CompositeReadIO.new(binary,utf8) - - expect = "\x86\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\n" - expect.force_encoding('BINARY') if expect.respond_to?(:force_encoding) - assert_equal expect, @io.read - end - end - - def test_partial_read - assert_equal 'the quick', @io.read(9) - end - - def test_partial_read_to_boundary - assert_equal 'the quick ', @io.read(10) - end - - def test_read_with_size_larger_than_available - assert_equal 'the quick brown fox', @io.read(32) - end - - def test_read_into_buffer - buf = '' - @io.read(nil, buf) - assert_equal 'the quick brown fox', buf - end - - def test_multiple_reads - assert_equal 'the ', @io.read(4) - assert_equal 'quic', @io.read(4) - assert_equal 'k br', @io.read(4) - assert_equal 'own ', @io.read(4) - assert_equal 'fox', @io.read(4) - end - - def test_read_after_end - @io.read - assert_equal "", @io.read - end - - def test_read_after_end_with_amount - @io.read(32) - assert_equal nil, @io.read(32) - end - - def test_second_full_read_after_rewinding - @io.read - @io.rewind - assert_equal 'the quick brown fox', @io.read - end - - def test_convert_error - assert_raises(ArgumentError) { - UploadIO.convert!('tmp.txt', 'text/plain', 'tmp.txt', 'tmp.txt') - } - end - - ## FIXME excluding on JRuby due to - ## http://jira.codehaus.org/browse/JRUBY-7109 - if IO.respond_to?(:copy_stream) && !defined?(JRUBY_VERSION) - def test_compatible_with_copy_stream - target_io = StringIO.new - Timeout.timeout(1) do - IO.copy_stream(@io, target_io) - end - assert_equal "the quick brown fox", target_io.string - end - end - - def test_empty - io = CompositeReadIO.new - assert_equal "", io.read - end - - def test_empty_limited - io = CompositeReadIO.new - assert_nil io.read(1) - end - - def test_empty_parts - io = CompositeReadIO.new(StringIO.new, StringIO.new('the '), StringIO.new, StringIO.new('quick')) - assert_equal "the", io.read(3) - assert_equal " qu", io.read(3) - assert_equal "ick", io.read(4) - end - - def test_all_empty_parts - io = CompositeReadIO.new(StringIO.new, StringIO.new) - assert_nil io.read(1) - end -end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/test_parts.rb new/test/test_parts.rb --- old/test/test_parts.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/test/test_parts.rb 1970-01-01 01:00:00.000000000 +0100 @@ -1,86 +0,0 @@ -#-- -# Copyright (c) 2007-2012 Nick Sieger. -# See the file README.txt included with the distribution for -# software license details. -#++ - -require 'test/unit' - -require 'parts' -require 'stringio' -require 'composite_io' -require 'tempfile' - - -MULTIBYTE = File.dirname(__FILE__)+'/multibyte.txt' -TEMP_FILE = "temp.txt" - -module AssertPartLength - def assert_part_length(part) - bytes = part.to_io.read - bytesize = bytes.respond_to?(:bytesize) ? bytes.bytesize : bytes.length - assert_equal bytesize, part.length - end -end - -class PartTest < Test::Unit::TestCase - def setup - @string_with_content_type = Class.new(String) do - def content_type; 'application/data'; end - end - end - - def test_file_with_upload_io - assert Parts::Part.file?(UploadIO.new(__FILE__, "text/plain")) - end - - def test_file_with_modified_string - assert !Parts::Part.file?(@string_with_content_type.new("Hello")) - end - - def test_new_with_modified_string - assert_kind_of Parts::ParamPart, - Parts::Part.new("boundary", "multibyte", @string_with_content_type.new("Hello")) - end -end - -class FilePartTest < Test::Unit::TestCase - include AssertPartLength - - def setup - File.open(TEMP_FILE, "w") {|f| f << "1234567890"} - io = UploadIO.new(TEMP_FILE, "text/plain") - @part = Parts::FilePart.new("boundary", "afile", io) - end - - def teardown - File.delete(TEMP_FILE) rescue nil - end - - def test_correct_length - assert_part_length @part - end - - def test_multibyte_file_length - assert_part_length Parts::FilePart.new("boundary", "multibyte", UploadIO.new(MULTIBYTE, "text/plain")) - end - - def test_multibyte_filename - name = File.read(MULTIBYTE, 300) - file = Tempfile.new(name.respond_to?(:force_encoding) ? name.force_encoding("UTF-8") : name) - assert_part_length Parts::FilePart.new("boundary", "multibyte", UploadIO.new(file, "text/plain")) - file.close - end -end - -class ParamPartTest < Test::Unit::TestCase - include AssertPartLength - - def setup - @part = Parts::ParamPart.new("boundary", "multibyte", File.read(MULTIBYTE)) - end - - def test_correct_length - assert_part_length @part - end -end