File: fixed.rb

package info (click to toggle)
ruby-protocol-http1 0.35.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 376 kB
  • sloc: ruby: 2,367; makefile: 4
file content (90 lines) | stat: -rw-r--r-- 2,452 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
82
83
84
85
86
87
88
89
90
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2019-2025, by Samuel Williams.

require "protocol/http/body/readable"

module Protocol
	module HTTP1
		module Body
			# Represents a fixed length body.
			class Fixed < HTTP::Body::Readable
				# Initialize the body with the given connection and length.
				#
				# @parameter connection [Protocol::HTTP1::Connection] the connection to read the body from.
				# @parameter length [Integer] the length of the body.
				def initialize(connection, length)
					@connection = connection
					
					@length = length
					@remaining = length
				end
				
				# @attribute [Integer] the length of the body.
				attr :length
				
				# @attribute [Integer] the remaining bytes to read.
				attr :remaining
				
				# @returns [Boolean] true if the body is empty.
				def empty?
					@connection.nil? or @remaining == 0
				end
				
				# Close the connection.
				#
				# @parameter error [Exception | Nil] the error that caused the connection to be closed, if any.
				def close(error = nil)
					if connection = @connection
						@connection = nil
						
						unless @remaining == 0
							connection.close_read
						end
					end
					
					super
				end
				
				# Read a chunk of data.
				#
				# @returns [String | Nil] the next chunk of data.
				# @raises [EOFError] if the connection is closed before the expected length is read.
				def read
					if @remaining > 0
						if @connection
							# `readpartial` will raise `EOFError` if the connection is finished, or `IOError` if the connection is closed.
							chunk = @connection.readpartial(@remaining)
							
							@remaining -= chunk.bytesize
							
							if @remaining == 0
								@connection.receive_end_stream!
								@connection = nil
							end
							
							return chunk
						end
						
						# If the connection has been closed before we have read the expected length, raise an error:
						raise EOFError, "connection closed before expected length was read!"
					end
				end
				
				# @returns [String] a human-readable representation of the body.
				def inspect
					"#<#{self.class} #{@length} bytes, #{@remaining} remaining, #{empty? ? 'finished' : 'reading'}>"
				end
				
				# @returns [Hash] JSON representation for tracing and debugging.
				def as_json(...)
					super.merge(
						remaining: @remaining,
						state: @connection ? "open" : "closed"
					)
				end
			end
		end
	end
end