wwmd 0.2.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +38 -0
- data/README.rdoc +87 -0
- data/Rakefile +33 -0
- data/examples/config_example.yaml +24 -0
- data/examples/wwmd_example.rb +73 -0
- data/lib/wwmd.rb +84 -0
- data/lib/wwmd/class_extensions.rb +4 -0
- data/lib/wwmd/class_extensions/extensions_base.rb +251 -0
- data/lib/wwmd/class_extensions/extensions_encoding.rb +79 -0
- data/lib/wwmd/class_extensions/extensions_external.rb +18 -0
- data/lib/wwmd/class_extensions/extensions_nilclass.rb +11 -0
- data/lib/wwmd/class_extensions/extensions_rbkb.rb +193 -0
- data/lib/wwmd/class_extensions/mixins_string_encoding.rb +40 -0
- data/lib/wwmd/guid.rb +155 -0
- data/lib/wwmd/page.rb +3 -0
- data/lib/wwmd/page/_fa.old +302 -0
- data/lib/wwmd/page/auth.rb +17 -0
- data/lib/wwmd/page/constants.rb +63 -0
- data/lib/wwmd/page/form.rb +99 -0
- data/lib/wwmd/page/form_array.rb +304 -0
- data/lib/wwmd/page/headers.rb +118 -0
- data/lib/wwmd/page/helpers.rb +41 -0
- data/lib/wwmd/page/html2text_hpricot.rb +76 -0
- data/lib/wwmd/page/html2text_nokogiri.rb +42 -0
- data/lib/wwmd/page/inputs.rb +47 -0
- data/lib/wwmd/page/irb_helpers.rb +114 -0
- data/lib/wwmd/page/page.rb +257 -0
- data/lib/wwmd/page/parsing_convenience.rb +98 -0
- data/lib/wwmd/page/reporting_helpers.rb +89 -0
- data/lib/wwmd/page/scrape.rb +196 -0
- data/lib/wwmd/page/spider.rb +127 -0
- data/lib/wwmd/urlparse.rb +125 -0
- data/lib/wwmd/viewstate.rb +17 -0
- data/lib/wwmd/viewstate/viewstate.rb +101 -0
- data/lib/wwmd/viewstate/viewstate_deserializer_methods.rb +217 -0
- data/lib/wwmd/viewstate/viewstate_from_xml.rb +129 -0
- data/lib/wwmd/viewstate/viewstate_types.rb +51 -0
- data/lib/wwmd/viewstate/viewstate_utils.rb +164 -0
- data/lib/wwmd/viewstate/viewstate_yaml.rb +25 -0
- data/lib/wwmd/viewstate/vs_stubs.rb +22 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_array.rb +38 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_binary_serialized.rb +30 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_hashtable.rb +42 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_hybrid_dict.rb +42 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_indexed_string.rb +6 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_indexed_string_ref.rb +24 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_int_enum.rb +27 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_list.rb +34 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_pair.rb +29 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_read_types.rb +11 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_read_value.rb +35 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_sparse_array.rb +58 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_string.rb +33 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_string_array.rb +39 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_string_formatted.rb +32 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_stub_helpers.rb +37 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_triplet.rb +31 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_type.rb +23 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_unit.rb +30 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_value.rb +35 -0
- data/lib/wwmd/wwmd_config.rb +52 -0
- data/lib/wwmd/wwmd_puts.rb +9 -0
- data/lib/wwmd/wwmd_utils.rb +28 -0
- data/spec/README +3 -0
- data/spec/form_array.spec +49 -0
- data/spec/spider_csrf_test.spec +28 -0
- data/spec/urlparse_test.spec +101 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- metadata +222 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
# Geoff Davis geoff at geoffdavis.net
|
2
|
+
# Wed May 2 20:08:44 EDT 2007
|
3
|
+
# http://rubyforge.org/pipermail/raleigh-rb-members/2007-May/000789.html
|
4
|
+
# modified by mtracy at matasano.com for WWMD
|
5
|
+
|
6
|
+
module WWMD
|
7
|
+
InlineTags = ['a','abbr','acronym','address','b','bdo','big','cite','code','del','dfn','em','font','i','ins','kbd','label','noframes','noscript','q','s','samp','small','span','strike','strong','sub','sup','td','th','tt','u','html','body','table']
|
8
|
+
BlockTags = ['blockquote','br','center','dd','div','fieldset','form','h1','h2','h3', 'h4','h5','h6','hr','p','pre','tr','var',]
|
9
|
+
ListTags = ['dir','dl','menu','ol','ul']
|
10
|
+
ItemTags = ['li','dt']
|
11
|
+
# AsciiEquivalents = {"amp"=>"&","bull"=>"*","copy"=>"(c)","laquo"=>"<<","raquo"=>">>","ge"=> ">=","le"=>"<=","mdash"=>"-","ndash"=>"-","plusmn"=>"+/-","times"=>"x"}
|
12
|
+
|
13
|
+
# NamedCharRegex = Regexp.new("(&("+Hpricot::NamedCharacters.keys.join("|")+");)")
|
14
|
+
|
15
|
+
class Page
|
16
|
+
def element_to_text(n)
|
17
|
+
tag = n.etag || n.stag
|
18
|
+
name = tag.name.downcase
|
19
|
+
s = ""
|
20
|
+
is_block = BlockTags.include?(name)
|
21
|
+
is_list = ListTags.include?(name)
|
22
|
+
is_item = ItemTags.include?(name)
|
23
|
+
is_inline = InlineTags.include?(name)
|
24
|
+
if is_block or is_list or is_item or is_inline
|
25
|
+
n.each_child do |c|
|
26
|
+
s += node_to_text(c)
|
27
|
+
end
|
28
|
+
if is_block or is_list
|
29
|
+
s += "\n"
|
30
|
+
elsif is_item
|
31
|
+
s = "* " + s + "\n"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
s
|
35
|
+
end
|
36
|
+
|
37
|
+
def node_to_text(n)
|
38
|
+
return "" if n.comment?
|
39
|
+
return element_to_text(n) if n.elem?
|
40
|
+
return n.inner_text if n.text?
|
41
|
+
|
42
|
+
s = ""
|
43
|
+
begin
|
44
|
+
n.each_child do |c|
|
45
|
+
s += node_to_text(c)
|
46
|
+
end
|
47
|
+
rescue => e
|
48
|
+
putw "WARN: #{e.inspect}"
|
49
|
+
end
|
50
|
+
return s
|
51
|
+
end
|
52
|
+
|
53
|
+
# def lookup_named_char(s)
|
54
|
+
# c = Hpricot::NamedCharacters[s[1...-1]]
|
55
|
+
# c.chr if c
|
56
|
+
# end
|
57
|
+
|
58
|
+
def html2text
|
59
|
+
doc = self.scrape.hdoc
|
60
|
+
text = node_to_text(doc)
|
61
|
+
# text.gsub!(NamedCharRegex){|s| "#{lookup_named_char(s)}"}
|
62
|
+
# clean up white space
|
63
|
+
text.gsub!("\r"," ")
|
64
|
+
text.squeeze!(" ")
|
65
|
+
text.strip!
|
66
|
+
ret = ''
|
67
|
+
text.split(/\n/).each do |l|
|
68
|
+
l.strip!
|
69
|
+
next if l == ''
|
70
|
+
next if l =~ /^\?+$/
|
71
|
+
ret += "#{l}\n"
|
72
|
+
end
|
73
|
+
return ret
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
html2text that works with Nokogiri
|
3
|
+
=end
|
4
|
+
module WWMD
|
5
|
+
|
6
|
+
INLINETAGS = ['a','abbr','acronym','address','b','bdo','big','cite',
|
7
|
+
'code','del','dfn','em','font','i','ins','kbd','label',
|
8
|
+
'noframes','noscript','q','s','samp','small','span',
|
9
|
+
'strike','strong','sub','sup','td','th','tt','u',
|
10
|
+
'html','body','table']
|
11
|
+
BLOCKTAGS = ['blockquote','center','dd','div','fieldset','form',
|
12
|
+
'h1','h2','h3','h4','h5','h6','p','pre','tr','var',]
|
13
|
+
LISTTAGS = ['dir','dl','menu','ol','ul']
|
14
|
+
ITEMTAGS = ['li','dt']
|
15
|
+
SPECIALTAGS = ['br','hr']
|
16
|
+
|
17
|
+
class Page
|
18
|
+
def html2text
|
19
|
+
arr = []
|
20
|
+
self.scrape.hdoc.traverse do |x|
|
21
|
+
arr << [x.parent.name,x.text] if x.text?
|
22
|
+
if x.elem?
|
23
|
+
arr << [x.name,""] if SPECIALTAGS.include?(x.name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
ret = ""
|
27
|
+
arr.each do |name,str|
|
28
|
+
(ret += "\n"; next ) if name == "br"
|
29
|
+
(ret += "\n" + ("-" * 72) + "\n"; next) if name == "hr"
|
30
|
+
s = str.strip
|
31
|
+
if BLOCKTAGS.include?(name) or LISTTAGS.include?(name)
|
32
|
+
s += "\n"
|
33
|
+
elsif ITEMTAGS.include?(name)
|
34
|
+
s = "* " + s + "\n"
|
35
|
+
end
|
36
|
+
ret += s
|
37
|
+
end
|
38
|
+
ret.gsub(/\n+/) { "\n" }
|
39
|
+
ret.gsub(/[^\x20-\x7e,\n]/,"").gsub(/^\n/,"")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module WWMD
|
2
|
+
class Inputs
|
3
|
+
attr_accessor :elems
|
4
|
+
|
5
|
+
@cobj = '' # wwmd object
|
6
|
+
@elems = '' # array of elems parse out by self.new()
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
@cobj = args.shift
|
10
|
+
end
|
11
|
+
|
12
|
+
def show
|
13
|
+
putx @elems
|
14
|
+
end
|
15
|
+
|
16
|
+
# call me from Page.set_data
|
17
|
+
def set
|
18
|
+
@elems = [@cobj.search("//input").map,@cobj.search("//select").map].flatten
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(attr=nil)
|
22
|
+
@elems.map { |x| x[attr] }.reject { |y| y.nil? }
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# return: FormArray containing all page inputs
|
27
|
+
def form
|
28
|
+
ret = {}
|
29
|
+
@elems.map do |x|
|
30
|
+
name = x['name']
|
31
|
+
id = x['id']
|
32
|
+
next if (name.nil? && id.nil?)
|
33
|
+
value = x['value']
|
34
|
+
type = x['type']
|
35
|
+
ret[name] = value
|
36
|
+
ret[id] = value if ((id || name) != name)
|
37
|
+
end
|
38
|
+
return FormArray.new(ret)
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# return: FormArray containing get params
|
43
|
+
def params
|
44
|
+
return FormArray.new(@cobj.cur.clop.to_form)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
this file contains methods to help operations in irb (display methods etc.).
|
3
|
+
=end
|
4
|
+
module WWMD
|
5
|
+
class Page
|
6
|
+
|
7
|
+
#:section: IRB helper methods
|
8
|
+
|
9
|
+
def head(i=1)
|
10
|
+
if i.kind_of?(Range)
|
11
|
+
puts self.body_data.split("\n")[i].join("\n")
|
12
|
+
return nil
|
13
|
+
end
|
14
|
+
puts self.body_data.head(i)
|
15
|
+
end
|
16
|
+
|
17
|
+
# IRB: text report what has been parsed from this page
|
18
|
+
def report(short=nil)
|
19
|
+
puts "-------------------------------------------------"
|
20
|
+
self.summary
|
21
|
+
puts "---- links found [#{self.has_links?.to_s} | #{self.links.size}]"
|
22
|
+
self.links.each_index { |i| puts "#{i.to_s} :: #{@links[i]}" } if short.nil?
|
23
|
+
puts "---- javascript found [#{self.has_jlinks?.to_s} | #{self.jlinks.size}]"
|
24
|
+
self.jlinks.each { |url| puts url } if short.nil?
|
25
|
+
puts "---- forms found [#{self.has_form?.to_s} | #{self.forms.size}]"
|
26
|
+
puts "---- comments found [#{self.has_comments?.to_s}]"
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :show, :report#:nodoc:
|
31
|
+
|
32
|
+
# IRB: display summary of what has been parsed from this page
|
33
|
+
def summary
|
34
|
+
status = self.page_status
|
35
|
+
puts "XXXX[#{self.report_flags}] | #{self.response_code.to_s} | #{status} | #{self.url} | #{self.size}"
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# IRB: display current headers
|
40
|
+
def request_headers
|
41
|
+
self.headers.each_pair { |k,v| puts "#{k}: #{v}" }
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :show_headers, :request_headers#:nodoc:
|
46
|
+
alias_method :req_headers, :request_headers#:nodoc:
|
47
|
+
|
48
|
+
# IRB: display response headers
|
49
|
+
def response_headers
|
50
|
+
self.header_data.each { |x| puts "#{x[0]} :: #{x[1]}" }
|
51
|
+
return nil
|
52
|
+
end
|
53
|
+
|
54
|
+
alias_method :resp_headers, :response_headers#:nodoc:
|
55
|
+
|
56
|
+
# display self.body_data
|
57
|
+
def dump_body
|
58
|
+
puts self.body_data
|
59
|
+
end
|
60
|
+
|
61
|
+
alias_method :dump, :dump_body#:nodoc:
|
62
|
+
|
63
|
+
# IRB: puts the page filtered through html2text
|
64
|
+
def to_text; puts self.html2text; end
|
65
|
+
def text; self.html2text; end
|
66
|
+
|
67
|
+
# IRB: display a human readable report of all forms contained in page.body_data
|
68
|
+
def all_forms
|
69
|
+
self.forms.each_index { |x| puts "[#{x.to_s}]-------"; self.forms[x].report }
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def onclicks
|
74
|
+
self.search("//*[@onclick]").each { |x| puts x[:onclick] }
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
# hexdump self.body_data
|
79
|
+
def hexdump
|
80
|
+
puts self.body_data.hexdump
|
81
|
+
end
|
82
|
+
|
83
|
+
# this only works on a mac so get a mac
|
84
|
+
def open #:nodoc:
|
85
|
+
fn = "wwmdtmp_#{Guid.new}.html"
|
86
|
+
self.write(fn)
|
87
|
+
%x[open #{fn}]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Form
|
92
|
+
def report
|
93
|
+
return nil if not WWMD::console
|
94
|
+
puts "action = #{self.action}"
|
95
|
+
self.fields.each { |field| puts field.to_text }
|
96
|
+
return nil
|
97
|
+
end
|
98
|
+
alias_method :show, :report
|
99
|
+
end
|
100
|
+
|
101
|
+
class FormArray
|
102
|
+
# IRB: puts the form in human readable format
|
103
|
+
# if you <tt>form.show(true)</tt> it will show unescaped values
|
104
|
+
def show(unescape=false)
|
105
|
+
if unescape
|
106
|
+
self.each_index { |i| puts i.to_s + " :: " + self[i][0].to_s + " = " + self[i][1].to_s.unescape }
|
107
|
+
else
|
108
|
+
self.each_index { |i| puts i.to_s + " :: " + self[i][0].to_s + " = " + self[i][1].to_s }
|
109
|
+
end
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,257 @@
|
|
1
|
+
module WWMD
|
2
|
+
# WWMD::Page is an extension of a Curl::Easy object which provides methods to
|
3
|
+
# enhance and ease the performance of web application penetration testing.
|
4
|
+
class Page
|
5
|
+
attr_accessor :curl_object
|
6
|
+
attr_accessor :body_data
|
7
|
+
attr_accessor :post_data
|
8
|
+
attr_accessor :header_data
|
9
|
+
attr_accessor :use_referer
|
10
|
+
attr_reader :forms
|
11
|
+
attr_reader :last_error
|
12
|
+
attr_reader :links # array of links (urls)
|
13
|
+
attr_reader :jlinks # array of included javascript files
|
14
|
+
attr_reader :spider # spider object
|
15
|
+
attr_reader :scrape # scrape object
|
16
|
+
attr_reader :urlparse # urlparse object
|
17
|
+
attr_reader :comments
|
18
|
+
|
19
|
+
attr_reader :header_file
|
20
|
+
|
21
|
+
attr_accessor :base_url # needed to properly munge relative urls into fq urls
|
22
|
+
attr_accessor :logged_in # are we logged in?
|
23
|
+
|
24
|
+
attr_accessor :opts
|
25
|
+
attr_accessor :inputs
|
26
|
+
|
27
|
+
|
28
|
+
include WWMDUtils
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
# hack
|
32
|
+
return "Page"
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(opts={}, &block)
|
36
|
+
@opts = opts.clone
|
37
|
+
DEFAULTS.each { |k,v| @opts[k] = v unless @opts.has_key?(k) }
|
38
|
+
@spider = Spider.new(@opts)
|
39
|
+
@scrape = Scrape.new
|
40
|
+
@base_url ||= opts[:base_url]
|
41
|
+
@scrape.warn = opts[:scrape_warn] if !opts[:scrape_warn].nil? # yeah yeah... bool false
|
42
|
+
@urlparse = URLParse.new()
|
43
|
+
@inputs = Inputs.new(self)
|
44
|
+
@logged_in = false
|
45
|
+
@body_data = ""
|
46
|
+
@post_data = ""
|
47
|
+
@comments = []
|
48
|
+
@header_data = FormArray.new
|
49
|
+
@header_file = nil
|
50
|
+
|
51
|
+
@curl_object = Curl::Easy.new
|
52
|
+
@opts.each do |k,v|
|
53
|
+
next if k == :proxy_url
|
54
|
+
if (@curl_object.respond_to?("#{k}=".intern))
|
55
|
+
@curl_object.send("#{k}=".intern,v)
|
56
|
+
else
|
57
|
+
self.instance_variable_set("@#{k.to_s}".intern,v)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
@curl_object.on_body { |data| self._body_cb(data) }
|
61
|
+
@curl_object.on_header { |data| self._header_cb(data) }
|
62
|
+
|
63
|
+
# cookies?
|
64
|
+
@curl_object.enable_cookies = @opts[:enable_cookies]
|
65
|
+
if @curl_object.enable_cookies?
|
66
|
+
@curl_object.cookiejar = @opts[:cookiejar] || "./__cookiejar"
|
67
|
+
end
|
68
|
+
|
69
|
+
#proxy?
|
70
|
+
@curl_object.proxy_url = @opts[:proxy_url] if @opts[:use_proxy]
|
71
|
+
instance_eval(&block) if block_given?
|
72
|
+
if opts.empty? && @scrape.warn
|
73
|
+
putw "Page initialized without opts"
|
74
|
+
@scrape.warn = false
|
75
|
+
end
|
76
|
+
|
77
|
+
if @header_file
|
78
|
+
begin
|
79
|
+
headers_from_file(@header_file)
|
80
|
+
@curl_object.enable_cookies = false
|
81
|
+
rescue => e
|
82
|
+
puts "ERROR: #{e}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#:section: Heavy Lifting
|
88
|
+
|
89
|
+
# set reporting data for the page
|
90
|
+
#
|
91
|
+
# Scan for comments, anchors, links and javascript includes and
|
92
|
+
# set page flags. The heavy lifting for parsing is done in the
|
93
|
+
# scrape class.
|
94
|
+
#
|
95
|
+
# returns: <tt>array [ code, page_status, body_data.size ]</tt>
|
96
|
+
def set_data
|
97
|
+
# reset scrape and inputs object
|
98
|
+
# transparently gunzip
|
99
|
+
begin
|
100
|
+
io = StringIO.new(self.body_data)
|
101
|
+
gz = Zlib::GzipReader.new(io)
|
102
|
+
self.body_data.replace(gz.read)
|
103
|
+
rescue => e
|
104
|
+
end
|
105
|
+
@scrape.reset(self.body_data)
|
106
|
+
@inputs.set
|
107
|
+
|
108
|
+
# remove comments that are css selectors for IE silliness
|
109
|
+
@comments = @scrape.for_comments.reject do |c|
|
110
|
+
c =~ /\[if IE\]/ ||
|
111
|
+
c =~ /\[if IE \d/ ||
|
112
|
+
c =~ /\[if lt IE \d/
|
113
|
+
end
|
114
|
+
@links = @scrape.for_links.map do |url|
|
115
|
+
l = @urlparse.parse(self.last_effective_url,url).to_s
|
116
|
+
end
|
117
|
+
@jlinks = @scrape.for_javascript_links
|
118
|
+
@forms = @scrape.for_forms
|
119
|
+
@spider.add(self.last_effective_url,@links)
|
120
|
+
return [self.code,self.body_data.size]
|
121
|
+
end
|
122
|
+
|
123
|
+
# clear self.body_data and self.header_data
|
124
|
+
def clear_data
|
125
|
+
return false if self.opts[:parse] = false
|
126
|
+
@body_data = ""
|
127
|
+
@post_data = nil
|
128
|
+
@header_data.clear
|
129
|
+
@last_error = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
# override Curl::Easy.perform to perform page actions,
|
133
|
+
# call <tt>self.set_data</tt>
|
134
|
+
#
|
135
|
+
# returns: <tt>array [ code, page_status, body_data.size ]</tt>
|
136
|
+
#
|
137
|
+
# don't call this directly if we are in console mode
|
138
|
+
# use get and submit respectively for GET and POST
|
139
|
+
def perform
|
140
|
+
self.clear_data
|
141
|
+
self.headers["Referer"] = self.cur if self.use_referer
|
142
|
+
begin
|
143
|
+
@curl_object.perform
|
144
|
+
rescue => e
|
145
|
+
@last_error = e
|
146
|
+
putw "WARN: #{e.class}" if e.class =~ /Curl::Err/
|
147
|
+
end
|
148
|
+
self.set_data
|
149
|
+
end
|
150
|
+
|
151
|
+
# replacement for Curl::Easy.http_post
|
152
|
+
#
|
153
|
+
# post the form attempting to remove curl supplied headers (Expect, X-Forwarded-For
|
154
|
+
# call <tt>self.set_data</tt>
|
155
|
+
#
|
156
|
+
# if passed a regexp, escape values in the form using regexp before submitting
|
157
|
+
# if passed nil for the regexp arg, the form will not be escaped
|
158
|
+
# default: WWMD::ESCAPE[:url]
|
159
|
+
#
|
160
|
+
# returns: <tt>array [ code, body_data.size ]</tt>
|
161
|
+
def submit(iform=nil,reg=WWMD::ESCAPE[:default])
|
162
|
+
## this is just getting worse and worse
|
163
|
+
if iform.class == "Symbol"
|
164
|
+
reg = iform
|
165
|
+
iform = nil
|
166
|
+
end
|
167
|
+
reg = WWMD::ESCAPE[reg] if reg.class == Symbol
|
168
|
+
self.clear_data
|
169
|
+
["Expect","X-Forwarded-For","Content-length"].each { |s| self.clear_header(s) }
|
170
|
+
self.headers["Referer"] = self.cur if self.use_referer
|
171
|
+
unless iform
|
172
|
+
unless self.form.empty?
|
173
|
+
sform = self.form.clone
|
174
|
+
else
|
175
|
+
return "no form provided"
|
176
|
+
end
|
177
|
+
else
|
178
|
+
sform = iform.clone # clone the form so that we don't change the original
|
179
|
+
end
|
180
|
+
sform.escape_all!(reg)
|
181
|
+
self.url = sform.action if sform.action
|
182
|
+
if sform.empty?
|
183
|
+
self.http_post('')
|
184
|
+
else
|
185
|
+
self.http_post(self.post_data = sform.to_post)
|
186
|
+
end
|
187
|
+
self.set_data
|
188
|
+
end
|
189
|
+
|
190
|
+
# submit a form using POST string
|
191
|
+
def submit_string(post_string)
|
192
|
+
self.clear_data
|
193
|
+
self.http_post(post_string)
|
194
|
+
putw "WARN: authentication headers in response" if self.auth?
|
195
|
+
self.set_data
|
196
|
+
end
|
197
|
+
|
198
|
+
# override for Curl::Easy.perform
|
199
|
+
#
|
200
|
+
# if the passed url string doesn't contain an fully qualified
|
201
|
+
# path, we'll guess and prepend opts[:base_url]
|
202
|
+
#
|
203
|
+
# returns: <tt>array [ code, body_data.size ]</tt>
|
204
|
+
def get(url=nil,parse=true)
|
205
|
+
self.clear_data
|
206
|
+
self.headers["Referer"] = self.cur if self.use_referer
|
207
|
+
if !(url =~ /[a-z]+:\/\//) && parse
|
208
|
+
self.url = @urlparse.parse(self.base_url,url).to_s if url
|
209
|
+
elsif url
|
210
|
+
self.url = url
|
211
|
+
end
|
212
|
+
self.http_get
|
213
|
+
putw "WARN: authentication headers in response" if self.auth?
|
214
|
+
self.set_data
|
215
|
+
end
|
216
|
+
|
217
|
+
# GET with params and POST it as a form
|
218
|
+
def post(url=nil)
|
219
|
+
ep = url.clip
|
220
|
+
self.url = @urlparse.parse(self.opts[:base_url],ep).to_s if ep
|
221
|
+
form = url.clop.to_form
|
222
|
+
self.submit(form)
|
223
|
+
end
|
224
|
+
|
225
|
+
# send arbitrary verb (only works with patch to taf2-curb)
|
226
|
+
def verb(verb,url=nil)
|
227
|
+
return false if !@curl_object.respond_to?(:http_verb)
|
228
|
+
self.url = url if url
|
229
|
+
self.clear_data
|
230
|
+
self.headers["Referer"] = self.cur if self.use_referer
|
231
|
+
self.http_verb(verb)
|
232
|
+
self.set_data
|
233
|
+
end
|
234
|
+
|
235
|
+
#:section: Data callbacks and method_missing
|
236
|
+
|
237
|
+
# callback for <tt>self.on_body</tt>
|
238
|
+
def _body_cb(data)
|
239
|
+
@body_data << data if data
|
240
|
+
return data.length.to_i
|
241
|
+
end
|
242
|
+
|
243
|
+
# callback for <tt>self.on_header</tt>
|
244
|
+
def _header_cb(data)
|
245
|
+
myArr = Array.new(data.split(":",2))
|
246
|
+
@header_data.add(myArr[0].to_s.strip,myArr[1].to_s.strip)
|
247
|
+
# @header_data[myArr[0].to_s.strip] = myArr[1].to_s.strip
|
248
|
+
return data.length.to_i
|
249
|
+
end
|
250
|
+
|
251
|
+
# send methods not defined here to <tt>@curl_object</tt>
|
252
|
+
def method_missing(methodname, *args)
|
253
|
+
@curl_object.send(methodname, *args)
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
end
|