multipart-post 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7f48186ca2c1e47dbb18d8ba20ed99e1d2dbabac5735c47a5fdf3f3de2ff6c1
4
- data.tar.gz: 86bdb76a37261133d45eba29e94c6026118564fa0168120549d64a8cf89e19f7
3
+ metadata.gz: f1a26f1b06e253bdd1a96889881cd28090f1bb294754de989b5d01ee173f2251
4
+ data.tar.gz: f0df38197a55f9470d21d0284fb12c16deabe86e1ab71e39f409bcbabfb9cf86
5
5
  SHA512:
6
- metadata.gz: 47022f82aba55743549c58e82cda833a1f769927ca7c348b35e8dbcfeec851ca5570ef4b43755d33c4d5957a97b915412e86d9b333769f5cd11d0b9cdeede744
7
- data.tar.gz: c9c767b946971349722a5798b0594f9da22095262f0f322391656dc79e73a677a48b0fdc53942f5bfbfe58d258c7e6df8bd3fb02821b49a64f794c6f898012d5
6
+ metadata.gz: 8048da79e851331b26fae693ce8e5329481c729934f3653fce804332df8b3f8edcdc566dc543a14e461ec674bb0700e87b92d26b5fe24dc4fcb13312574faf04
7
+ data.tar.gz: 1323dbcffd530f36bbb14e7ca5f90033ce3bf558ef669387df855638da7a6a619b4fe355ab5b2470428edfd2bb5c1fdbd267b848a940d84a0bbcb451c341c743
checksums.yaml.gz.sig ADDED
Binary file
data/changelog.md ADDED
@@ -0,0 +1,14 @@
1
+ # CHANGELOG
2
+
3
+ ## Unreleased
4
+
5
+ ### Added
6
+
7
+ - Add the ability to set Content-ID header for ParamPart [#62](https://github.com/socketry/multipart-post/pull/62)
8
+ - Allow mixed key types for parts headers [#79](https://github.com/socketry/multipart-post/pull/79)
9
+
10
+ ### Changed
11
+
12
+ - Refactor `Parts` into a `Multipart::Post` namespace [#65](https://github.com/socketry/multipart-post/pull/65)
13
+ - Use mutable strings where needed [#70](https://github.com/socketry/multipart-post/pull/70)
14
+ - Use `frozen_string_literal` everywhere [#78](https://github.com/socketry/multipart-post/pull/78)
data/lib/composite_io.rb CHANGED
@@ -1,108 +1,17 @@
1
- #--
2
- # Copyright (c) 2007-2012 Nick Sieger.
3
- # See the file README.txt included with the distribution for
4
- # software license details.
5
- #++
6
-
7
- # Concatenate together multiple IO objects into a single, composite IO object
8
- # for purposes of reading as a single stream.
9
- #
10
- # @example
11
- # crio = CompositeReadIO.new(StringIO.new('one'),
12
- # StringIO.new('two'),
13
- # StringIO.new('three'))
14
- # puts crio.read # => "onetwothree"
15
- class CompositeReadIO
16
- # Create a new composite-read IO from the arguments, all of which should
17
- # respond to #read in a manner consistent with IO.
18
- def initialize(*ios)
19
- @ios = ios.flatten
20
- @index = 0
21
- end
22
-
23
- # Read from IOs in order until `length` bytes have been received.
24
- def read(length = nil, outbuf = nil)
25
- got_result = false
26
- outbuf = outbuf ? outbuf.replace("") : ""
27
-
28
- while io = current_io
29
- if result = io.read(length)
30
- got_result ||= !result.nil?
31
- result.force_encoding("BINARY") if result.respond_to?(:force_encoding)
32
- outbuf << result
33
- length -= result.length if length
34
- break if length == 0
35
- end
36
- advance_io
37
- end
38
- (!got_result && length) ? nil : outbuf
39
- end
40
-
41
- def rewind
42
- @ios.each { |io| io.rewind }
43
- @index = 0
44
- end
45
-
46
- private
47
-
48
- def current_io
49
- @ios[@index]
50
- end
51
-
52
- def advance_io
53
- @index += 1
54
- end
55
- end
56
-
57
- # Convenience methods for dealing with files and IO that are to be uploaded.
58
- class UploadIO
59
- attr_reader :content_type, :original_filename, :local_path, :io, :opts
60
-
61
- # Create an upload IO suitable for including in the params hash of a
62
- # Net::HTTP::Post::Multipart.
63
- #
64
- # Can take two forms. The first accepts a filename and content type, and
65
- # opens the file for reading (to be closed by finalizer).
66
- #
67
- # The second accepts an already-open IO, but also requires a third argument,
68
- # the filename from which it was opened (particularly useful/recommended if
69
- # uploading directly from a form in a framework, which often save the file to
70
- # an arbitrarily named RackMultipart file in /tmp).
71
- #
72
- # @example
73
- # UploadIO.new("file.txt", "text/plain")
74
- # UploadIO.new(file_io, "text/plain", "file.txt")
75
- def initialize(filename_or_io, content_type, filename = nil, opts = {})
76
- io = filename_or_io
77
- local_path = ""
78
- if io.respond_to? :read
79
- # in Ruby 1.9.2, StringIOs no longer respond to path
80
- # (since they respond to :length, so we don't need their local path, see parts.rb:41)
81
- local_path = filename_or_io.respond_to?(:path) ? filename_or_io.path : "local.path"
82
- else
83
- io = File.open(filename_or_io)
84
- local_path = filename_or_io
85
- end
86
- filename ||= local_path
87
-
88
- @content_type = content_type
89
- @original_filename = File.basename(filename)
90
- @local_path = local_path
91
- @io = io
92
- @opts = opts
93
- end
94
-
95
- def self.convert!(io, content_type, original_filename, local_path)
96
- raise ArgumentError, "convert! has been removed. You must now wrap IOs " \
97
- "using:\nUploadIO.new(filename_or_io, content_type, " \
98
- "filename=nil)\nPlease update your code."
99
- end
100
-
101
- def method_missing(*args)
102
- @io.send(*args)
103
- end
104
-
105
- def respond_to?(meth, include_all = false)
106
- @io.respond_to?(meth, include_all) || super(meth, include_all)
107
- end
108
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2006-2013, by Nick Sieger.
5
+ # Copyright, 2010, by Tohru Hashimoto.
6
+ # Copyright, 2011, by Jeff Hodges.
7
+ # Copyright, 2011, by Alex Koppel.
8
+ # Copyright, 2011, by Christine Yen.
9
+ # Copyright, 2011, by Gerrit Riessen.
10
+ # Copyright, 2011, by Luke Redpath.
11
+ # Copyright, 2013, by Mislav Marohnić.
12
+ # Copyright, 2013, by Leo Cassarani.
13
+ # Copyright, 2019, by Olle Jonsson.
14
+ # Copyright, 2022, by Samuel Williams.
15
+
16
+ warn "Top level ::CompositeIO is deprecated, require 'multipart/post' and use `Multipart::Post::CompositeReadIO` instead!"
17
+ require_relative 'multipart/post'
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2006-2013, by Nick Sieger.
5
+ # Copyright, 2010, by Tohru Hashimoto.
6
+ # Copyright, 2011, by Jeff Hodges.
7
+ # Copyright, 2011, by Alex Koppel.
8
+ # Copyright, 2011, by Christine Yen.
9
+ # Copyright, 2011, by Gerrit Riessen.
10
+ # Copyright, 2011, by Luke Redpath.
11
+ # Copyright, 2013, by Mislav Marohnić.
12
+ # Copyright, 2013, by Leo Cassarani.
13
+ # Copyright, 2019, by Olle Jonsson.
14
+ # Copyright, 2019, by Patrick Davey.
15
+ # Copyright, 2021, by Lewis Cowles.
16
+ # Copyright, 2021-2022, by Samuel Williams.
17
+
18
+ module Multipart
19
+ module Post
20
+ # Concatenate together multiple IO objects into a single, composite IO object
21
+ # for purposes of reading as a single stream.
22
+ #
23
+ # @example
24
+ # crio = CompositeReadIO.new(StringIO.new('one'),
25
+ # StringIO.new('two'),
26
+ # StringIO.new('three'))
27
+ # puts crio.read # => "onetwothree"
28
+ class CompositeReadIO
29
+ # Create a new composite-read IO from the arguments, all of which should
30
+ # respond to #read in a manner consistent with IO.
31
+ def initialize(*ios)
32
+ @ios = ios.flatten
33
+ @index = 0
34
+ end
35
+
36
+ # Read from IOs in order until `length` bytes have been received.
37
+ def read(length = nil, outbuf = nil)
38
+ got_result = false
39
+ outbuf = outbuf ? outbuf.replace("") : String.new
40
+
41
+ while io = current_io
42
+ if result = io.read(length)
43
+ got_result ||= !result.nil?
44
+ result.force_encoding("BINARY") if result.respond_to?(:force_encoding)
45
+ outbuf << result
46
+ length -= result.length if length
47
+ break if length == 0
48
+ end
49
+ advance_io
50
+ end
51
+ (!got_result && length) ? nil : outbuf
52
+ end
53
+
54
+ def rewind
55
+ @ios.each { |io| io.rewind }
56
+ @index = 0
57
+ end
58
+
59
+ private
60
+
61
+ def current_io
62
+ @ios[@index]
63
+ end
64
+
65
+ def advance_io
66
+ @index += 1
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ CompositeIO = Multipart::Post::CompositeReadIO
73
+ Object.deprecate_constant :CompositeIO
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2008, by McClain Looney.
5
+ # Copyright, 2008-2013, by Nick Sieger.
6
+ # Copyright, 2011, by Gerrit Riessen.
7
+ # Copyright, 2013, by Vincent Pellé.
8
+ # Copyright, 2013, by Gustav Ernberg.
9
+ # Copyright, 2013, by Socrates Vicente.
10
+ # Copyright, 2013, by Steffen Grunwald.
11
+ # Copyright, 2019, by Olle Jonsson.
12
+ # Copyright, 2019-2022, by Samuel Williams.
13
+ # Copyright, 2019, by Patrick Davey.
14
+ # Copyright, 2022, by Jason York.
15
+
16
+ require_relative 'parts'
17
+ require_relative 'composite_read_io'
18
+
19
+ require 'securerandom'
20
+
21
+ module Multipart
22
+ module Post
23
+ module Multipartable
24
+ def self.secure_boundary
25
+ # https://tools.ietf.org/html/rfc7230
26
+ # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
27
+ # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
28
+ # / DIGIT / ALPHA
29
+
30
+ # https://tools.ietf.org/html/rfc2046
31
+ # bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
32
+ # "+" / "_" / "," / "-" / "." /
33
+ # "/" / ":" / "=" / "?"
34
+
35
+ "--#{SecureRandom.uuid}"
36
+ end
37
+
38
+ def initialize(path, params, headers={}, boundary = Multipartable.secure_boundary)
39
+ headers = headers.clone # don't want to modify the original variable
40
+ parts_headers = symbolize_keys(headers.delete(:parts) || {})
41
+
42
+ super(path, headers)
43
+ parts = symbolize_keys(params).map do |k,v|
44
+ case v
45
+ when Array
46
+ v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) }
47
+ else
48
+ Parts::Part.new(boundary, k, v, parts_headers[k])
49
+ end
50
+ end.flatten
51
+ parts << Parts::EpiloguePart.new(boundary)
52
+ ios = parts.map {|p| p.to_io }
53
+ self.set_content_type(headers["Content-Type"] || "multipart/form-data",
54
+ { "boundary" => boundary })
55
+ self.content_length = parts.inject(0) {|sum,i| sum + i.length }
56
+ self.body_stream = CompositeReadIO.new(*ios)
57
+
58
+ @boundary = boundary
59
+ end
60
+
61
+ attr :boundary
62
+
63
+ private
64
+
65
+ if RUBY_VERSION >= "2.5.0"
66
+ def symbolize_keys(hash)
67
+ hash.transform_keys(&:to_sym)
68
+ end
69
+ else
70
+ def symbolize_keys(hash)
71
+ hash.map{|key,value| [key.to_sym, value]}.to_h
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2008-2009, by McClain Looney.
5
+ # Copyright, 2009-2013, by Nick Sieger.
6
+ # Copyright, 2011, by Johannes Wagener.
7
+ # Copyright, 2011, by Gerrit Riessen.
8
+ # Copyright, 2011, by Jason Moore.
9
+ # Copyright, 2012, by Steven Davidovitz.
10
+ # Copyright, 2012, by hexfet.
11
+ # Copyright, 2013, by Vincent Pellé.
12
+ # Copyright, 2013, by Gustav Ernberg.
13
+ # Copyright, 2013, by Socrates Vicente.
14
+ # Copyright, 2017, by David Moles.
15
+ # Copyright, 2017, by Matt Colyer.
16
+ # Copyright, 2017, by Eric Hutzelman.
17
+ # Copyright, 2019-2021, by Olle Jonsson.
18
+ # Copyright, 2019, by Ethan Turkeltaub.
19
+ # Copyright, 2019, by Patrick Davey.
20
+ # Copyright, 2021-2022, by Samuel Williams.
21
+
22
+ require 'stringio'
23
+
24
+ module Multipart
25
+ module Post
26
+ module Parts
27
+ module Part
28
+ def self.new(boundary, name, value, headers = {})
29
+ headers ||= {} # avoid nil values
30
+ if file?(value)
31
+ FilePart.new(boundary, name, value, headers)
32
+ else
33
+ ParamPart.new(boundary, name, value, headers)
34
+ end
35
+ end
36
+
37
+ def self.file?(value)
38
+ value.respond_to?(:content_type) && value.respond_to?(:original_filename)
39
+ end
40
+
41
+ def length
42
+ @part.length
43
+ end
44
+
45
+ def to_io
46
+ @io
47
+ end
48
+ end
49
+
50
+ # Represents a parametric part to be filled with given value.
51
+ class ParamPart
52
+ include Part
53
+
54
+ # @param boundary [String]
55
+ # @param name [#to_s]
56
+ # @param value [String]
57
+ # @param headers [Hash] Content-Type and Content-ID are used, if present.
58
+ def initialize(boundary, name, value, headers = {})
59
+ @part = build_part(boundary, name, value, headers)
60
+ @io = StringIO.new(@part)
61
+ end
62
+
63
+ def length
64
+ @part.bytesize
65
+ end
66
+
67
+ # @param boundary [String]
68
+ # @param name [#to_s]
69
+ # @param value [String]
70
+ # @param headers [Hash] Content-Type is used, if present.
71
+ def build_part(boundary, name, value, headers = {})
72
+ part = String.new
73
+ part << "--#{boundary}\r\n"
74
+ part << "Content-ID: #{headers["Content-ID"]}\r\n" if headers["Content-ID"]
75
+ part << "Content-Disposition: form-data; name=\"#{name.to_s}\"\r\n"
76
+ part << "Content-Type: #{headers["Content-Type"]}\r\n" if headers["Content-Type"]
77
+ part << "\r\n"
78
+ part << "#{value}\r\n"
79
+ end
80
+ end
81
+
82
+ # Represents a part to be filled from file IO.
83
+ class FilePart
84
+ include Part
85
+
86
+ attr_reader :length
87
+
88
+ # @param boundary [String]
89
+ # @param name [#to_s]
90
+ # @param io [IO]
91
+ # @param headers [Hash]
92
+ def initialize(boundary, name, io, headers = {})
93
+ file_length = io.respond_to?(:length) ? io.length : File.size(io.local_path)
94
+ @head = build_head(boundary, name, io.original_filename, io.content_type, file_length,
95
+ io.respond_to?(:opts) ? io.opts.merge(headers) : headers)
96
+ @foot = "\r\n"
97
+ @length = @head.bytesize + file_length + @foot.length
98
+ @io = CompositeReadIO.new(StringIO.new(@head), io, StringIO.new(@foot))
99
+ end
100
+
101
+ # @param boundary [String]
102
+ # @param name [#to_s]
103
+ # @param filename [String]
104
+ # @param type [String]
105
+ # @param content_len [Integer]
106
+ # @param opts [Hash]
107
+ def build_head(boundary, name, filename, type, content_len, opts = {})
108
+ opts = opts.clone
109
+
110
+ trans_encoding = opts.delete("Content-Transfer-Encoding") || "binary"
111
+ content_disposition = opts.delete("Content-Disposition") || "form-data"
112
+
113
+ part = String.new
114
+ part << "--#{boundary}\r\n"
115
+ part << "Content-Disposition: #{content_disposition}; name=\"#{name.to_s}\"; filename=\"#{filename}\"\r\n"
116
+ part << "Content-Length: #{content_len}\r\n"
117
+ if content_id = opts.delete("Content-ID")
118
+ part << "Content-ID: #{content_id}\r\n"
119
+ end
120
+
121
+ if opts["Content-Type"] != nil
122
+ part << "Content-Type: " + opts["Content-Type"] + "\r\n"
123
+ else
124
+ part << "Content-Type: #{type}\r\n"
125
+ end
126
+
127
+ part << "Content-Transfer-Encoding: #{trans_encoding}\r\n"
128
+
129
+ opts.each do |k, v|
130
+ part << "#{k}: #{v}\r\n"
131
+ end
132
+
133
+ part << "\r\n"
134
+ end
135
+ end
136
+
137
+ # Represents the epilogue or closing boundary.
138
+ class EpiloguePart
139
+ include Part
140
+
141
+ def initialize(boundary)
142
+ @part = String.new("--#{boundary}--\r\n")
143
+ @io = StringIO.new(@part)
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2022, by Samuel Williams.
5
+
6
+ module Multipart
7
+ module Post
8
+ # Convenience methods for dealing with files and IO that are to be uploaded.
9
+ class UploadIO
10
+ attr_reader :content_type, :original_filename, :local_path, :io, :opts
11
+
12
+ # Create an upload IO suitable for including in the params hash of a
13
+ # Net::HTTP::Post::Multipart.
14
+ #
15
+ # Can take two forms. The first accepts a filename and content type, and
16
+ # opens the file for reading (to be closed by finalizer).
17
+ #
18
+ # The second accepts an already-open IO, but also requires a third argument,
19
+ # the filename from which it was opened (particularly useful/recommended if
20
+ # uploading directly from a form in a framework, which often save the file to
21
+ # an arbitrarily named RackMultipart file in /tmp).
22
+ #
23
+ # @example
24
+ # UploadIO.new("file.txt", "text/plain")
25
+ # UploadIO.new(file_io, "text/plain", "file.txt")
26
+ def initialize(filename_or_io, content_type, filename = nil, opts = {})
27
+ io = filename_or_io
28
+ local_path = ""
29
+ if io.respond_to? :read
30
+ # in Ruby 1.9.2, StringIOs no longer respond to path
31
+ # (since they respond to :length, so we don't need their local path, see parts.rb:41)
32
+ local_path = filename_or_io.respond_to?(:path) ? filename_or_io.path : "local.path"
33
+ else
34
+ io = File.open(filename_or_io)
35
+ local_path = filename_or_io
36
+ end
37
+ filename ||= local_path
38
+
39
+ @content_type = content_type
40
+ @original_filename = File.basename(filename)
41
+ @local_path = local_path
42
+ @io = io
43
+ @opts = opts
44
+ end
45
+
46
+ def self.convert!(io, content_type, original_filename, local_path)
47
+ raise ArgumentError, "convert! has been removed. You must now wrap IOs " \
48
+ "using:\nUploadIO.new(filename_or_io, content_type, " \
49
+ "filename=nil)\nPlease update your code."
50
+ end
51
+
52
+ def method_missing(*args)
53
+ @io.send(*args)
54
+ end
55
+
56
+ def respond_to?(meth, include_all = false)
57
+ @io.respond_to?(meth, include_all) || super(meth, include_all)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ UploadIO = Multipart::Post::UploadIO
64
+ Object.deprecate_constant :UploadIO
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2019, by Patrick Davey.
5
+ # Copyright, 2021-2023, by Samuel Williams.
6
+
7
+ module Multipart
8
+ module Post
9
+ VERSION = "2.3.0"
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2019, by Patrick Davey.
5
+ # Copyright, 2021-2022, by Samuel Williams.
6
+
7
+ require_relative 'post/multipartable'
8
+ require_relative 'post/upload_io'
@@ -1,9 +1,11 @@
1
- #--
2
- # Copyright (c) 2007-2013 Nick Sieger.
3
- # See the file README.txt included with the distribution for
4
- # software license details.
5
- #++
1
+ # frozen_string_literal: true
6
2
 
7
- module MultipartPost
8
- VERSION = "2.1.0"
9
- end
3
+ # Released under the MIT License.
4
+ # Copyright, 2009-2013, by Nick Sieger.
5
+ # Copyright, 2019-2022, by Samuel Williams.
6
+
7
+ warn "Top level ::MultipartPost is deprecated, require 'multipart/post' and use `Multipart::Post` instead!"
8
+ require_relative 'multipart/post'
9
+
10
+ MultipartPost = Multipart::Post
11
+ Object.deprecate_constant :MultipartPost
data/lib/multipartable.rb CHANGED
@@ -1,48 +1,19 @@
1
- #--
2
- # Copyright (c) 2007-2013 Nick Sieger.
3
- # See the file README.txt included with the distribution for
4
- # software license details.
5
- #++
1
+ # frozen_string_literal: true
6
2
 
7
- require 'parts'
8
- require 'securerandom'
3
+ # Released under the MIT License.
4
+ # Copyright, 2008, by McClain Looney.
5
+ # Copyright, 2008-2013, by Nick Sieger.
6
+ # Copyright, 2011, by Gerrit Riessen.
7
+ # Copyright, 2013, by Vincent Pellé.
8
+ # Copyright, 2013, by Gustav Ernberg.
9
+ # Copyright, 2013, by Socrates Vicente.
10
+ # Copyright, 2013, by Steffen Grunwald.
11
+ # Copyright, 2019, by Olle Jonsson.
12
+ # Copyright, 2019-2022, by Samuel Williams.
13
+ # Copyright, 2019, by Patrick Davey.
9
14
 
10
- module Multipartable
11
- def self.secure_boundary
12
- # https://tools.ietf.org/html/rfc7230
13
- # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
14
- # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
15
- # / DIGIT / ALPHA
16
-
17
- # https://tools.ietf.org/html/rfc2046
18
- # bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
19
- # "+" / "_" / "," / "-" / "." /
20
- # "/" / ":" / "=" / "?"
21
-
22
- "--#{SecureRandom.alphanumeric(60)}"
23
- end
24
-
25
- def initialize(path, params, headers={}, boundary = Multipartable.secure_boundary)
26
- headers = headers.clone # don't want to modify the original variable
27
- parts_headers = headers.delete(:parts) || {}
28
- super(path, headers)
29
- parts = params.map do |k,v|
30
- case v
31
- when Array
32
- v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) }
33
- else
34
- Parts::Part.new(boundary, k, v, parts_headers[k])
35
- end
36
- end.flatten
37
- parts << Parts::EpiloguePart.new(boundary)
38
- ios = parts.map {|p| p.to_io }
39
- self.set_content_type(headers["Content-Type"] || "multipart/form-data",
40
- { "boundary" => boundary })
41
- self.content_length = parts.inject(0) {|sum,i| sum + i.length }
42
- self.body_stream = CompositeReadIO.new(*ios)
43
-
44
- @boundary = boundary
45
- end
46
-
47
- attr :boundary
48
- end
15
+ warn "Top level ::Multipartable is deprecated, require 'multipart/post' and use `Multipart::Post::Multipartable` instead!"
16
+ require_relative 'multipart/post'
17
+
18
+ Multipartable = Multipart::Post::Multipartable
19
+ Object.deprecate_constant :Multipartable
@@ -1,27 +1,27 @@
1
- #--
2
- # Copyright (c) 2007-2012 Nick Sieger.
3
- # See the file README.txt included with the distribution for
4
- # software license details.
5
- #++
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2006-2012, by Nick Sieger.
5
+ # Copyright, 2008, by McClain Looney.
6
+ # Copyright, 2019, by Olle Jonsson.
7
+ # Copyright, 2019, by Patrick Davey.
8
+ # Copyright, 2021-2022, by Samuel Williams.
6
9
 
7
10
  require 'net/http'
8
- require 'stringio'
9
- require 'cgi'
10
- require 'composite_io'
11
- require 'multipartable'
12
- require 'parts'
11
+
12
+ require_relative '../../../multipart/post'
13
13
 
14
14
  module Net
15
15
  class HTTP
16
16
  class Put
17
17
  class Multipart < Put
18
- include Multipartable
18
+ include ::Multipart::Post::Multipartable
19
19
  end
20
20
  end
21
21
 
22
22
  class Post
23
23
  class Multipart < Post
24
- include Multipartable
24
+ include ::Multipart::Post::Multipartable
25
25
  end
26
26
  end
27
27
  end