Class: Yahns::StreamInput
- Inherits:
-
Object
- Object
- Yahns::StreamInput
- Defined in:
- lib/yahns/stream_input.rb
Overview
When processing uploads, Yahns may expose a StreamInput object under “rack.input” of the (future) Rack (2.x) environment.
Direct Known Subclasses
Instance Method Summary collapse
- #__rsize ⇒ Object
- #__tlsbuf ⇒ Object
-
#close ⇒ Object
return nil.
-
#each ⇒ Object
:call-seq: ios.each { |line| block } => ios.
- #eof! ⇒ Object
- #eof? ⇒ Boolean
- #filter_body(dst, src) ⇒ Object
-
#gets ⇒ Object
:call-seq: ios.gets => string or nil.
-
#initialize(client, request) ⇒ StreamInput
constructor
Initializes a new StreamInput object.
-
#read(length = nil, rv = ''.dup) ⇒ Object
:call-seq: ios.read([length [, buffer ]]) => string, buffer, or nil.
- #read_all(dst) ⇒ Object
Constructor Details
#initialize(client, request) ⇒ StreamInput
Initializes a new StreamInput object. You normally do not have to call this unless you are writing an HTTP server.
11 12 13 14 15 16 17 18 19 |
# File 'lib/yahns/stream_input.rb', line 11 def initialize(client, request) @chunked = request.content_length.nil? @client = client @parser = request @buf = request.buf @rbuf = ''.dup @bytes_read = 0 filter_body(@rbuf, @buf) unless @buf.empty? end |
Instance Method Details
#__rsize ⇒ Object
64 65 66 |
# File 'lib/yahns/stream_input.rb', line 64 def __rsize @client ? @client.class.client_body_buffer_size : nil end |
#__tlsbuf ⇒ Object
68 69 70 |
# File 'lib/yahns/stream_input.rb', line 68 def __tlsbuf Thread.current[:yahns_rbuf] end |
#close ⇒ Object
return nil
155 156 |
# File 'lib/yahns/stream_input.rb', line 155 def close # return nil end |
#each ⇒ Object
:call-seq:
ios.each { |line| block } => ios
Executes the block for every “line” in ios, where lines are separated by the global record separator ($/, typically “n”).
104 105 106 107 108 109 110 |
# File 'lib/yahns/stream_input.rb', line 104 def each while line = gets yield line end self # Rack does not specify what the return value is here end |
#eof! ⇒ Object
145 146 147 148 149 150 151 152 153 |
# File 'lib/yahns/stream_input.rb', line 145 def eof! # in case client only did a premature shutdown(SHUT_WR) # we do support clients that shutdown(SHUT_WR) after the # _entire_ request has been sent, and those will not have # raised EOFError on us. @client.shutdown if @client ensure raise Yahns::ClientShutdown, "bytes_read=#{@bytes_read}", [] end |
#eof? ⇒ Boolean
112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/yahns/stream_input.rb', line 112 def eof? if @parser.body_eof? rsize = __rsize tlsbuf = __tlsbuf while @chunked && ! @parser.parse @client.yahns_read(rsize, tlsbuf) or eof! @buf << tlsbuf end @client = nil true else false end end |
#filter_body(dst, src) ⇒ Object
127 128 129 130 131 |
# File 'lib/yahns/stream_input.rb', line 127 def filter_body(dst, src) rv = @parser.filter_body(dst, src) @bytes_read += dst.size rv end |
#gets ⇒ Object
:call-seq:
ios.gets => string or nil
Reads the next “line” from the I/O stream; lines are separated by the global record separator ($/, typically “n”). A global record separator of nil reads the entire unread contents of ios. Returns nil if called at the end of file. This takes zero arguments for strict Rack::Lint compatibility, unlike IO#gets.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/yahns/stream_input.rb', line 81 def gets sep = $/ if sep.nil? read_all(rv = ''.dup) return rv.empty? ? nil : rv end re = /\A(.*?#{Regexp.escape(sep)})/ rsize = __rsize or return tlsbuf = __tlsbuf begin @rbuf.sub!(re, '') and return $1 return @rbuf.empty? ? nil : @rbuf.slice!(0, @rbuf.size) if eof? @client.yahns_read(rsize, @buf) or eof! filter_body(tlsbuf, @buf) @rbuf << tlsbuf end while true end |
#read(length = nil, rv = ''.dup) ⇒ Object
:call-seq:
ios.read([length [, buffer ]]) => string, buffer, or nil
Reads at most length bytes from the I/O stream, or to the end of file if length is omitted or is nil. length must be a non-negative integer or nil. If the optional buffer argument is present, it must reference a String, which will receive the data.
At end of file, it returns nil or ” depend on length. ios.read() and ios.read(nil) returns ”. ios.read(length [, buffer]) returns nil.
If the Content-Length of the HTTP request is known (as is the common case for POST requests), then ios.read(length [, buffer]) will block until the specified length is read (or it is the last chunk). Otherwise, for uncommon “Transfer-Encoding: chunked” requests, ios.read(length [, buffer]) will return immediately if there is any data and only block when nothing is available (providing IO#readpartial semantics).
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/yahns/stream_input.rb', line 40 def read(length = nil, rv = ''.dup) if length if length <= @rbuf.size length < 0 and raise ArgumentError, "negative length #{length} given" rv.replace(@rbuf.slice!(0, length)) else cur = @rbuf.size to_read = length - cur cur == 0 ? rv.clear : rv.replace(@rbuf.slice!(0, cur)) until to_read == 0 || eof? || (rv.size > 0 && @chunked) @client.yahns_read(to_read, @buf) or eof! filter_body(@rbuf, @buf) rv << @rbuf to_read -= @rbuf.size end @rbuf.clear end rv = nil if rv.empty? && length != 0 else read_all(rv) end rv end |
#read_all(dst) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/yahns/stream_input.rb', line 133 def read_all(dst) dst.replace(@rbuf) rsize = __rsize or return until eof? @client.yahns_read(rsize, @buf) or eof! filter_body(@rbuf, @buf) dst << @rbuf end ensure @rbuf.clear end |