raptor-io 0.0.1
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.
- checksums.yaml +15 -0
- data/LICENSE +30 -0
- data/README.md +51 -0
- data/lib/rack/handler/raptor-io.rb +130 -0
- data/lib/raptor-io.rb +11 -0
- data/lib/raptor-io/error.rb +19 -0
- data/lib/raptor-io/protocol.rb +6 -0
- data/lib/raptor-io/protocol/error.rb +10 -0
- data/lib/raptor-io/protocol/http.rb +34 -0
- data/lib/raptor-io/protocol/http/client.rb +685 -0
- data/lib/raptor-io/protocol/http/error.rb +16 -0
- data/lib/raptor-io/protocol/http/headers.rb +132 -0
- data/lib/raptor-io/protocol/http/message.rb +67 -0
- data/lib/raptor-io/protocol/http/request.rb +307 -0
- data/lib/raptor-io/protocol/http/request/manipulator.rb +117 -0
- data/lib/raptor-io/protocol/http/request/manipulators.rb +217 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticator.rb +110 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticators/basic.rb +36 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb +135 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticators/negotiate.rb +69 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticators/ntlm.rb +29 -0
- data/lib/raptor-io/protocol/http/request/manipulators/redirect_follower.rb +65 -0
- data/lib/raptor-io/protocol/http/response.rb +166 -0
- data/lib/raptor-io/protocol/http/server.rb +446 -0
- data/lib/raptor-io/ruby.rb +4 -0
- data/lib/raptor-io/ruby/hash.rb +24 -0
- data/lib/raptor-io/ruby/ipaddr.rb +15 -0
- data/lib/raptor-io/ruby/openssl.rb +23 -0
- data/lib/raptor-io/ruby/string.rb +27 -0
- data/lib/raptor-io/socket.rb +175 -0
- data/lib/raptor-io/socket/comm.rb +143 -0
- data/lib/raptor-io/socket/comm/local.rb +94 -0
- data/lib/raptor-io/socket/comm/sapni.rb +75 -0
- data/lib/raptor-io/socket/comm/socks.rb +237 -0
- data/lib/raptor-io/socket/comm_chain.rb +30 -0
- data/lib/raptor-io/socket/error.rb +45 -0
- data/lib/raptor-io/socket/switch_board.rb +183 -0
- data/lib/raptor-io/socket/switch_board/route.rb +42 -0
- data/lib/raptor-io/socket/tcp.rb +231 -0
- data/lib/raptor-io/socket/tcp/ssl.rb +77 -0
- data/lib/raptor-io/socket/tcp_server.rb +16 -0
- data/lib/raptor-io/socket/tcp_server/ssl.rb +52 -0
- data/lib/raptor-io/socket/udp.rb +0 -0
- data/lib/raptor-io/version.rb +6 -0
- data/lib/tasks/yard.rake +26 -0
- data/spec/rack/handler/raptor_spec.rb +140 -0
- data/spec/raptor-io/protocol/http/client_spec.rb +671 -0
- data/spec/raptor-io/protocol/http/headers_spec.rb +189 -0
- data/spec/raptor-io/protocol/http/message_spec.rb +5 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticator_spec.rb +193 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticators/basic_spec.rb +32 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticators/digest_spec.rb +76 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticators/negotiate_spec.rb +52 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticators/ntlm_spec.rb +37 -0
- data/spec/raptor-io/protocol/http/request/manipulators/redirect_follower_spec.rb +51 -0
- data/spec/raptor-io/protocol/http/request/manipulators_spec.rb +202 -0
- data/spec/raptor-io/protocol/http/request_spec.rb +965 -0
- data/spec/raptor-io/protocol/http/response_spec.rb +236 -0
- data/spec/raptor-io/protocol/http/server_spec.rb +345 -0
- data/spec/raptor-io/ruby/hash_spec.rb +20 -0
- data/spec/raptor-io/ruby/string_spec.rb +20 -0
- data/spec/raptor-io/socket/comm/local_spec.rb +50 -0
- data/spec/raptor-io/socket/switch_board/route_spec.rb +49 -0
- data/spec/raptor-io/socket/switch_board_spec.rb +87 -0
- data/spec/raptor-io/socket/tcp/ssl_spec.rb +18 -0
- data/spec/raptor-io/socket/tcp_server/ssl_spec.rb +59 -0
- data/spec/raptor-io/socket/tcp_server_spec.rb +19 -0
- data/spec/raptor-io/socket/tcp_spec.rb +14 -0
- data/spec/raptor-io/socket_spec.rb +16 -0
- data/spec/raptor-io/version_spec.rb +10 -0
- data/spec/spec_helper.rb +56 -0
- data/spec/support/fixtures/raptor/protocol/http/request/manipulators/manifoolators/fooer.rb +25 -0
- data/spec/support/fixtures/raptor/protocol/http/request/manipulators/niccolo_machiavelli.rb +20 -0
- data/spec/support/fixtures/raptor/protocol/http/request/manipulators/options_validator.rb +28 -0
- data/spec/support/fixtures/raptor/socket/ssl_server.crt +18 -0
- data/spec/support/fixtures/raptor/socket/ssl_server.key +15 -0
- data/spec/support/lib/path_helpers.rb +11 -0
- data/spec/support/lib/webserver_option_parser.rb +26 -0
- data/spec/support/lib/webservers.rb +120 -0
- data/spec/support/shared/contexts/with_ssl_server.rb +70 -0
- data/spec/support/shared/contexts/with_tcp_server.rb +58 -0
- data/spec/support/shared/examples/raptor/comm_examples.rb +26 -0
- data/spec/support/shared/examples/raptor/protocols/http/message.rb +106 -0
- data/spec/support/shared/examples/raptor/socket_examples.rb +135 -0
- data/spec/support/webservers/raptor/protocols/http/client.rb +100 -0
- data/spec/support/webservers/raptor/protocols/http/client_close_connection.rb +29 -0
- data/spec/support/webservers/raptor/protocols/http/client_https.rb +43 -0
- data/spec/support/webservers/raptor/protocols/http/request/manipulators/authenticators/basic.rb +9 -0
- data/spec/support/webservers/raptor/protocols/http/request/manipulators/authenticators/digest.rb +22 -0
- data/spec/support/webservers/raptor/protocols/http/request/manipulators/redirect_follower.rb +11 -0
- metadata +336 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module RaptorIO
|
|
2
|
+
module Protocol::HTTP
|
|
3
|
+
|
|
4
|
+
class Request
|
|
5
|
+
|
|
6
|
+
# Base manipulator class, all manipulator components should inherit from it.
|
|
7
|
+
#
|
|
8
|
+
# @author Tasos Laskos <tasos_laskos@rapid7.com>
|
|
9
|
+
# @abstract
|
|
10
|
+
class Manipulator
|
|
11
|
+
|
|
12
|
+
#
|
|
13
|
+
# {HTTP::Request::Manipulator} error namespace.
|
|
14
|
+
#
|
|
15
|
+
# All {HTTP::Request::Manipulator} errors inherit from and live under it.
|
|
16
|
+
#
|
|
17
|
+
# @author Tasos "Zapotek" Laskos
|
|
18
|
+
#
|
|
19
|
+
class Error < Request::Error
|
|
20
|
+
|
|
21
|
+
# Indicates invalid options for a manipulator.
|
|
22
|
+
#
|
|
23
|
+
# @author Tasos Laskos
|
|
24
|
+
class InvalidOptions < Error
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @return [HTTP::Client] Current HTTP client instance.
|
|
30
|
+
attr_reader :client
|
|
31
|
+
|
|
32
|
+
# @return [HTTP::Request] Request to manipulate.
|
|
33
|
+
attr_reader :request
|
|
34
|
+
|
|
35
|
+
# @return [Hash] Manipulator options.
|
|
36
|
+
attr_reader :options
|
|
37
|
+
|
|
38
|
+
# @param [HTTP::Client] client
|
|
39
|
+
# HTTP client which will handle the request.
|
|
40
|
+
# @param [HTTP::Request] request
|
|
41
|
+
# Request to process.
|
|
42
|
+
def initialize( client, request, options = {} )
|
|
43
|
+
@client = client
|
|
44
|
+
@request = request
|
|
45
|
+
@options = options
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Delivers the manipulator's payload.
|
|
49
|
+
# @abstract
|
|
50
|
+
def run
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Delegates the work to another manipulator.
|
|
54
|
+
#
|
|
55
|
+
# @param [Symbol] manipulator Manipulator to run.
|
|
56
|
+
# @param [Hash] opts Manipulator options.
|
|
57
|
+
def delegate( manipulator, opts = options )
|
|
58
|
+
Request::Manipulators.process( manipulator, client, request, opts )
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [Hash] Persistent storage -- per {HTTP::Client} instance.
|
|
62
|
+
def datastore
|
|
63
|
+
client.datastore[shortname]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [String] Shortname of `self`.
|
|
67
|
+
def shortname
|
|
68
|
+
self.class.shortname
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @return [Hash{Symbol=>Array<String>}]
|
|
72
|
+
# Option names keys for and error messages for values.
|
|
73
|
+
def validate_options
|
|
74
|
+
self.class.validate_options!( options, client )
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class <<self
|
|
78
|
+
|
|
79
|
+
# @return [Hash{Symbol=>Array<String>}]
|
|
80
|
+
# Option names keys for and error messages for values.
|
|
81
|
+
def validate_options( &block )
|
|
82
|
+
fail ArgumentError, 'Missing block.' if !block_given?
|
|
83
|
+
@validator = block
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
#
|
|
87
|
+
# @param [Hash] options Manipulator options.
|
|
88
|
+
# @param [HTTP::Client] client Applicable client.
|
|
89
|
+
#
|
|
90
|
+
# @return [Hash{Symbol=>Array<String>}]
|
|
91
|
+
# Option names keys for and error messages for values.
|
|
92
|
+
#
|
|
93
|
+
# @abstract
|
|
94
|
+
def validate_options!( options, client )
|
|
95
|
+
@validator ? @validator.call( options, client ) : {}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @return [String] Shortname of `self`.
|
|
99
|
+
def shortname
|
|
100
|
+
@shortname ||= Request::Manipulators.class_to_name( self )
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Registers manipulators which inherit from this class.
|
|
104
|
+
#
|
|
105
|
+
# @see Request::Manipulators#register
|
|
106
|
+
def inherited( manipulator_klass )
|
|
107
|
+
Request::Manipulators.register(
|
|
108
|
+
Request::Manipulators.path_to_name( caller.first.split( ':' ).first ),
|
|
109
|
+
manipulator_klass
|
|
110
|
+
)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
module RaptorIO
|
|
2
|
+
module Protocol::HTTP
|
|
3
|
+
|
|
4
|
+
class Request
|
|
5
|
+
|
|
6
|
+
require_relative 'manipulator'
|
|
7
|
+
|
|
8
|
+
# Namespace holding all Request manipulators and providing some helper methods
|
|
9
|
+
# for management.
|
|
10
|
+
#
|
|
11
|
+
# @author Tasos Laskos <tasos_laskos@rapid7.com>
|
|
12
|
+
module Manipulators
|
|
13
|
+
|
|
14
|
+
class <<self
|
|
15
|
+
include Enumerable
|
|
16
|
+
|
|
17
|
+
# @return [String] Directory of the manipulators' repository.
|
|
18
|
+
attr_reader :library
|
|
19
|
+
|
|
20
|
+
# @param [String] manipulator
|
|
21
|
+
# Manipulator to run -- will be loaded if needed.
|
|
22
|
+
# @param [HTTP::Client] client
|
|
23
|
+
# Applicable client.
|
|
24
|
+
# @param [HTTP::Request] request
|
|
25
|
+
# Request to process.
|
|
26
|
+
# @param [Hash] options
|
|
27
|
+
# Manipulator options.
|
|
28
|
+
def process( manipulator, client, request, options = {} )
|
|
29
|
+
load( manipulator ).new( client, request, options ).run
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Performs batch validation of manipulator options.
|
|
33
|
+
#
|
|
34
|
+
# @param [Hash{String=>Hash}] manipulators
|
|
35
|
+
# Manipulators for keys and their options as values.
|
|
36
|
+
# @param [HTTP::Client] client
|
|
37
|
+
# Applicable client.
|
|
38
|
+
#
|
|
39
|
+
# @return [Hash{String=>Hash}]
|
|
40
|
+
# Manipulators for keys and error hashes as values.
|
|
41
|
+
#
|
|
42
|
+
def validate_batch_options( manipulators, client )
|
|
43
|
+
errors = {}
|
|
44
|
+
manipulators.each do |manipulator, options|
|
|
45
|
+
errors[manipulator] =
|
|
46
|
+
validate_options( manipulator, options, client )
|
|
47
|
+
end
|
|
48
|
+
errors.reject { |_, errs| errs.empty? }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Same as {.validate_batch_options} but raises exception on errors.
|
|
52
|
+
def validate_batch_options!( manipulators, client )
|
|
53
|
+
errors = validate_batch_options( manipulators, client )
|
|
54
|
+
if errors.any?
|
|
55
|
+
fail Request::Manipulator::Error::InvalidOptions, errors.to_s
|
|
56
|
+
end
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @param [String] manipulator
|
|
61
|
+
# @param [Hash] options Manipulator options.
|
|
62
|
+
# @param [HTTP::Client] client Applicable client.
|
|
63
|
+
#
|
|
64
|
+
# @return [Hash{Symbol=>Array<String>}]
|
|
65
|
+
# Option names keys for and error messages for values.
|
|
66
|
+
def validate_options( manipulator, options, client )
|
|
67
|
+
load( manipulator ).validate_options!( options, client )
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @param [String] directory Directory including manipulators.
|
|
71
|
+
def library=( directory )
|
|
72
|
+
@library = File.expand_path( directory ) + '/'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [Array<String>] Paths of all manipulators.
|
|
76
|
+
def paths
|
|
77
|
+
Dir.glob( "#{library}**/*.rb" )
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @return [Array<Symbol>] Names of all manipulators.
|
|
81
|
+
def available
|
|
82
|
+
paths.map { |path| path_to_name path }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @param [Symbol] manipulator
|
|
86
|
+
# Loads a manipulator by name.
|
|
87
|
+
#
|
|
88
|
+
# @return [Class] Loaded manipulator.
|
|
89
|
+
def load( manipulator )
|
|
90
|
+
manipulator = normalize_name( manipulator )
|
|
91
|
+
return @manipulators[manipulator] if @manipulators.include? manipulator
|
|
92
|
+
|
|
93
|
+
Kernel.load name_to_path( manipulator )
|
|
94
|
+
@manipulators[manipulator]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Loads all manipulators.
|
|
98
|
+
#
|
|
99
|
+
# @return [Hash] All manipulators.
|
|
100
|
+
def load_all
|
|
101
|
+
paths.each { |path| load path_to_name( path ) }
|
|
102
|
+
loaded
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @param [Symbol] manipulator
|
|
106
|
+
# Unloads a manipulator by name.
|
|
107
|
+
#
|
|
108
|
+
# @return [Bool]
|
|
109
|
+
# `true` if the manipulator was unloaded successfully, `false` if no
|
|
110
|
+
# matching one was found.
|
|
111
|
+
def unload( manipulator )
|
|
112
|
+
klass = @manipulators.delete( normalize_name( manipulator ) )
|
|
113
|
+
return false if !klass
|
|
114
|
+
|
|
115
|
+
container = self
|
|
116
|
+
klass.to_s.gsub( "#{self}::", '' ).split( '::' )[0...-1].each do |c|
|
|
117
|
+
container = container.const_get( c.to_sym )
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
container.instance_eval do
|
|
121
|
+
remove_const klass.to_s.split( ':' ).last.to_sym
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Remove the container namespaces themselves if they're now empty.
|
|
125
|
+
container = self
|
|
126
|
+
klass.to_s.gsub( "#{self}::", '' ).split( '::' )[0...-1].each do |c|
|
|
127
|
+
container = container.const_get( c.to_sym )
|
|
128
|
+
if container != self && container.constants.empty?
|
|
129
|
+
remove_const container.to_s.split( ':' ).last.to_sym
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Unloads all manipulators.
|
|
137
|
+
def unload_all
|
|
138
|
+
@manipulators.keys.each { |manipulator| unload manipulator }
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @param [Block] block
|
|
143
|
+
# Block to be passed each manipulator name=>class.
|
|
144
|
+
# @return [Enumerator, Manipulators]
|
|
145
|
+
# `Enumerator` if no `block` is given, `self` otherwise.
|
|
146
|
+
def each( &block )
|
|
147
|
+
return enum_for( __method__ ) if !block_given?
|
|
148
|
+
@manipulators.each( &block )
|
|
149
|
+
self
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# @return [Hash] All manipulators as a frozen hash.
|
|
153
|
+
def loaded
|
|
154
|
+
@manipulators.dup.freeze
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Registers a manipulator.
|
|
158
|
+
#
|
|
159
|
+
# @param [Symbol] name
|
|
160
|
+
# @param [Base] klass
|
|
161
|
+
#
|
|
162
|
+
# @return [Manipulator] `self`
|
|
163
|
+
#
|
|
164
|
+
# @private
|
|
165
|
+
def register( name, klass )
|
|
166
|
+
@manipulators[normalize_name( name )] = klass
|
|
167
|
+
self
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Resets the manipulators by unloading all and settings the {#library} to
|
|
171
|
+
# its default setting.
|
|
172
|
+
def reset
|
|
173
|
+
unload_all if @manipulators
|
|
174
|
+
|
|
175
|
+
@library = File.expand_path( File.dirname( __FILE__ ) + '/manipulators' ) + '/'
|
|
176
|
+
@manipulators = {}
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# @param [String] name Manipulator name.
|
|
180
|
+
# @return [Bool] `true` if the given manipulator exists, `false` otherwise.
|
|
181
|
+
def exist?( name )
|
|
182
|
+
File.exist? name_to_path( name )
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# @param [String] path FS path to a manipulator.
|
|
186
|
+
# @return [String] Manipulator shortname.
|
|
187
|
+
def path_to_name( path )
|
|
188
|
+
normalize_name path.gsub( library, '' ).gsub( /(.+)\.rb$/, '\1' )
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# @param [Class] klass Manipulator class.
|
|
192
|
+
# @return [String, nil]
|
|
193
|
+
# Manipulator shortname, `nil` if the manipulator isn't loaded.
|
|
194
|
+
def class_to_name( klass )
|
|
195
|
+
@manipulators.select { |name, k| return name if k == klass }
|
|
196
|
+
nil
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# @param [String] name Manipulator shortname.
|
|
200
|
+
# @return [String] Manipulator FS path.
|
|
201
|
+
def name_to_path( name )
|
|
202
|
+
File.expand_path "#{library}/#{name}.rb"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# @param [String, Symbol] name Manipulator name.
|
|
206
|
+
# @return [String] Manipulator name.
|
|
207
|
+
def normalize_name( name )
|
|
208
|
+
name.to_s
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
reset
|
|
213
|
+
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
module RaptorIO
|
|
2
|
+
module Protocol::HTTP
|
|
3
|
+
class Request
|
|
4
|
+
|
|
5
|
+
module Manipulators
|
|
6
|
+
|
|
7
|
+
# Namespace for all authenticator manipulators.
|
|
8
|
+
module Authenticators
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# Implements automatic HTTP authentication.
|
|
13
|
+
#
|
|
14
|
+
# @author Tasos Laskos
|
|
15
|
+
#
|
|
16
|
+
class Authenticator < Manipulator
|
|
17
|
+
|
|
18
|
+
validate_options do |options, _|
|
|
19
|
+
errors = {}
|
|
20
|
+
next errors if options[:skip]
|
|
21
|
+
|
|
22
|
+
[:username, :password].each do |option|
|
|
23
|
+
errors[option] = [ "Can't be blank." ] if options[option].to_s.empty?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
errors
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def run
|
|
30
|
+
datastore[:tries] ||= 0
|
|
31
|
+
return if skip?
|
|
32
|
+
|
|
33
|
+
callbacks = request.callbacks.dup
|
|
34
|
+
request.clear_callbacks
|
|
35
|
+
|
|
36
|
+
# We need to block until authentication is complete, that's why we requeue
|
|
37
|
+
# and run.
|
|
38
|
+
|
|
39
|
+
requeue
|
|
40
|
+
request.on_complete do |response|
|
|
41
|
+
auth_type = type( response )
|
|
42
|
+
|
|
43
|
+
if !failed? && response.code == 401 && supported?( auth_type )
|
|
44
|
+
retry_with_auth( auth_type, response )
|
|
45
|
+
else
|
|
46
|
+
request.callbacks = callbacks
|
|
47
|
+
request.handle_response response
|
|
48
|
+
request.clear_callbacks
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
client.run
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
# @note Set by one of the authenticators, not `self`.
|
|
57
|
+
# @return [Bool] `true` if authentication failed, `false` otherwise.
|
|
58
|
+
def failed?
|
|
59
|
+
!!datastore[:failed]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Retries the request with authentication.
|
|
63
|
+
#
|
|
64
|
+
# @param [Symbol] type Authenticator to use.
|
|
65
|
+
# @param [RaptorIO::Protocol::HTTP::Response] response
|
|
66
|
+
# Response signaling the need to authenticate.
|
|
67
|
+
def retry_with_auth( type, response )
|
|
68
|
+
datastore[:tries] += 1
|
|
69
|
+
|
|
70
|
+
remove_client_authenticators if ![:ntlm, :negotiate].include?( type )
|
|
71
|
+
client.manipulators.merge!({
|
|
72
|
+
"authenticators/#{type}" => options.merge( response: response )
|
|
73
|
+
})
|
|
74
|
+
requeue
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Requeues the request after the proper authenticator has been enabled.
|
|
78
|
+
def requeue
|
|
79
|
+
client.queue( request, shortname => { skip: true } )
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @param [RaptorIO::Protocol::HTTP::Response] response
|
|
83
|
+
# Response signaling the need to authenticate.
|
|
84
|
+
# @return [Symbol] Authentication type.
|
|
85
|
+
def type( response )
|
|
86
|
+
response.headers['www-authenticate'].to_s.split( ' ' ).first.to_s.downcase.to_s.to_sym
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def skip?
|
|
90
|
+
failed? || !!options[:skip]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @param [Symbol] type Authentication type to check.
|
|
94
|
+
# @return [Bool]
|
|
95
|
+
# `true` if the authentication `type` is supported, `false` otherwise.
|
|
96
|
+
def supported?( type )
|
|
97
|
+
Request::Manipulators.exist? "authenticators/#{type}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Removes all enabled authenticators.
|
|
101
|
+
def remove_client_authenticators
|
|
102
|
+
client.manipulators.reject!{ |k, _| k.start_with? 'authenticator' }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module RaptorIO
|
|
2
|
+
module Protocol::HTTP
|
|
3
|
+
class Request
|
|
4
|
+
|
|
5
|
+
module Manipulators
|
|
6
|
+
module Authenticators
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# Implements HTTP Basic authentication.
|
|
10
|
+
#
|
|
11
|
+
# @author Tasos Laskos
|
|
12
|
+
#
|
|
13
|
+
class Basic < Manipulator
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
request.headers['Authorization'] =
|
|
17
|
+
"Basic #{Base64.encode64("#{username}:#{password}").chomp}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def username
|
|
23
|
+
options[:username]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def password
|
|
27
|
+
options[:password]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|