protocol-multipart 0.6.0 → 0.7.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: fa90f615454830d99794083234b6004921aba4eaa2846c6977fa4e871fbba1f8
4
- data.tar.gz: 1aac98c2b5492345559aa76abd036ae30055e6a614e42a04936e0852649ad519
3
+ metadata.gz: '07498e70d64dd8df616ae6c73a9c00a71901707c81b3c5223cd8bb855fbe0d65'
4
+ data.tar.gz: 7ce3e69f8afac4da7339c3d953640e5e1144612cb7f7f12868eaab1aa360b733
5
5
  SHA512:
6
- metadata.gz: 0234a8d2cd90bdb27d77136d7decdb2f841090590dec28ca4b8e4d43eb729bd7f79dfa386bcf93a83ee401450c6add28743aa95ed2fa8261bcfc50cd9d3b7fbb
7
- data.tar.gz: 5a04aaec79f48cc4c9e3dcf0ead6517b10c1aa74f084d5f5ec3c5d31e1b9b2856400ac305091bda7ec87596eccc6320b0eee0f69322eb17fcb7d9c8ae3e51922
6
+ metadata.gz: 0fbe8ff1c95cc58a7548b14f0da442ca3715fa825fe56a395e792a0fc3b83249571d1b63a5f3d4ba0ecb544446d9f138fe811ae46220652d2f0d961a20684541
7
+ data.tar.gz: e5e7bbf1d0c7dac99f934429d251d190877b1f807f76dfe4eeebdcd2dbc0117df53b185aedbe4b63c9c203811bb0361a124b54aa83a62e64982e64e282cc0600
checksums.yaml.gz.sig CHANGED
Binary file
@@ -8,6 +8,7 @@ require_relative "parser"
8
8
  require_relative "string_part"
9
9
  require_relative "escape"
10
10
  require_relative "byte_limit"
11
+ require_relative "readable"
11
12
 
12
13
  module Protocol
13
14
  module Multipart
@@ -27,6 +28,8 @@ module Protocol
27
28
 
28
29
  # A file upload yielded while parsing form data.
29
30
  class Upload
31
+ include Readable
32
+
30
33
  # Initialize a streamed file upload.
31
34
  # @parameter part [Parser::Part] The underlying multipart part.
32
35
  # @parameter filename [String] The submitted filename.
@@ -6,6 +6,7 @@
6
6
  require "io/stream"
7
7
  require_relative "error"
8
8
  require_relative "headers"
9
+ require_relative "readable"
9
10
 
10
11
  module Protocol
11
12
  module Multipart
@@ -29,6 +30,8 @@ module Protocol
29
30
 
30
31
  # Represents a single part within a multipart message.
31
32
  class Part
33
+ include Readable
34
+
32
35
  # Initialize a new part with a readable stream, headers, and a boundary string.
33
36
  #
34
37
  # @parameter readable [IO::Stream] The readable stream that contains the part's data.
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2026, by Samuel Williams.
5
+
6
+ module Protocol
7
+ module Multipart
8
+ # Common operations for streaming readable multipart content.
9
+ module Readable
10
+ # Copy the content to a writable object.
11
+ # @parameter output [#write] The writable destination.
12
+ # @parameter chunk_size [Integer] The maximum chunk size.
13
+ # @returns [Integer] The number of bytes copied.
14
+ def copy_to(output, chunk_size = 8192)
15
+ size = 0
16
+
17
+ each(chunk_size) do |chunk|
18
+ offset = 0
19
+
20
+ # A writable object may consume only part of a chunk:
21
+ while offset < chunk.bytesize
22
+ written = output.write(chunk.byteslice(offset, chunk.bytesize - offset))
23
+
24
+ unless written && written > 0
25
+ raise IOError, "Could not make progress while copying multipart content!"
26
+ end
27
+
28
+ offset += written
29
+ end
30
+
31
+ size += chunk.bytesize
32
+ end
33
+
34
+ return size
35
+ end
36
+
37
+ # Save the content to a new local file.
38
+ # @parameter path [String, #to_path] The destination path, which must not exist.
39
+ # @parameter permissions [Integer] The permissions for the new file.
40
+ # @parameter chunk_size [Integer] The maximum chunk size.
41
+ # @returns [Integer] The number of bytes saved.
42
+ def save(path, permissions: 0o600, chunk_size: 8192)
43
+ flags = File::WRONLY | File::CREAT | File::EXCL
44
+ created = false
45
+
46
+ begin
47
+ File.open(path, flags, permissions) do |file|
48
+ created = true
49
+ file.binmode
50
+ return copy_to(file, chunk_size)
51
+ end
52
+ rescue
53
+ # Remove a partial destination created by this operation:
54
+ if created
55
+ File.unlink(path)
56
+ end
57
+
58
+ raise
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Protocol
7
7
  module Multipart
8
- VERSION = "0.6.0"
8
+ VERSION = "0.7.0"
9
9
  end
10
10
  end
@@ -7,6 +7,7 @@ require_relative "multipart/version"
7
7
  require_relative "multipart/error"
8
8
  require_relative "multipart/byte_limit"
9
9
  require_relative "multipart/headers"
10
+ require_relative "multipart/readable"
10
11
  require_relative "multipart/parser"
11
12
  require_relative "multipart/mixed"
12
13
  require_relative "multipart/part"
data/readme.md CHANGED
@@ -6,6 +6,10 @@
6
6
 
7
7
  Please see the [project releases](https://socketry.github.io/protocol-multipart/releases/index) for all releases.
8
8
 
9
+ ### v0.7.0
10
+
11
+ - Add `copy_to` and secure local `save` operations for readable multipart parts and form-data uploads.
12
+
9
13
  ### v0.6.0
10
14
 
11
15
  - Rename `Protocol::Multipart::FormData::Parser::CONTENT_TYPE` to `MEDIA_TYPE`.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.7.0
4
+
5
+ - Add `copy_to` and secure local `save` operations for readable multipart parts and form-data uploads.
6
+
3
7
  ## v0.6.0
4
8
 
5
9
  - Rename `Protocol::Multipart::FormData::Parser::CONTENT_TYPE` to `MEDIA_TYPE`.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protocol-multipart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -99,6 +99,7 @@ files:
99
99
  - lib/protocol/multipart/mixed.rb
100
100
  - lib/protocol/multipart/parser.rb
101
101
  - lib/protocol/multipart/part.rb
102
+ - lib/protocol/multipart/readable.rb
102
103
  - lib/protocol/multipart/string_part.rb
103
104
  - lib/protocol/multipart/version.rb
104
105
  - license.md
metadata.gz.sig CHANGED
Binary file