1 # Copyright (c) 2009 Eric Wong
2 # You can redistribute it and/or modify it under the same terms as Ruby.
10 def initialize(env, input, buf)
11 @env, @input, @buf = env, input, buf
16 def readpartial(max, buf = Z.dup)
17 while @input && @chunk_left <= 0 && ! parse_chunk_header
18 @buf << @input.readpartial(Const::CHUNK_SIZE, buf)
23 @buf << @input.read_nonblock(Const::CHUNK_SIZE, buf)
24 rescue Errno::EAGAIN, Errno::EINTR
28 max = @chunk_left if max > @chunk_left
29 buf.replace(last_block(max) || Z)
30 @chunk_left -= buf.size
31 (0 == buf.size && @input.nil?) and raise EOFError
37 def last_block(max = nil)
39 if max && rv && max < rv.size
40 @buf = rv[max - rv.size, rv.size - max]
47 def parse_chunk_header
49 # ignoring chunk-extension info for now, I haven't seen any use for it
50 # (or any users, and TE:chunked sent by clients is rare already)
51 # if there was not enough data in buffer to parse length of the chunk
53 if buf.sub!(/\A(?:\r\n)?([a-fA-F0-9]{1,8})[^\r]*?\r\n/, Z)
54 @chunk_left = $1.to_i(16)
55 if 0 == @chunk_left # EOF
56 buf.sub!(/\A\r\n(?:\r\n)?/, Z) # cleanup for future requests
57 if trailer = @env[Const::HTTP_TRAILER]
58 tp = TrailerParser.new(trailer)
59 while ! tp.execute!(@env, buf)
60 buf << @input.readpartial(Const::CHUNK_SIZE)
69 raise HttpParserError,
70 "malformed chunk, chunk-length not found in buffer: " \