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

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

Overview

HTTP response class.

Direct Known Subclasses

Msf::Auxiliary::Web::HTTP::Response, E404, OK

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


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

def code
  @code
end

#count_100Object

Returns the value of attribute count_100


249
250
251
# File 'lib/rex/proto/http/response.rb', line 249

def count_100
  @count_100
end

#messageObject

Returns the value of attribute message


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

def message
  @message
end

#peerinfoObject

Host address:port associated with this request/response


244
245
246
# File 'lib/rex/proto/http/response.rb', line 244

def peerinfo
  @peerinfo
end

#protoObject

Returns the value of attribute proto


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

def proto
  @proto
end

#requestObject

Used to store a copy of the original request


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

def request
  @request
end

Instance Method Details

#check_100Object

Allow 100 Continues to be ignored by the caller


202
203
204
205
206
207
208
# File 'lib/rex/proto/http/response.rb', line 202

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.


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

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.


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/rex/proto/http/response.rb', line 165

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>)

140
141
142
143
# File 'lib/rex/proto/http/response.rb', line 140

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:


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

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)

123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rex/proto/http/response.rb', line 123

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

#redirect?Boolean

Answers if the response is a redirection one.

Returns:

  • (Boolean)

    true if the response is a redirection, false otherwise.


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

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.


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

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

#update_cmd_parts(str) ⇒ Object

Updates the various parts of the HTTP response command string.


187
188
189
190
191
192
193
194
195
196
197
# File 'lib/rex/proto/http/response.rb', line 187

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