Class: Protocol::Multipart::Parser::Part

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/multipart/parser.rb

Overview

Represents a single part within a multipart message.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(readable, headers, boundary) ⇒ Part

Initialize a new part with a readable stream, headers, and a boundary string.



36
37
38
39
40
41
42
# File 'lib/protocol/multipart/parser.rb', line 36

def initialize(readable, headers, boundary)
	@readable = readable
	@boundary = boundary
	@headers = headers
	@ended = false
	@is_closing = false
end

Instance Attribute Details

#headersObject (readonly)

Returns the value of attribute headers.



45
46
47
# File 'lib/protocol/multipart/parser.rb', line 45

def headers
  @headers
end

#The headers associated with this part.(headersassociatedwiththispart.) ⇒ Object (readonly)



45
# File 'lib/protocol/multipart/parser.rb', line 45

attr_reader :headers

Instance Method Details

#closing_boundary?Boolean

Checks if this part ends with a closing boundary. A closing boundary indicates that this is the last part in the multipart message.

Returns:

  • (Boolean)


157
158
159
# File 'lib/protocol/multipart/parser.rb', line 157

def closing_boundary?
	@is_closing || (@readable.nil? && @is_closing)
end

#discardObject

Efficiently discards all data until the next boundary is found. This is used to skip parts without reading their content into memory.



134
135
136
137
138
139
140
141
142
143
144
# File 'lib/protocol/multipart/parser.rb', line 134

def discard
	# Efficiently discard all data until boundary
	return unless @readable
	
	# Discard data until boundary
	@readable.discard_until("\r\n--#{@boundary}")
	
	self.read_boundary_suffix
	
	return nil
end

#each(chunk_size = 8192) ⇒ Object

Iterate through the part content in chunks.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/protocol/multipart/parser.rb', line 51

def each(chunk_size = 8192)
	return to_enum(:each, chunk_size) unless block_given?
	
	return unless @readable
	
	boundary_marker = "\r\n--#{@boundary}"
	
	# Stream data in chunks using read_until with a limit
	while @readable
		if chunk = @readable.read_until(boundary_marker, limit: chunk_size, chomp: true)
			# We found the boundary, check if it's a closing boundary:
			if suffix = @readable.read_until("\r\n", chomp: true)
				@is_closing = (suffix == "--")
				@ended = true
				@readable = nil
			else
				@readable = nil
				raise EOFError, "Unexpected end of stream while reading part data!"
			end
		else
			chunk = @readable.read(chunk_size)
		end
		
		if chunk
			yield chunk unless chunk.empty?
		else
			# No more data to read, break the loop:
			break
		end
	end
end

#ended?Boolean

Checks if this part has been completely read.

Returns:

  • (Boolean)


149
150
151
# File 'lib/protocol/multipart/parser.rb', line 149

def ended?
	@ended
end

#finishObject

Finishes reading this part's data and advances to the next boundary.



119
120
121
122
123
124
125
126
127
128
# File 'lib/protocol/multipart/parser.rb', line 119

def finish
	return unless @readable
	
	# Read all data until boundary
	data = @readable.read_until("\r\n--#{@boundary}", chomp: true)
	
	self.read_boundary_suffix
	
	return data
end

#read_boundary_suffixObject

Reads the suffix after a boundary to determine if it's a closing boundary.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/protocol/multipart/parser.rb', line 99

def read_boundary_suffix
	# Read the rest of the boundary line to check if it's closing:
	boundary_suffix = @readable.read(2)
	if boundary_suffix == "--"
		@is_closing = true
		@ended = true
		@readable = nil
	elsif boundary_suffix == "\r\n"
		@is_closing = false
		@ended = true
		@readable = nil
	else
		@readable = nil
		raise EOFError, "Unexpected end of stream while reading part data!"
	end
end

#read_empty_boundary?Boolean

Checks if the next content is an empty boundary (part with no content).

Returns:

  • (Boolean)


86
87
88
89
90
91
92
93
94
95
96
# File 'lib/protocol/multipart/parser.rb', line 86

def read_empty_boundary?
	boundary_marker = "--#{@boundary}"
	if @readable.peek(boundary_marker.bytesize) == boundary_marker
		@readable.read(boundary_marker.bytesize)
		self.read_boundary_suffix
		
		return true
	end
	
	return false
end