1 # Copyright (c) 2009 Eric Wong
2 # You can redistribute it and/or modify it under the same terms as Ruby.
10 Z.force_encoding(Encoding::BINARY) if Z.respond_to?(:force_encoding)
17 def reopen(input, buf)
19 buf.force_encoding(Encoding::BINARY) if buf.respond_to?(:force_encoding)
20 @input, @buf = input, buf
25 def readpartial(max, buf = Z.dup)
26 buf.force_encoding(Encoding::BINARY) if buf.respond_to?(:force_encoding)
28 while @input && @chunk_left <= 0 && ! parse_chunk_header
29 @buf << @input.readpartial(Const::CHUNK_SIZE, buf)
34 @buf << @input.read_nonblock(Const::CHUNK_SIZE, buf)
35 rescue Errno::EAGAIN, Errno::EINTR
39 max = @chunk_left if max > @chunk_left
40 buf.replace(last_block(max) || Z)
41 @chunk_left -= buf.size
42 (0 == buf.size && @input.nil?) and raise EOFError
49 line = readpartial(Const::CHUNK_SIZE)
51 if line.sub!(%r{\A(.*?#{$/})}, Z)
52 @chunk_left += line.size
53 @buf = @buf ? (line << @buf) : line
56 line << readpartial(Const::CHUNK_SIZE)
65 def last_block(max = nil)
67 if max && rv && max < rv.size
68 @buf = rv[max - rv.size, rv.size - max]
75 def parse_chunk_header
77 # ignoring chunk-extension info for now, I haven't seen any use for it
78 # (or any users, and TE:chunked sent by clients is rare already)
79 # if there was not enough data in buffer to parse length of the chunk
81 if buf.sub!(/\A(?:\r\n)?([a-fA-F0-9]{1,8})[^\r]*?\r\n/, Z)
82 @chunk_left = $1.to_i(16)
83 if 0 == @chunk_left # EOF
84 buf.sub!(/\A\r\n(?:\r\n)?/, Z) # cleanup for future requests
91 raise HttpParserError,
92 "malformed chunk, chunk-length not found in buffer: " \