Class: Rex::Proto::Http::Response

Inherits:
Packet
  • Object
show all
Defined in:
lib/rex/proto/http/response.rb

Overview

HTTP response class.

Defined Under Namespace

Classes: E404, OK

Instance Attribute Summary collapse

Attributes inherited from Packet

#auto_cl, #body, #body_bytes_left, #bufq, #chunk_max_size, #chunk_min_size, #compress, #error, #headers, #incomplete, #inside_chunk, #keepalive, #max_data, #state, #transfer_chunked

Instance Method Summary collapse

Methods inherited from Packet

#[], #[]=, #chunk, #completed?, #from_s, #output_packet, #parse, #parse_body, #parse_header, #reset, #reset_except_queue, #to_s, #to_terminal_output

Constructor Details

#initialize(code = 200, message = 'OK', proto = DefaultProtocol) ⇒ Response

Constructage of the HTTP response with the supplied code, message, and protocol.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rex/proto/http/response.rb', line 47

def initialize(code = 200, message = 'OK', proto = DefaultProtocol)
  super()

  self.code    = code.to_i
  self.message = message
  self.proto   = proto

  # Default responses to auto content length on
  self.auto_cl = true

  # default chunk sizes (if chunked is used)
  self.chunk_min_size = 1
  self.chunk_max_size = 10

  # 100 continue counter
  self.count_100 = 0
end

Instance Attribute Details

#codeObject

Returns the value of attribute code.



254
255
256
# File 'lib/rex/proto/http/response.rb', line 254

def code
  @code
end

#count_100Object

Returns the value of attribute count_100.



257
258
259
# File 'lib/rex/proto/http/response.rb', line 257

def count_100
  @count_100
end

#messageObject

Returns the value of attribute message.



255
256
257
# File 'lib/rex/proto/http/response.rb', line 255

def message
  @message
end

#peerinfoObject

Host address:port associated with this request/response



252
253
254
# File 'lib/rex/proto/http/response.rb', line 252

def peerinfo
  @peerinfo
end

#protoObject

Returns the value of attribute proto.



256
257
258
# File 'lib/rex/proto/http/response.rb', line 256

def proto
  @proto
end

#requestObject

Used to store a copy of the original request



247
248
249
# File 'lib/rex/proto/http/response.rb', line 247

def request
  @request
end

Instance Method Details

#check_100Object

Allow 100 Continues to be ignored by the caller



212
213
214
215
216
217
218
# File 'lib/rex/proto/http/response.rb', line 212

def check_100
  # If this was a 100 continue with no data, reset
  if self.code == 100 and (self.body_bytes_left == -1 or self.body_bytes_left == 0) and self.count_100 < 5
    self.reset_except_queue
    self.count_100 += 1
  end
end

#cmd_stringObject

Returns the response based command string.



240
241
242
# File 'lib/rex/proto/http/response.rb', line 240

def cmd_string
  "HTTP\/#{proto} #{code}#{(message and message.length > 0) ? ' ' + message : ''}\r\n"
end

#get_cookiesObject

Gets cookies from the Set-Cookie header in a format to be used in the ‘cookie’ send_request field



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rex/proto/http/response.rb', line 69

def get_cookies
  cookies = ""
  if (self.headers.include?('Set-Cookie'))
    set_cookies = self.headers['Set-Cookie']
    key_vals = set_cookies.scan(/\s?([^, ;]+?)=([^, ;]*?)[;,]/)
    key_vals.each do |k, v|
      # Dont downcase actual cookie name as may be case sensitive
      name = k.downcase
      next if name == 'path'
      next if name == 'expires'
      next if name == 'domain'
      next if name == 'max-age'
      cookies << "#{k}=#{v}; "
    end
  end

  return cookies.strip
end

#get_cookies_parsedObject

Gets cookies from the Set-Cookie header in a parsed format



91
92
93
94
95
96
97
98
# File 'lib/rex/proto/http/response.rb', line 91

def get_cookies_parsed
  if (self.headers.include?('Set-Cookie'))
    ret = CGI::Cookie::parse(self.headers['Set-Cookie'])
  else
    ret = {}
  end
  ret
end

#get_hidden_inputsArray<Hash>

Returns a collection of found hidden inputs

Examples:

res = send_request_cgi('uri'=>'/')
inputs = res.get_hidden_inputs
session_id = inputs[0]['sessionid'] # The first form's 'sessionid' hidden input

Returns:

  • (Array<Hash>)

    An array, each element represents a form that contains a hash of found hidden inputs

    • 'name' [String] The hidden input's original name. The value is the hidden input's original value.



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/rex/proto/http/response.rb', line 175

def get_hidden_inputs
  forms = []
  noko = get_html_document
  noko.search("form").each_entry do |form|
    found_inputs = {}
    form.search("input").each_entry do |input|
      input_type = input.attributes['type'] ? input.attributes['type'].value : ''
      next if input_type !~ /hidden/i

      input_name = input.attributes['name'] ? input.attributes['name'].value : ''
      input_value = input.attributes['value'] ? input.attributes['value'].value : ''
      found_inputs[input_name] = input_value unless input_name.empty?
    end
    forms << found_inputs unless found_inputs.empty?
  end

  forms
end

#get_html_documentNokogiri::HTML::Document

Returns a parsed HTML document. Instead of using regexes to parse the HTML body, you should use this and use the Nokogiri API.

Returns:

  • (Nokogiri::HTML::Document)

See Also:



106
107
108
# File 'lib/rex/proto/http/response.rb', line 106

def get_html_document
  Nokogiri::HTML(self.body)
end

#get_html_meta_elementsArray<Nokogiri::XML::Element>

Returns meta tags. You will probably want to use this the web app’s version info (or other stuff) can be found in the metadata.

Returns:

  • (Array<Nokogiri::XML::Element>)


150
151
152
153
# File 'lib/rex/proto/http/response.rb', line 150

def get_html_meta_elements
  n = get_html_document
  n.search('//meta')
end

#get_html_scriptsArray<RKelly::Nodes::SourceElementsNode>

Returns parsed JavaScript blocks. The parsed version is a RKelly object that allows you to be able do advanced parsing.

Returns:

  • (Array<RKelly::Nodes::SourceElementsNode>)

See Also:



160
161
162
163
164
# File 'lib/rex/proto/http/response.rb', line 160

def get_html_scripts
  n = get_html_document
  rkelly = RKelly::Parser.new
  n.search('//script').map { |s| rkelly.parse(s.text) }
end

#get_json_documentHash

Returns a parsed json document. Instead of using regexes to parse the JSON body, you should use this.

Returns:

  • (Hash)


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

def get_json_document
  json = {}

  begin
    json = JSON.parse(self.body)
  rescue JSON::ParserError => e
    elog(e)
  end

  json
end

#get_xml_documentNokogiri::XML::Document

Returns a parsed XML document. Instead of using regexes to parse the XML body, you should use this and use the Nokogiri API.

Returns:

  • (Nokogiri::XML::Document)

See Also:



115
116
117
# File 'lib/rex/proto/http/response.rb', line 115

def get_xml_document
  Nokogiri::XML(self.body)
end

#gzip_decodeObject



123
124
125
126
127
# File 'lib/rex/proto/http/response.rb', line 123

def gzip_decode
  gz = Zlib::GzipReader.new(StringIO.new(self.body.to_s))    

  gz.read
end

#gzip_decode!Object



119
120
121
# File 'lib/rex/proto/http/response.rb', line 119

def gzip_decode!
  self.body = gzip_decode
end

#redirect?Boolean

Answers if the response is a redirection one.

Returns:

  • (Boolean)

    true if the response is a redirection, false otherwise.



223
224
225
# File 'lib/rex/proto/http/response.rb', line 223

def redirect?
  [301, 302, 303, 307, 308].include?(code)
end

#redirectionURI?

Provides the uri of the redirection location.

Returns:

  • (URI)

    the uri of the redirection location.

  • (nil)

    if the response hasn't a Location header or it isn't a valid uri.



231
232
233
234
235
# File 'lib/rex/proto/http/response.rb', line 231

def redirection
  URI(headers['Location'])
rescue ArgumentError, ::URI::InvalidURIError
  nil
end

#update_cmd_parts(str) ⇒ Object

Updates the various parts of the HTTP response command string.



197
198
199
200
201
202
203
204
205
206
207
# File 'lib/rex/proto/http/response.rb', line 197

def update_cmd_parts(str)
  if (md = str.match(/HTTP\/(.+?)\s+(\d+)\s?(.+?)\r?\n?$/))
    self.message = md[3].gsub(/\r/, '')
    self.code    = md[2].to_i
    self.proto   = md[1]
  else
    raise RuntimeError, "Invalid response command string", caller
  end

  check_100()
end