# File lib/protocols/httpclient.rb, line 151
151:   def receive_data data
152:     while data and data.length > 0
153:       case @read_state
154:       when :base
155:         # Perform any per-request initialization here and don't consume any data.
156:         @data = ""
157:         @headers = []
158:         @content_length = nil # not zero
159:         @content = ""
160:         @status = nil
161:         @read_state = :header
162:       when :header
163:         ary = data.split( /\r?\n/m, 2 )
164:         if ary.length == 2
165:           data = ary.last
166:           if ary.first == ""
167:               if @content_length and @content_length > 0
168:                   @read_state = :content
169:               else
170:                   dispatch_response
171:                   @read_state = :base
172:               end
173:           else
174:             @headers << ary.first
175:             if @headers.length == 1
176:               parse_response_line
177:             elsif ary.first =~ /\Acontent-length:\s*/i
178:               # Only take the FIRST content-length header that appears,
179:               # which we can distinguish because @content_length is nil.
180:               # TODO, it's actually a fatal error if there is more than one
181:               # content-length header, because the caller is presumptively
182:               # a bad guy. (There is an exploit that depends on multiple
183:               # content-length headers.)
184:               @content_length ||= $'.to_i
185:             end
186:           end
187:         else
188:           @data << data
189:           data = ""
190:         end
191:       when :content
192:         # If there was no content-length header, we have to wait until the connection
193:         # closes. Everything we get until that point is content.
194:         # TODO: Must impose a content-size limit, and also must implement chunking.
195:         # Also, must support either temporary files for large content, or calling
196:         # a content-consumer block supplied by the user.
197:         if @content_length
198:           bytes_needed = @content_length - @content.length
199:           @content += data[0, bytes_needed]
200:           data = data[bytes_needed..-1] || ""
201:           if @content_length == @content.length
202:             dispatch_response
203:             @read_state = :base
204:           end
205:         else
206:           @content << data
207:           data = ""
208:         end
209:       end
210:     end
211:   end