~ubuntu-branches/ubuntu/utopic/ruby-excon/utopic

« back to all changes in this revision

Viewing changes to lib/excon/response.rb

  • Committer: Package Import Robot
  • Author(s): Praveen Arimbrathodiyil
  • Date: 2014-01-14 18:44:24 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20140114184424-3nx5mqudhzjpcrjs
Tags: 0.31.0-1
* Team upload
* New upstream release
* Refresh patches
* Bump standards version to 3.9.5 (no changes)

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
    end
31
31
 
32
32
    def self.parse(socket, datum)
 
33
      # this will discard any trailing lines from the previous response if any.
 
34
      until match = /^HTTP\/\d+\.\d+\s(\d{3})\s/.match(socket.readline); end
 
35
      status = match[1].to_i
 
36
 
33
37
      datum[:response] = {
34
38
        :body       => '',
35
39
        :headers    => {},
36
 
        :status     => socket.read(12)[9, 11].to_i,
 
40
        :status     => status,
37
41
        :remote_ip  => socket.respond_to?(:remote_ip) && socket.remote_ip
38
42
      }
39
 
      socket.readline # read the rest of the status line and CRLF
40
43
 
41
 
      until ((data = socket.readline).chop!).empty?
42
 
        key, value = data.split(/:\s*/, 2)
43
 
        datum[:response][:headers][key] = ([*datum[:response][:headers][key]] << value).compact.join(', ')
44
 
        if key.casecmp('Content-Length') == 0
45
 
          content_length = value.to_i
46
 
        elsif (key.casecmp('Transfer-Encoding') == 0) && (value.casecmp('chunked') == 0)
47
 
          transfer_encoding_chunked = true
48
 
        end
49
 
      end
 
44
      parse_headers(socket, datum)
50
45
 
51
46
      unless (['HEAD', 'CONNECT'].include?(datum[:method].to_s.upcase)) || NO_ENTITY.include?(datum[:response][:status])
52
47
 
53
 
        # check to see if expects was set and matched
54
 
        expected_status = !datum.has_key?(:expects) || [*datum[:expects]].include?(datum[:response][:status])
55
 
 
56
 
        # if expects matched and there is a block, use it
57
 
        if expected_status && datum.has_key?(:response_block)
58
 
          if transfer_encoding_chunked
59
 
            # 2 == "/r/n".length
60
 
            while (chunk_size = socket.readline.chop!.to_i(16)) > 0
61
 
              datum[:response_block].call(socket.read(chunk_size + 2).chop!, nil, nil)
62
 
            end
63
 
            socket.read(2)
64
 
          elsif remaining = content_length
 
48
        if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Transfer-Encoding') == 0 }
 
49
          encodings = Utils.split_header_value(datum[:response][:headers][key])
 
50
          if (encoding = encodings.last) && encoding.casecmp('chunked') == 0
 
51
            transfer_encoding_chunked = true
 
52
            encodings.pop
 
53
            datum[:response][:headers][key] = encodings.join(', ')
 
54
          end
 
55
        end
 
56
        unless transfer_encoding_chunked
 
57
          if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Content-Length') == 0 }
 
58
            content_length = datum[:response][:headers][key].to_i
 
59
          end
 
60
        end
 
61
 
 
62
        # use :response_block unless :expects would fail
 
63
        if response_block = datum[:response_block]
 
64
          if datum[:middlewares].include?(Excon::Middleware::Expects) && datum[:expects] &&
 
65
                                !Array(datum[:expects]).include?(datum[:response][:status])
 
66
            response_block = nil
 
67
          end
 
68
        end
 
69
 
 
70
        if transfer_encoding_chunked
 
71
          # 2 == "\r\n".length
 
72
          if response_block
 
73
            while (chunk_size = socket.readline.chop!.to_i(16)) > 0
 
74
              response_block.call(socket.read(chunk_size + 2).chop!, nil, nil)
 
75
            end
 
76
          else
 
77
            while (chunk_size = socket.readline.chop!.to_i(16)) > 0
 
78
              datum[:response][:body] << socket.read(chunk_size + 2).chop!
 
79
            end
 
80
          end
 
81
          parse_headers(socket, datum) # merge trailers into headers
 
82
        elsif remaining = content_length
 
83
          if response_block
65
84
            while remaining > 0
66
 
              datum[:response_block].call(socket.read([datum[:chunk_size], remaining].min), [remaining - datum[:chunk_size], 0].max, content_length)
 
85
              response_block.call(socket.read([datum[:chunk_size], remaining].min), [remaining - datum[:chunk_size], 0].max, content_length)
67
86
              remaining -= datum[:chunk_size]
68
87
            end
69
88
          else
70
 
            while remaining = socket.read(datum[:chunk_size])
71
 
              datum[:response_block].call(remaining, remaining.length, content_length)
72
 
            end
73
 
          end
74
 
        else # no block or unexpected status
75
 
          if transfer_encoding_chunked
76
 
            while (chunk_size = socket.readline.chop!.to_i(16)) > 0
77
 
              datum[:response][:body] << socket.read(chunk_size + 2).chop! # 2 == "/r/n".length
78
 
            end
79
 
            socket.read(2) # 2 == "/r/n".length
80
 
          elsif remaining = content_length
81
89
            while remaining > 0
82
90
              datum[:response][:body] << socket.read([datum[:chunk_size], remaining].min)
83
91
              remaining -= datum[:chunk_size]
84
92
            end
 
93
          end
 
94
        else
 
95
          if response_block
 
96
            while chunk = socket.read(datum[:chunk_size])
 
97
              response_block.call(chunk, nil, nil)
 
98
            end
85
99
          else
86
100
            datum[:response][:body] << socket.read
87
101
          end
90
104
      datum
91
105
    end
92
106
 
 
107
    def self.parse_headers(socket, datum)
 
108
      last_key = nil
 
109
      until (data = socket.readline.chop!).empty?
 
110
        if !data.lstrip!.nil?
 
111
          raise Excon::Errors::ResponseParseError, 'malformed header' unless last_key
 
112
          # append to last_key's last value
 
113
          datum[:response][:headers][last_key] << ' ' << data.rstrip
 
114
        else
 
115
          key, value = data.split(':', 2)
 
116
          raise Excon::Errors::ResponseParseError, 'malformed header' unless value
 
117
          # add key/value or append value to existing values
 
118
          datum[:response][:headers][key] = ([datum[:response][:headers][key]] << value.strip).compact.join(', ')
 
119
          last_key = key
 
120
        end
 
121
      end
 
122
    end
 
123
 
93
124
    def initialize(params={})
94
125
      @data = {
95
126
        :body     => '',
106
137
    end
107
138
 
108
139
    def params
109
 
      Excon.display_warning("Excon::Response#params is deprecated use Excon::Response#data instead (#{caller.first})")
 
140
      Excon.display_warning('Excon::Response#params is deprecated use Excon::Response#data instead.')
110
141
      data
111
142
    end
112
143