Class: Excon::Response

Inherits:
Object
  • Object
show all
Defined in:
lib/excon/response.rb

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Response) initialize(params = {})



132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/excon/response.rb', line 132

def initialize(params={})
  @data = {
    :body     => '',
    :headers  => Excon::Headers.new
  }.merge(params)
  @body          = @data[:body]
  @headers       = @data[:headers]
  @status        = @data[:status]
  @remote_ip     = @data[:remote_ip]
  @local_port    = @data[:local_port]
  @local_address = @data[:local_address]
end

Instance Attribute Details

- (Object) data

Returns the value of attribute data



4
5
6
# File 'lib/excon/response.rb', line 4

def data
  @data
end

Class Method Details

+ (Object) parse(socket, datum)



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/excon/response.rb', line 38

def self.parse(socket, datum)
  # this will discard any trailing lines from the previous response if any.
  until match = /^HTTP\/\d+\.\d+\s(\d{3})\s/.match(socket.readline); end
  status = match[1].to_i

  datum[:response] = {
    :body          => '',
    :headers       => Excon::Headers.new,
    :status        => status,
    :remote_ip     => socket.respond_to?(:remote_ip) && socket.remote_ip,
    :local_port    => socket.respond_to?(:local_port) && socket.local_port,
    :local_address => socket.respond_to?(:local_address) && socket.local_address
  }

  parse_headers(socket, datum)

  unless (['HEAD', 'CONNECT'].include?(datum[:method].to_s.upcase)) || NO_ENTITY.include?(datum[:response][:status])

    if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Transfer-Encoding') == 0 }
      encodings = Utils.split_header_value(datum[:response][:headers][key])
      if (encoding = encodings.last) && encoding.casecmp('chunked') == 0
        transfer_encoding_chunked = true
        encodings.pop
        datum[:response][:headers][key] = encodings.join(', ')
      end
    end
    unless transfer_encoding_chunked
      if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Content-Length') == 0 }
        content_length = datum[:response][:headers][key].to_i
      end
    end

    # use :response_block unless :expects would fail
    if response_block = datum[:response_block]
      if datum[:middlewares].include?(Excon::Middleware::Expects) && datum[:expects] &&
                            !Array(datum[:expects]).include?(datum[:response][:status])
        response_block = nil
      end
    end

    if transfer_encoding_chunked
      # 2 == "\r\n".length
      if response_block
        while (chunk_size = socket.readline.chop!.to_i(16)) > 0
          response_block.call(socket.read(chunk_size + 2).chop!, nil, nil)
        end
      else
        while (chunk_size = socket.readline.chop!.to_i(16)) > 0
          datum[:response][:body] << socket.read(chunk_size + 2).chop!
        end
      end
      parse_headers(socket, datum) # merge trailers into headers
    elsif remaining = content_length
      if response_block
        while remaining > 0
          response_block.call(socket.read([datum[:chunk_size], remaining].min), [remaining - datum[:chunk_size], 0].max, content_length)
          remaining -= datum[:chunk_size]
        end
      else
        while remaining > 0
          datum[:response][:body] << socket.read([datum[:chunk_size], remaining].min)
          remaining -= datum[:chunk_size]
        end
      end
    else
      if response_block
        while chunk = socket.read(datum[:chunk_size])
          response_block.call(chunk, nil, nil)
        end
      else
        datum[:response][:body] << socket.read
      end
    end
  end
  datum
end

+ (Object) parse_headers(socket, datum)



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/excon/response.rb', line 115

def self.parse_headers(socket, datum)
  last_key = nil
  until (data = socket.readline.chop!).empty?
    if !data.lstrip!.nil?
      raise Excon::Errors::ResponseParseError, 'malformed header' unless last_key
      # append to last_key's last value
      datum[:response][:headers][last_key] << ' ' << data.rstrip
    else
      key, value = data.split(':', 2)
      raise Excon::Errors::ResponseParseError, 'malformed header' unless value
      # add key/value or append value to existing values
      datum[:response][:headers][key] = ([datum[:response][:headers][key]] << value.strip).compact.join(', ')
      last_key = key
    end
  end
end

Instance Method Details

- (Object) [](key)



145
146
147
# File 'lib/excon/response.rb', line 145

def [](key)
  @data[key]
end

- (Object) body



10
11
12
# File 'lib/excon/response.rb', line 10

def body
  @data[:body]
end

- (Object) body=(new_body)

backwards compatability reader/writers



7
8
9
# File 'lib/excon/response.rb', line 7

def body=(new_body)
  @data[:body] = new_body
end

- (Object) get_header(name)

Retrieve a specific header value. Header names are treated case-insensitively.

@param [String] name Header name


156
157
158
# File 'lib/excon/response.rb', line 156

def get_header(name)
  headers[name]
end

- (Object) headers



16
17
18
# File 'lib/excon/response.rb', line 16

def headers
  @data[:headers]
end

- (Object) headers=(new_headers)



13
14
15
# File 'lib/excon/response.rb', line 13

def headers=(new_headers)
  @data[:headers] = new_headers
end

- (Object) local_address



34
35
36
# File 'lib/excon/response.rb', line 34

def local_address
  @data[:local_address]
end

- (Object) local_port



31
32
33
# File 'lib/excon/response.rb', line 31

def local_port
  @data[:local_port]
end

- (Object) params



149
150
151
152
# File 'lib/excon/response.rb', line 149

def params
  Excon.display_warning('Excon::Response#params is deprecated use Excon::Response#data instead.')
  data
end

- (Object) remote_ip



28
29
30
# File 'lib/excon/response.rb', line 28

def remote_ip
  @data[:remote_ip]
end

- (Object) remote_ip=(new_remote_ip)



25
26
27
# File 'lib/excon/response.rb', line 25

def remote_ip=(new_remote_ip)
  @data[:remote_ip] = new_remote_ip
end

- (Object) status



22
23
24
# File 'lib/excon/response.rb', line 22

def status
  @data[:status]
end

- (Object) status=(new_status)



19
20
21
# File 'lib/excon/response.rb', line 19

def status=(new_status)
  @data[:status] = new_status
end