rhack 0.4.1 → 1.0.0.rc4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +2 -5
  3. data/LICENSE +19 -15
  4. data/README.md +66 -26
  5. data/Rakefile +42 -31
  6. data/config/cacert.pem +3895 -0
  7. data/config/rhack.yml.template +40 -0
  8. data/ext/curb-original/curb_config.h +3 -0
  9. data/ext/curb-original/curb_easy.c +3 -54
  10. data/ext/curb-original/curb_multi.c +69 -140
  11. data/ext/curb/curb_multi.c +1 -1
  12. data/lib/rhack.rb +82 -12
  13. data/lib/rhack/cookie.rb +49 -0
  14. data/lib/rhack/curl.rb +6 -0
  15. data/lib/{extensions/curb.rb → rhack/curl/easy.rb} +26 -48
  16. data/lib/rhack/curl/global.rb +175 -0
  17. data/lib/rhack/curl/itt.rb +11 -0
  18. data/lib/rhack/curl/multi.rb +37 -0
  19. data/lib/rhack/curl/post_field.rb +20 -0
  20. data/lib/rhack/curl/response.rb +91 -0
  21. data/lib/rhack/dl.rb +308 -0
  22. data/lib/rhack/frame.rb +316 -0
  23. data/lib/{extensions → rhack/js}/browser/env.js +0 -0
  24. data/lib/{extensions → rhack/js}/browser/jquery.js +0 -0
  25. data/lib/{extensions → rhack/js}/browser/xmlsax.js +0 -0
  26. data/lib/{extensions → rhack/js}/browser/xmlw3cdom_1.js +0 -0
  27. data/lib/{extensions → rhack/js}/browser/xmlw3cdom_2.js +0 -0
  28. data/lib/rhack/js/johnson.rb +71 -0
  29. data/lib/rhack/page.rb +263 -0
  30. data/lib/rhack/proxy.rb +3 -0
  31. data/lib/rhack/proxy/checker.rb +1 -1
  32. data/lib/rhack/scout.rb +342 -0
  33. data/lib/rhack/scout_squad.rb +98 -0
  34. data/lib/rhack/services.rb +1 -464
  35. data/lib/rhack/services/base.rb +59 -0
  36. data/lib/rhack/services/examples.rb +423 -0
  37. data/lib/rhack/version.rb +3 -0
  38. data/lib/rhack_in.rb +3 -2
  39. data/rhack.gemspec +28 -0
  40. metadata +104 -85
  41. data/.gemtest +0 -0
  42. data/Gemfile.lock +0 -23
  43. data/Manifest.txt +0 -60
  44. data/ext/curb/Makefile +0 -217
  45. data/lib/cache.rb +0 -44
  46. data/lib/curl-global.rb +0 -164
  47. data/lib/extensions/declarative.rb +0 -153
  48. data/lib/extensions/johnson.rb +0 -63
  49. data/lib/frame.rb +0 -848
  50. data/lib/init.rb +0 -49
  51. data/lib/rhack.yml.template +0 -19
  52. data/lib/scout.rb +0 -589
  53. data/lib/words.rb +0 -25
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ module RHACK
3
+
4
+ class Cookie
5
+ __init__
6
+
7
+ def initialize(*args)
8
+ if args[1].is Scout
9
+ str, scout = *args
10
+ ck = str//;\s*/
11
+ ck[1..-1].each {|par|
12
+ a = par/'='
13
+ case a[0].downcase
14
+ when 'path'; @path = (a[1] == '/') ? // : /^#{Regexp.escape a[1]}/
15
+ when 'domain'; @domain = /(^|\.)#{Regexp.escape a[1].sub(/^./, '')}$/
16
+ when 'expires'; @expires = a[1].to_time
17
+ end
18
+ }
19
+ @name, @value = ck[0].split('=', 2)
20
+ #@value.gsub!(/^['"]|['"]$/, '')
21
+ #L.debug args if !@domain
22
+ (scout.cookies[scout.uri.host] ||= {})[@name] = self
23
+ else
24
+ @name, cookie = args[0]
25
+ case cookie
26
+ when Array; @value, @path, @domain = cookie
27
+ when Hash; @value, @path, @domain = cookie.value, cookie.path, cookie.domain
28
+ else @value = args[1].to_s
29
+ end
30
+ end
31
+ @path ||= //
32
+ @domain ||= //
33
+ @string = "#{@name}=#{@value}; "
34
+ end
35
+
36
+ def use(str, uri)
37
+ if !@expires or @expires > Time.now
38
+ str << @string if uri.path[@path] and !uri.root || uri.host[@domain]
39
+ else
40
+ :expired
41
+ end
42
+ end
43
+
44
+ def to_s; @value end
45
+ def inspect; @value.inspect end
46
+
47
+ end
48
+
49
+ end
data/lib/rhack/curl.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'rhack/curl/easy'
2
+ require 'rhack/curl/multi'
3
+ require 'rhack/curl/post_field'
4
+ require 'rhack/curl/response'
5
+ require 'rhack/curl/global'
6
+ require 'rhack/curl/itt'
@@ -44,18 +44,22 @@ module Curl
44
44
  set :interface, value
45
45
  end
46
46
 
47
+ # <host>:<port>
47
48
  def url=(u)
48
49
  set :url, u
49
50
  end
50
51
 
52
+ # <host>:<port>
51
53
  def proxy_url=(url)
52
54
  set :proxy, url
53
55
  end
54
56
 
57
+ # <username>:<password>
55
58
  def userpwd=(value)
56
59
  set :userpwd, value
57
60
  end
58
61
 
62
+ # <username>:<password>
59
63
  def proxypwd=(value)
60
64
  set :proxyuserpwd, value
61
65
  end
@@ -65,59 +69,33 @@ module Curl
65
69
  end
66
70
 
67
71
  def head=(onoff)
68
- set :nobody, !!onoff
72
+ if onoff
73
+ set :httpget, false
74
+ set :customrequest, nil
75
+ set :nobody, true
76
+ else
77
+ set :nobody, false
78
+ end
69
79
  end
70
80
 
71
81
  def get=(onoff)
72
- set :httpget, !!onoff
73
- end
74
-
75
- end
76
-
77
- class PostField
78
-
79
- def to_s
80
- raise "Cannot convert unnamed field to string" if !name
81
- display_content = if (cp = content_proc)
82
- cp.inspect
83
- elsif (c = content)
84
- "#{c[0...20].inspect}#{"… (#{c.size.bytes})" if c.size > 20}"
85
- elsif (ln = local_name)
86
- File.new(ln).inspect
87
- end
88
- "#{name}=#{display_content}"
89
- end
90
-
91
- end
92
-
93
- class Multi
94
- if method_defined? :requests
95
- alias :reqs :requests
96
- end
97
-
98
- def reset
99
- reqs.each {|k| remove k rescue()}
100
- $Carier = Multi.new
101
- $Carier.pipeline = true
102
- # GC.start
103
- end
104
-
105
- def drop
106
- while running > 0 do perform rescue() end
107
- Curl.recall
108
- end
109
-
110
- def drop!
111
- drop
112
- reset if reqs.size + running > 0
113
- end
114
-
115
- def sheduled
116
- 0 < running and running <= reqs.size
82
+ if onoff
83
+ set :nobody, false
84
+ set :customrequest, nil
85
+ set :httpget, true
86
+ else
87
+ set :httpget, false
88
+ end
117
89
  end
118
90
 
119
- def inspect
120
- "<#Carier #{'unit'.x reqs.size}, #{running} executing>"
91
+ def delete=(onoff)
92
+ if onoff
93
+ set :nobody, false
94
+ set :httpget, false
95
+ set :customrequest, 'DELETE'
96
+ else
97
+ set :customrequest, nil
98
+ end
121
99
  end
122
100
 
123
101
  end
@@ -0,0 +1,175 @@
1
+ # encoding: utf-8
2
+ module Curl
3
+ class << Curl
4
+
5
+ def execute(unless_allready=false)
6
+ #if unless_allready and status
7
+ # return L.log "Carier allready executing"
8
+ #end
9
+ if @@carier_thread and s = @@carier_thread.status
10
+ L.log "Carier Thread allready started and has status #{s}"
11
+ else
12
+ if s = status(false) then L.warn s end
13
+ L.log(@@carier_thread ? "Resetting Carier thread" : "Setting Carier thread up")
14
+ @@carier_thread = thread {
15
+ error = nil
16
+ begin
17
+ yield if block_given?
18
+ rescue => error
19
+ nil
20
+ end
21
+ loop {
22
+ begin
23
+ # with true argument (idle) it would break only if there is no requests to perform
24
+ # and still carier thread is joined
25
+ break unless @@carier.perform true
26
+ L.log "All requests have been performed; idling..."
27
+ rescue => error
28
+ L.log "Catched #{error.class.name} in Carier Thread"
29
+ break
30
+ # but ruby mystically crashes if next sequence occur:
31
+ # Multi performs and can't see any requests so entering idle mode
32
+ # we add some requests and multi load them
33
+ # one of requests' callbacks raises error in *main* thread
34
+ # so we can't allow any raises here, instead, keep them in 'wait' section
35
+ end
36
+ } unless error
37
+ L.log "Nothing to perform; recalling..."
38
+ error
39
+ }
40
+ # until main thread has sleep a bit, $CarierThread will have status "run",
41
+ # no matter whether it's idling or performing requests
42
+ sleep 0.001
43
+ end
44
+ end
45
+ alias :run :execute
46
+
47
+ def wait
48
+ if @@carier_thread and @@carier_thread.status
49
+ unless within = Thread.current == @@carier_thread
50
+ # We can't set `perform' timeout lesser than 1 second in the curl binding
51
+ # because in that case thread status would always be "run"
52
+ # so here we wait for exactly 1 sec
53
+ sleep 1
54
+ end
55
+ # Also, if thread do Kernel.sleep, it would skip Curl.wait here
56
+ if !@@carier.sheduled and (@@carier_thread.status == 'sleep' or within && @@carier.reqs.empty?)
57
+ L.log "No shedule to wait"
58
+ else
59
+ this_thread = within ? 'it\'s thread' : Thread.main == Thread.current ? 'main thread' : 'thread '+Thread.current.object_id
60
+ L.log "Waiting for Carier to complete in #{this_thread}"
61
+ begin
62
+ L.log { "Trying to change Curl.joined #@@joined -> true from #{this_thread}" }
63
+ if within
64
+ L.log "calling this from one of callbacks to wait for the rest to complete"
65
+ begin
66
+ @@carier.perform
67
+ rescue RuntimeError => e
68
+ L.warn [e, e.message]
69
+ L.info "@@carier @@carier.sheduled @@carier_thread @@carier_thread.status", binding
70
+ L.warn "Failed to run Multi#perform: nothing to perform"
71
+ end
72
+ else
73
+ @@joined = true
74
+ @@carier_thread.join
75
+ end
76
+ rescue (defined?(IRB) ? IRB::Abort : NilClass)
77
+ recall!
78
+ L.info "Carier Thread recalled by a keyboard"
79
+ ensure
80
+ L.log "trying to change Curl.joined #@@joined -> false from #{this_thread}"
81
+ if !within
82
+ @@joined = false
83
+ # using Curl#execute from different threads may cause problems here when you don't control input,
84
+ # for example, in a daemonized ruby process
85
+ # just do not get $CarierThread joined from non-main thread
86
+ if @@carier_thread and e = @@carier_thread.value
87
+ # this will raise thread-safely in main thread
88
+ # in case of unrescued error in CarierThread
89
+ L.log(([e.message]+RMTools.format_trace(e.backtrace))*"\n")
90
+ recall!
91
+ raise e
92
+ end
93
+ execute
94
+ end
95
+ end
96
+ end
97
+ else
98
+ L < "No thread to wait. I guess I should create one"
99
+ execute
100
+ wait
101
+ end
102
+ end
103
+
104
+ def recall
105
+ L.debug caller
106
+ if @@carier_thread
107
+ L.log "Recalling Carier thread"
108
+ @@carier_thread.kill
109
+ sleep 1
110
+ else
111
+ L.log "No thread to recall"
112
+ end
113
+ end
114
+ alias :stop :recall
115
+
116
+ def recall!
117
+ if @@carier_thread
118
+ L.warn "Recalling thread and resetting Carier!!!"
119
+ @@carier_thread.kill
120
+ @@carier_thread = nil
121
+ reset_carier!
122
+ else
123
+ L.log "No thread to recall!"
124
+ end
125
+ end
126
+ alias :stop! :recall!
127
+
128
+ def reset_carier!
129
+ @@carier.clear!
130
+ @@carier = Multi.new
131
+ carier.pipeline = true
132
+ #GC.start
133
+ end
134
+
135
+ def reset
136
+ recall
137
+ execute
138
+ end
139
+ alias :reload :reset
140
+
141
+ def reset!
142
+ recall!
143
+ execute
144
+ end
145
+ alias :reload! :reset!
146
+
147
+ def status(raise_error=true)
148
+ if @@carier_thread and (s = @@carier_thread.status)
149
+ L.log "Carier Thread responding with status #{s}"
150
+ s
151
+ elsif @@carier_thread
152
+ begin
153
+ # status = nil
154
+ error = @@carier_thread.value
155
+ rescue => error
156
+ L.warn "Carier Thread has raised an exception"
157
+ if raise_error
158
+ recall!
159
+ raise error
160
+ else
161
+ L.log "Carier Thread has catched #{error.inspect}"
162
+ error
163
+ end
164
+ else
165
+ # status = false
166
+ L.log "Carier Thread has exited without an exception"
167
+ end
168
+ else
169
+ L.log "There is no Carier Thread atm"
170
+ end
171
+ end
172
+ alias :st :status
173
+
174
+ end\
175
+ end
@@ -0,0 +1,11 @@
1
+ module Curl
2
+
3
+ # Run proc in Multi's thread processing callbacks at this moment
4
+ def ITT
5
+ res = nil
6
+ RHACK::Scout('file://').loadGet(__FILE__) {|c| res = yield}
7
+ loop {if res then break res else sleep 0.01 end}
8
+ end
9
+ module_function :ITT
10
+
11
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ module Curl
3
+
4
+ class Multi
5
+ if method_defined? :requests
6
+ alias :reqs :requests
7
+ end
8
+
9
+ def sheduled
10
+ 0 < running and running <= reqs.size
11
+ end
12
+
13
+ def inspect
14
+ rsize = reqs.size
15
+ "<#Carier #{rsize} #{rsize == 1 ? 'unit' : 'units'}, #{running} executing>"
16
+ end
17
+
18
+
19
+ # Used for Curl.reset_carier!
20
+ def clear!
21
+ reqs.each {|k| remove k rescue()}
22
+ end
23
+
24
+ # Emergency debug methods, not used inside a framework
25
+ def drop
26
+ while running > 0 do perform rescue() end
27
+ Curl.recall
28
+ end
29
+
30
+ def drop!
31
+ drop
32
+ Curl.reset_carier! if reqs.size + running > 0
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ module Curl
3
+
4
+ class PostField
5
+
6
+ def to_s
7
+ raise "Cannot convert unnamed field to string" if !name
8
+ display_content = if (cp = content_proc)
9
+ cp.inspect
10
+ elsif (c = content)
11
+ "#{c[0...20].inspect}#{"… (#{c.size.bytes})" if c.size > 20}"
12
+ elsif (ln = local_name)
13
+ File.new(ln).inspect
14
+ end
15
+ "#{name}=#{display_content}"
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+ module Curl
3
+
4
+ class Response
5
+ __init__
6
+ attr_reader :header, :code, :body, :hash, :timestamp, :time, :req, :date, :error
7
+
8
+ def to_s
9
+ str = '<#'
10
+ if @error
11
+ str << "#{@error[0].self_name}: #{@error[1]}"
12
+ else
13
+ str << (@header[/\d{3}/] == @code.to_s ? @header : "#{@header[/\S+/]} #{@code}") if @header
14
+ if @hash.location
15
+ str << ' '+@req.url if $panic
16
+ str << ' -> '+@hash.location
17
+ end
18
+ str << " (#{@body ? @body.size.bytes : 'No'} Body)"
19
+ str << " [#{@timestamp}]" if @timestamp
20
+ end
21
+ str << '>'
22
+ end
23
+ alias :inspect :to_s
24
+
25
+ def initialize(easy)
26
+ @hash = {}
27
+ @timestamp = @date = @header = nil
28
+ if easy.base.error
29
+ @error = easy.base.error
30
+ else
31
+ if headers = easy.header_str || easy.base.headers
32
+ headers /= "\r\n"
33
+ @header = headers.shift
34
+ headers.each {|h|
35
+ h /= ': '
36
+ if h[0]
37
+ h[0].downcase!
38
+ if h[0] == 'set-cookie'
39
+ (@hash.cookies ||= []) << h[1]
40
+ else
41
+ @hash[h[0]] = h[1]
42
+ end
43
+ end
44
+ }
45
+ @timestamp = if @hash.date
46
+ begin
47
+ @date = @hash.date.to_time
48
+ rescue => e
49
+ (@date = Time.now).strftime("%H:%M:%S")
50
+ L < "Error #{e.class}:#{e.message} with @hash.date = #{@hash.date.inspect}"
51
+ end
52
+ @hash.date[/\d\d:\d\d:\d\d/]
53
+ else
54
+ (@date = Time.now).strftime("%H:%M:%S")
55
+ end
56
+ end
57
+ @code = easy.response_code
58
+ @body = easy.body_str.dup
59
+ @time = easy.total_time
60
+ end
61
+
62
+ @req = {}
63
+ @req.url = easy.last_effective_url
64
+ @req.headers = easy.headers
65
+ if range = easy.headers.Range and range[/(\d+)-(\d+)/]
66
+ @req.range = $1.to_i .. $2.to_i
67
+ end
68
+ if easy.base and @req.meth = easy.base.last_method and @req.meth.in [:post, :put]
69
+ @req.body = easy.post_body.dup
70
+ if @req.meth == :post
71
+ @req.mp = easy.multipart_form_post?
72
+ end
73
+ end
74
+ end
75
+
76
+ def is(klass)
77
+ if @error
78
+ klass == Array || klass = Curl::Response
79
+ else
80
+ klass == Curl::Response
81
+ end
82
+ end
83
+
84
+ def [](key_or_index)
85
+ @error ? @error[key_or_index] : @hash[key_or_index.downcase]
86
+ end
87
+
88
+ alias :headers :hash
89
+ end
90
+
91
+ end