11# frozen_string_literal: true
22
3+ require "http-parser"
4+
35module HTTP
46 class Response
7+ # @api private
8+ #
9+ # NOTE(ixti): This class is a subject of future refactoring, thus don't
10+ # expect this class API to be stable until this message disappears and
11+ # class is not marked as private anymore.
512 class Parser
613 attr_reader :headers
714
815 def initialize
9- @parser = HTTP ::Parser . new ( self )
16+ @state = HttpParser ::Parser . new_instance { |i | i . type = :response }
17+ @parser = HttpParser ::Parser . new ( self )
18+
1019 reset
1120 end
1221
22+ # @return [self]
1323 def add ( data )
14- @parser << data
24+ # XXX(ixti): API doc of HttpParser::Parser is misleading, it says that
25+ # it returns boolean true if data was parsed successfully, but instead
26+ # it's response tells if there was an error; So when it's `true` that
27+ # means parse failed, and `false` means parse was successful.
28+ # case of success.
29+ return self unless @parser . parse ( @state , data )
30+
31+ raise IOError , "Could not parse data"
1532 end
1633 alias << add
1734
1835 def headers?
19- !! @ headers
36+ @finished [ : headers]
2037 end
2138
2239 def http_version
23- @parser . http_version . join ( "." )
40+ @state . http_version
2441 end
2542
2643 def status_code
27- @parser . status_code
44+ @state . http_status
2845 end
2946
3047 #
3148 # HTTP::Parser callbacks
3249 #
3350
34- def on_headers_complete ( headers )
35- @headers = headers
51+ def on_header_field ( _response , field )
52+ @field = field
53+ end
54+
55+ def on_header_value ( _response , value )
56+ @headers . add ( @field , value ) if @field
57+ end
58+
59+ def on_headers_complete ( _reposse )
60+ @finished [ :headers ] = true
3661 end
3762
38- def on_body ( chunk )
63+ def on_body ( _response , chunk )
3964 if @chunk
4065 @chunk << chunk
4166 else
@@ -57,20 +82,21 @@ def read(size)
5782 chunk
5883 end
5984
60- def on_message_complete
61- @finished = true
85+ def on_message_complete ( _response )
86+ @finished [ :message ] = true
6287 end
6388
6489 def reset
65- @parser . reset!
90+ @state . reset!
6691
67- @finished = false
68- @headers = nil
92+ @finished = Hash . new ( false )
93+ @headers = HTTP ::Headers . new
94+ @field = nil
6995 @chunk = nil
7096 end
7197
7298 def finished?
73- @finished
99+ @finished [ :message ]
74100 end
75101 end
76102 end
0 commit comments