Class: Kronk::Response

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

Overview

Standard Kronk response object.

Defined Under Namespace

Classes: InvalidParser, MissingParser

Constant Summary collapse

ENCODING_MATCHER =
/(^|;\s?)charset=(.*?)\s*(;|$)/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io = nil, res = nil, request = nil) ⇒ Response

Create a new Response object from a String or IO.



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
# File 'lib/kronk/response.rb', line 53

def initialize io=nil, res=nil, request=nil
  return unless io
  io = StringIO.new io if String === io

  if io && res
    @_res, debug_io = res, io
  else
    @_res, debug_io = request_from_io(io)
  end

  @headers  = @_res.to_hash

  @encoding = "utf-8" unless @_res["Content-Type"]
  c_type = [*@headers["content-type"]].find{|ct| ct =~ ENCODING_MATCHER}
  @encoding = $2 if c_type
  @encoding ||= "ASCII-8BIT"
  @encoding = Encoding.find(@encoding) if defined?(Encoding)

  raw_req, raw_resp, bytes = read_raw_from debug_io
  @raw      = try_force_encoding raw_resp

  @request  = request ||
              raw_req = try_force_encoding(raw_req) &&
              Request.parse(raw_req)

  @time   = 0

  @body   = try_force_encoding(@_res.body) if @_res.body
  @body ||= @raw.split("\r\n\r\n",2)[1]

  @bytes = (@_res['Content-Length'] || @body.bytes.count).to_i

  @code = @_res.code

  @parser = Kronk.parser_for @_res['Content-Type']

  @uri = @request.uri if @request && @request.uri
  @uri = URI.parse io.path if File === io

  @byterate = 0
end

Instance Attribute Details

#bodyObject

Returns the value of attribute body.



42
43
44
# File 'lib/kronk/response.rb', line 42

def body
  @body
end

#byterateObject

Returns the value of attribute byterate.



42
43
44
# File 'lib/kronk/response.rb', line 42

def byterate
  @byterate
end

#bytesObject

Returns the value of attribute bytes.



42
43
44
# File 'lib/kronk/response.rb', line 42

def bytes
  @bytes
end

#codeObject

Returns the value of attribute code.



42
43
44
# File 'lib/kronk/response.rb', line 42

def code
  @code
end

#encodingObject (readonly)

Returns the value of attribute encoding.



45
46
47
# File 'lib/kronk/response.rb', line 45

def encoding
  @encoding
end

#headersObject Also known as: to_hash

Returns the value of attribute headers.



42
43
44
# File 'lib/kronk/response.rb', line 42

def headers
  @headers
end

#parserObject

Returns the value of attribute parser.



42
43
44
# File 'lib/kronk/response.rb', line 42

def parser
  @parser
end

#rawObject Also known as: to_s

Returns the value of attribute raw.



42
43
44
# File 'lib/kronk/response.rb', line 42

def raw
  @raw
end

#requestObject

Returns the value of attribute request.



42
43
44
# File 'lib/kronk/response.rb', line 42

def request
  @request
end

#timeObject

Returns the value of attribute time.



45
46
47
# File 'lib/kronk/response.rb', line 45

def time
  @time
end

#uriObject

Returns the value of attribute uri.



42
43
44
# File 'lib/kronk/response.rb', line 42

def uri
  @uri
end

Class Method Details

.read_file(path) ⇒ Object

Read http response from a file and return a HTTPResponse instance.



30
31
32
33
34
35
36
37
38
39
# File 'lib/kronk/response.rb', line 30

def self.read_file path
  Kronk::Cmd.verbose "Reading file:  #{path}\n"

  file     = File.open(path, "rb")
  resp     = new file
  resp.uri = path
  file.close

  resp
end

Instance Method Details

#[](key) ⇒ Object

Accessor for the HTTPResponse instance []



99
100
101
# File 'lib/kronk/response.rb', line 99

def [] key
  @_res[key]
end

#[]=(key, value) ⇒ Object

Accessor for the HTTPResponse instance []



107
108
109
# File 'lib/kronk/response.rb', line 107

def []= key, value
  @_res[key] = value
end

Cookie header accessor.



115
116
117
# File 'lib/kronk/response.rb', line 115

def cookie
  @_res['Cookie']
end

#follow_redirect(opts = {}) ⇒ Object

Follow the redirect and return a new Response instance. Returns nil if not redirect-able.



239
240
241
242
# File 'lib/kronk/response.rb', line 239

def follow_redirect opts={}
  return if !redirect?
  Request.new(@_res['Location'], opts).retrieve
end

#force_encoding(new_encoding) ⇒ Object

Force the encoding of the raw response and body



123
124
125
126
127
128
129
# File 'lib/kronk/response.rb', line 123

def force_encoding new_encoding
  new_encoding = Encoding.find new_encoding unless Encoding === new_encoding
  @encoding = new_encoding
  try_force_encoding @body
  try_force_encoding @raw
  @encoding
end

#headless?Boolean

If there was an error parsing the input as a standard http response, the input is assumed to be a body and HeadlessResponse is used.

Returns:

  • (Boolean)


136
137
138
# File 'lib/kronk/response.rb', line 136

def headless?
  HeadlessResponse === @_res
end

#inspectObject

Ruby inspect.



144
145
146
# File 'lib/kronk/response.rb', line 144

def inspect
  "#<#{self.class}:#{self.code} #{self['Content-Type']}>"
end

#parsed_body(parser = nil) ⇒ Object

Returns the body data parsed according to the content type. If no parser is given will look for the default parser based on the Content-Type, or will return the cached parsed body if available.

Raises:



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/kronk/response.rb', line 154

def parsed_body parser=nil
  @parsed_body ||= nil

  return @parsed_body if @parsed_body && !parser

  begin
    parser = Kronk.parser_for(parser) || Kronk.find_const(parser)
  rescue NameError
    raise InvalidParser, "No such parser: #{parser}"
  end if String === parser

  parser ||= @parser

  raise MissingParser,
    "No parser for Content-Type: #{@_res['Content-Type']}" unless parser

  begin
    @parsed_body = parser.parse(self.body) or raise RuntimeError

  rescue RuntimeError, ::Exception => e
    msg = ParserError === e ? e.message : "#{parser} failed parsing body"
    msg << " returned by #{@uri}" if @uri
    raise ParserError, msg
  end
end

#parsed_header(include_headers = true) ⇒ Object

Returns the parsed header hash.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/kronk/response.rb', line 184

def parsed_header include_headers=true
  headers = @_res.to_hash.dup

  case include_headers
  when nil, false
    nil

  when Array, String
    include_headers = [*include_headers].map{|h| h.to_s.downcase}

    headers.each do |key, value|
      headers.delete key unless
        include_headers.include? key.to_s.downcase
    end

    headers

  when true
    headers
  end
end

#raw_header(include_headers = true) ⇒ Object

Returns the header portion of the raw http response.



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/kronk/response.rb', line 210

def raw_header include_headers=true
  headers = "#{@raw.split("\r\n\r\n", 2)[0]}\r\n"

  case include_headers
  when nil, false
    nil

  when Array, String
    includes = [*include_headers].join("|")
    headers.scan(%r{^((?:#{includes}): [^\n]*\n)}im).flatten.join

  when true
    headers
  end
end

#redirect?Boolean

Check if this is a redirect response.

Returns:

  • (Boolean)


230
231
232
# File 'lib/kronk/response.rb', line 230

def redirect?
  @code.to_s =~ /^30\d$/
end

#selective_data(options = {}) ⇒ Object

Returns the parsed response with selective headers and/or the body of the response. Supports the following options:

:no_body

Bool - Don’t return the body; default nil

:with_headers

Bool/String/Array - Return headers; default nil

:parser

Object - The parser to use for the body; default nil

:ignore_data

String/Array - Removes the data from given data paths

:only_data

String/Array - Extracts the data from given data paths



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/kronk/response.rb', line 272

def selective_data options={}
  data = nil

  unless options[:no_body]
    data = parsed_body options[:parser]
  end

  if options[:with_headers]
    data = [parsed_header(options[:with_headers]), data].compact
  end

  Path::Transaction.run data, options do |t|
    t.select(*options[:only_data])
    t.delete(*options[:ignore_data])
  end
end

#selective_string(options = {}) ⇒ Object

Returns the raw response with selective headers and/or the body of the response. Supports the following options:

:no_body

Bool - Don’t return the body; default nil

:with_headers

Bool/String/Array - Return headers; default nil



251
252
253
254
255
256
257
258
259
260
# File 'lib/kronk/response.rb', line 251

def selective_string options={}
  str = @body unless options[:no_body]

  if options[:with_headers]
    header = raw_header(options[:with_headers])
    str = [header, str].compact.join "\r\n"
  end

  str
end

#stringify(options = {}) ⇒ Object

Returns a String representation of the response, the response body, or the response headers, parsed or in raw format. Options supported are:

:parser

Object/String - the parser for the body; default nil (raw)

:struct

Boolean - Return data types instead of values

:only_data

String/Array - extracts the data from given data paths

:ignore_data

String/Array - defines which data points to exclude

:raw

Boolean - Force using the unparsed raw response

:keep_indicies

Boolean - indicies of modified arrays display as hashes.

:with_headers

Boolean/String/Array - defines which headers to include



302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/kronk/response.rb', line 302

def stringify options={}
  if !options[:raw] && (options[:parser] || @parser)
    data = selective_data options
    Diff.ordered_data_string data, options[:struct]
  else
    selective_string options
  end

rescue MissingParser
  Cmd.verbose "Warning: No parser for #{@_res['Content-Type']} [#{@uri}]"
    selective_string options
end

#success?Boolean

Check if this is a 2XX response.

Returns:

  • (Boolean)


319
320
321
# File 'lib/kronk/response.rb', line 319

def success?
  @code.to_s =~ /^2\d\d$/
end

#total_bytesObject

Number of bytes of the response including the header.



337
338
339
# File 'lib/kronk/response.rb', line 337

def total_bytes
  self.raw.bytes.count
end