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

E404, OK

Defined Under Namespace

Classes: E404, OK

Instance Attribute Summary collapse

Attributes inherited from Packet

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

Instance Method Summary collapse

Methods inherited from Packet

#[], #[]=, #chunk, #completed?, #from_s, #parse, #reset, #reset_except_queue, #to_s

Constructor Details

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

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



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

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.



229
230
231
# File 'lib/rex/proto/http/response.rb', line 229

def code
  @code
end

#count_100Object

Returns the value of attribute count_100.



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

def count_100
  @count_100
end

#messageObject

Returns the value of attribute message.



230
231
232
# File 'lib/rex/proto/http/response.rb', line 230

def message
  @message
end

#protoObject

Returns the value of attribute proto.



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

def proto
  @proto
end

#requestObject

Used to store a copy of the original request



226
227
228
# File 'lib/rex/proto/http/response.rb', line 226

def request
  @request
end

Instance Method Details

#check_100Object

Allow 100 Continues to be ignored by the caller



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

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.



219
220
221
# File 'lib/rex/proto/http/response.rb', line 219

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



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

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_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.



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/rex/proto/http/response.rb', line 152

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:



93
94
95
# File 'lib/rex/proto/http/response.rb', line 93

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


127
128
129
130
# File 'lib/rex/proto/http/response.rb', line 127

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:



137
138
139
140
141
# File 'lib/rex/proto/http/response.rb', line 137

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)


110
111
112
113
114
115
116
117
118
119
120
# File 'lib/rex/proto/http/response.rb', line 110

def get_json_document
  json = {}

  begin
    json = JSON.parse(self.body)
  rescue JSON::ParserError => e
    elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
  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:



102
103
104
# File 'lib/rex/proto/http/response.rb', line 102

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.



200
201
202
# File 'lib/rex/proto/http/response.rb', line 200

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.



208
209
210
211
212
213
214
# File 'lib/rex/proto/http/response.rb', line 208

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.



174
175
176
177
178
179
180
181
182
183
184
# File 'lib/rex/proto/http/response.rb', line 174

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