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,42 @@
|
|
|
1
|
+
require 'ipaddr'
|
|
2
|
+
require 'raptor-io/ruby/ipaddr'
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# A logical switch board route.
|
|
6
|
+
#
|
|
7
|
+
class RaptorIO::Socket::SwitchBoard::Route
|
|
8
|
+
include Comparable
|
|
9
|
+
|
|
10
|
+
# @param subnet [String,IPAddr] The network associated with this
|
|
11
|
+
# route. If specified as a String, must be parseable by IPAddr.new
|
|
12
|
+
# @param netmask [String,IPAddr] `subnet`'s netmask. If specified as
|
|
13
|
+
# a String, must be parseable by IPAddr.new
|
|
14
|
+
# @param comm [Comm] The endpoint where sockets for this route
|
|
15
|
+
# should be created.
|
|
16
|
+
def initialize(subnet, netmask, comm)
|
|
17
|
+
self.netmask = IPAddr.parse(netmask)
|
|
18
|
+
self.subnet = IPAddr.parse(subnet).mask netmask.to_s
|
|
19
|
+
self.comm = comm
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# For direct equality, make sure all the attributes are the same
|
|
24
|
+
#
|
|
25
|
+
def ==(other)
|
|
26
|
+
return false unless other.kind_of? RaptorIO::Socket::SwitchBoard::Route
|
|
27
|
+
netmask == other.netmask && subnet == other.subnet && comm == other.comm
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# For comparison, sort according to netmask.
|
|
32
|
+
#
|
|
33
|
+
# This allows {Route routes} to be ordered by specificity
|
|
34
|
+
#
|
|
35
|
+
def <=>(other)
|
|
36
|
+
netmask <=> other.netmask
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :subnet, :netmask, :comm
|
|
40
|
+
protected
|
|
41
|
+
attr_writer :subnet, :netmask, :comm
|
|
42
|
+
end
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# TCP client socket
|
|
2
|
+
class RaptorIO::Socket::TCP < RaptorIO::Socket
|
|
3
|
+
|
|
4
|
+
# Default configuration options.
|
|
5
|
+
DEFAULT_OPTIONS = {
|
|
6
|
+
connect_timeout: 5,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
# Default options for SSL streams connected through this socket.
|
|
10
|
+
#
|
|
11
|
+
# @see #to_ssl
|
|
12
|
+
# @see TCP::SSL
|
|
13
|
+
DEFAULT_SSL_OPTIONS = {
|
|
14
|
+
ssl_version: :TLSv1,
|
|
15
|
+
ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# @!attribute socket
|
|
19
|
+
# The underlying IO for this socket. Usually this is the
|
|
20
|
+
# `socket` passed to {#initialize}
|
|
21
|
+
# @return [IO]
|
|
22
|
+
attr_accessor :socket
|
|
23
|
+
|
|
24
|
+
# @param (see Socket#initialize)
|
|
25
|
+
def initialize(socket, options = {})
|
|
26
|
+
options = DEFAULT_OPTIONS.merge(options)
|
|
27
|
+
super
|
|
28
|
+
@plaintext_socket = @socket = socket
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @!method getpeername(string)
|
|
32
|
+
# Return a Sockaddr struct for the *socket*. Note that this is the
|
|
33
|
+
# @return [String] Sockaddr data.
|
|
34
|
+
def_delegator :@plaintext_socket, :getpeername, :getpeername
|
|
35
|
+
|
|
36
|
+
# @!method ungetc
|
|
37
|
+
# Pushes back one character onto the {#socket}'s read buffer. Note
|
|
38
|
+
# that some streams will *lose data* if this is called with a
|
|
39
|
+
# `string` larger than one byte or called more than once between
|
|
40
|
+
# calls to {#read}!
|
|
41
|
+
#
|
|
42
|
+
# @param string [String] A single-byte string
|
|
43
|
+
# @return [nil]
|
|
44
|
+
def_delegator :@socket, :ungetc, :ungetc
|
|
45
|
+
|
|
46
|
+
def remote_address
|
|
47
|
+
::Addrinfo.new([ "AF_INET", options[:peer_port], options[:peer_host], options[:peer_host] ])
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Write `data` to the {#socket}.
|
|
51
|
+
#
|
|
52
|
+
# @param data [String,#to_s]
|
|
53
|
+
# @return [Fixnum]
|
|
54
|
+
def write(data)
|
|
55
|
+
begin
|
|
56
|
+
write_nonblock(data)
|
|
57
|
+
rescue IO::WaitWritable
|
|
58
|
+
IO.select(nil, [@socket])
|
|
59
|
+
retry
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Try to write `data` to the {#socket}.
|
|
64
|
+
#
|
|
65
|
+
# @param maxlen [Fixnum]
|
|
66
|
+
# @return [String]
|
|
67
|
+
def write_nonblock(data)
|
|
68
|
+
translate_errors do
|
|
69
|
+
@socket.write_nonblock(data)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Read exactly `maxlen` bytes from the {#socket}. If fewer than
|
|
74
|
+
# `maxlen` bytes are available for reading, wait until enough data
|
|
75
|
+
# is sent.
|
|
76
|
+
#
|
|
77
|
+
# @note May block
|
|
78
|
+
#
|
|
79
|
+
# @param (see #read_nonblock)
|
|
80
|
+
# @return (see #read_nonblock)
|
|
81
|
+
def read(maxlen)
|
|
82
|
+
buf = ""
|
|
83
|
+
until 0 == maxlen
|
|
84
|
+
prev_length = buf.length
|
|
85
|
+
buf << readpartial(maxlen)
|
|
86
|
+
maxlen -= buf.length - prev_length
|
|
87
|
+
end
|
|
88
|
+
buf
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Read at most `maxlen` bytes from the {#socket}.
|
|
92
|
+
#
|
|
93
|
+
# @note May block
|
|
94
|
+
#
|
|
95
|
+
# @param (see #read_nonblock)
|
|
96
|
+
# @return (see #read_nonblock)
|
|
97
|
+
def readpartial(maxlen = nil)
|
|
98
|
+
begin
|
|
99
|
+
read_nonblock(maxlen)
|
|
100
|
+
rescue IO::WaitReadable
|
|
101
|
+
IO.select([@socket])
|
|
102
|
+
retry
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Read at most `maxlen` bytes from the {#socket}.
|
|
107
|
+
#
|
|
108
|
+
# @param maxlen [Fixnum]
|
|
109
|
+
# @return [String]
|
|
110
|
+
def read_nonblock(maxlen = nil)
|
|
111
|
+
translate_errors do
|
|
112
|
+
@socket.read_nonblock(maxlen)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Ruby `Socket#gets` accepts:
|
|
117
|
+
#
|
|
118
|
+
# * `gets( sep = $/ )`
|
|
119
|
+
# * `gets( limit = nil )`
|
|
120
|
+
# * `gets( sep = $/, limit = nil )`
|
|
121
|
+
#
|
|
122
|
+
# `OpenSSL::SSL::SSLSocket#gets` however only supports `gets(sep=$/, limit=nil)`.
|
|
123
|
+
# This hack allows SSLSocket to behave the same as Ruby Socket.
|
|
124
|
+
#
|
|
125
|
+
# @note May block
|
|
126
|
+
def gets(*args)
|
|
127
|
+
translate_errors do
|
|
128
|
+
if args.size == 1
|
|
129
|
+
arg = args.first
|
|
130
|
+
if arg.is_a?(Numeric)
|
|
131
|
+
@socket.gets($/, arg)
|
|
132
|
+
else
|
|
133
|
+
@socket.gets(arg)
|
|
134
|
+
end
|
|
135
|
+
else
|
|
136
|
+
@socket.gets(*args)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Close this socket. If this socket is an SSL stream, closes both the
|
|
142
|
+
# SSL stream and the underlying socket
|
|
143
|
+
#
|
|
144
|
+
# @return [void]
|
|
145
|
+
def close
|
|
146
|
+
begin
|
|
147
|
+
super
|
|
148
|
+
ensure
|
|
149
|
+
if (!@plaintext_socket.closed?)
|
|
150
|
+
@plaintext_socket.close
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Attempt to turn this into something usable by `IO.select`.
|
|
156
|
+
#
|
|
157
|
+
# @return [IO]
|
|
158
|
+
def to_io
|
|
159
|
+
IO.try_convert(@socket) || @socket
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Whether this socket is encrypted with SSL
|
|
163
|
+
def ssl?
|
|
164
|
+
!!(@socket.respond_to?(:context) && @socket.context)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# The version of SSL/TLS that was negotiated with the server.
|
|
168
|
+
#
|
|
169
|
+
# @return [String] See OpenSSL::SSL::SSLSocket#ssl_version for
|
|
170
|
+
# possible values
|
|
171
|
+
# @return [nil] If this socket is not SSL
|
|
172
|
+
def ssl_version
|
|
173
|
+
return nil unless ssl?
|
|
174
|
+
@socket.ssl_version
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# @return [OpenSSL::SSL::SSLContext]
|
|
178
|
+
# @return [nil] If this socket is not SSL (see {#ssl?})
|
|
179
|
+
def ssl_context
|
|
180
|
+
return nil unless ssl?
|
|
181
|
+
@socket.context
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# @note The original socket is replaced by the newly connected
|
|
185
|
+
# {TCP::SSL} socket
|
|
186
|
+
#
|
|
187
|
+
# Starts an SSL/TLS stream over this connection.
|
|
188
|
+
#
|
|
189
|
+
# Using this as opposed to directly instantiating {TCP::SSL} allows
|
|
190
|
+
# you to start a TLS connection after data has already been exchanged
|
|
191
|
+
# to enable things like `STARTTLS`.
|
|
192
|
+
#
|
|
193
|
+
# @note May block
|
|
194
|
+
#
|
|
195
|
+
# @param ssl_options [Hash] Options
|
|
196
|
+
# @option ssl_options :ssl_version [Symbol] (:TLSv1)
|
|
197
|
+
# @option ssl_options :ssl_verify_mode [Constant] (OpenSSL::SSL::VERIFY_PEER)
|
|
198
|
+
# Peer verification mode.
|
|
199
|
+
# @option ssl_config :ssl_context [OpenSSL::SSL::SSLContext] (nil)
|
|
200
|
+
# SSL context to use.
|
|
201
|
+
#
|
|
202
|
+
# @return [RaptorIO::Socket::TCP::SSL] A new Socket with an established
|
|
203
|
+
# SSL connection
|
|
204
|
+
def to_ssl(ssl_options = {})
|
|
205
|
+
if ssl_options[:ssl_context]
|
|
206
|
+
options[:ssl_context] = ssl_options[:ssl_context]
|
|
207
|
+
else
|
|
208
|
+
ssl_options = DEFAULT_SSL_OPTIONS.merge(ssl_options)
|
|
209
|
+
options[:ssl_context] = OpenSSL::SSL::SSLContext.new.tap do |ctx|
|
|
210
|
+
ctx.ssl_version = ssl_options[:ssl_version]
|
|
211
|
+
ctx.verify_mode = ssl_options[:ssl_verify_mode]
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
s = RaptorIO::Socket::TCP::SSL.new(@plaintext_socket, options)
|
|
216
|
+
@socket = s
|
|
217
|
+
s
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
private
|
|
221
|
+
attr_accessor :plaintext_socket
|
|
222
|
+
|
|
223
|
+
def translate_errors(&block)
|
|
224
|
+
yield
|
|
225
|
+
rescue Errno::ECONNRESET, Errno::EPIPE
|
|
226
|
+
raise RaptorIO::Socket::Error::BrokenPipe
|
|
227
|
+
rescue Errno::ECONNREFUSED
|
|
228
|
+
raise RaptorIO::Socket::Error::ConnectionRefused
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
|
|
2
|
+
# TCP client with SSL encryption.
|
|
3
|
+
#
|
|
4
|
+
# @author Tasos Laskos <tasos_laskos@rapid7.com>
|
|
5
|
+
class RaptorIO::Socket::TCP::SSL < RaptorIO::Socket::TCP
|
|
6
|
+
|
|
7
|
+
# Create a new {SSL} from an already-connected
|
|
8
|
+
# `OpenSSL::SSL::SSLSocket`.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# tcp_server = ::TCPServer.new()
|
|
12
|
+
# ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server)
|
|
13
|
+
# RaptorIO::Socket::TCP::SSL.from_openssl(ssl_server.accept)
|
|
14
|
+
#
|
|
15
|
+
# @see TCPServer::SSL
|
|
16
|
+
# @param openssl_socket [OpenSSL::SSL::SSLSocket]
|
|
17
|
+
# @return [SSL]
|
|
18
|
+
def self.from_openssl(openssl_socket)
|
|
19
|
+
raptor = self.allocate
|
|
20
|
+
raptor.__send__(:socket=, openssl_socket)
|
|
21
|
+
raptor.__send__(:plaintext_socket=, openssl_socket.to_io)
|
|
22
|
+
raptor.options = {}
|
|
23
|
+
raptor.options[:ssl_context] = openssl_socket.context
|
|
24
|
+
|
|
25
|
+
raptor
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @!method ssl_context
|
|
29
|
+
# The SSL context for this encrypted stream.
|
|
30
|
+
#
|
|
31
|
+
# @return [OpenSSL::SSL::Context]
|
|
32
|
+
def_delegator :@socket, :ssl_context, :context
|
|
33
|
+
|
|
34
|
+
# @!method verify_mode
|
|
35
|
+
# @return [Fixnum] One of the `OpenSSL::SSL::VERIFY_*` constants
|
|
36
|
+
def_delegator :@socket, :ssl_verify_mode, :verify_mode
|
|
37
|
+
|
|
38
|
+
# @!method version
|
|
39
|
+
# @return [Symbol] SSL version.
|
|
40
|
+
def_delegator :@socket, :ssl_version, :version
|
|
41
|
+
|
|
42
|
+
# @param socket [RaptorIO::Socket]
|
|
43
|
+
# @param options [Hash] Options
|
|
44
|
+
# @option (see TCP#to_ssl)
|
|
45
|
+
def initialize( socket, options = {} )
|
|
46
|
+
options = DEFAULT_SSL_OPTIONS.merge( options )
|
|
47
|
+
super
|
|
48
|
+
|
|
49
|
+
@context = options[:context] || options[:ssl_context]
|
|
50
|
+
|
|
51
|
+
if @context.nil?
|
|
52
|
+
@context = OpenSSL::SSL::SSLContext.new( options[:ssl_version] )
|
|
53
|
+
@context.verify_mode = options[:ssl_verify_mode]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
@socket = OpenSSL::SSL::SSLSocket.new(socket.to_io, @context)
|
|
57
|
+
begin
|
|
58
|
+
#$stderr.puts("#{self.class}#initialize connecting")
|
|
59
|
+
@socket.connect_nonblock
|
|
60
|
+
rescue IO::WaitReadable, IO::WaitWritable => e
|
|
61
|
+
#$stderr.puts("Wait*able #{e}, #{options[:connect_timeout].inspect}")
|
|
62
|
+
if e.kind_of? IO::WaitReadable
|
|
63
|
+
r,w,_ = IO.select([@socket], nil, nil, options[:connect_timeout])
|
|
64
|
+
else
|
|
65
|
+
r,w,_ = IO.select(nil, [@socket], nil, options[:connect_timeout])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if r.nil? && w.nil?
|
|
69
|
+
#$stderr.puts("timeout")
|
|
70
|
+
raise RaptorIO::Socket::Error::ConnectionTimeout.new(e.to_s)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
retry
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# A listening TCP socket
|
|
2
|
+
class RaptorIO::Socket::TCPServer < RaptorIO::Socket
|
|
3
|
+
|
|
4
|
+
# @!method accept
|
|
5
|
+
def_delegator :@socket, :accept, :accept
|
|
6
|
+
|
|
7
|
+
# @!method accept_nonblock
|
|
8
|
+
def_delegator :@socket, :accept_nonblock, :accept_nonblock
|
|
9
|
+
|
|
10
|
+
# @!method bind
|
|
11
|
+
def_delegator :@socket, :bind, :bind
|
|
12
|
+
|
|
13
|
+
# @!method listen
|
|
14
|
+
def_delegator :@socket, :listen, :listen
|
|
15
|
+
|
|
16
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# TCP server with SSL encryption.
|
|
2
|
+
#
|
|
3
|
+
# @author Tasos Laskos <tasos_laskos@rapid7.com>
|
|
4
|
+
class RaptorIO::Socket::TCPServer::SSL < RaptorIO::Socket::TCPServer
|
|
5
|
+
|
|
6
|
+
def initialize( socket, options = {} )
|
|
7
|
+
#p options[:context].frozen?
|
|
8
|
+
super
|
|
9
|
+
#p options[:context].frozen?
|
|
10
|
+
|
|
11
|
+
@context = options[:context]
|
|
12
|
+
if @context.nil?
|
|
13
|
+
@context = OpenSSL::SSL::SSLContext.new( options[:ssl_version] )
|
|
14
|
+
@context.verify_mode = options[:verify_mode]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
@plaintext_socket = socket
|
|
18
|
+
@socket = OpenSSL::SSL::SSLServer.new( socket, @context )
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Accepts a client connection.
|
|
22
|
+
#
|
|
23
|
+
# @see Socket::TCP::SSL.from_openssl
|
|
24
|
+
# @return [RaptorIO::Socket::TCP::SSL]
|
|
25
|
+
def accept
|
|
26
|
+
RaptorIO::Socket::TCP::SSL.from_openssl(@socket.accept)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Accepts a client connection without blocking.
|
|
30
|
+
#
|
|
31
|
+
# @see Socket::TCP::SSL.from_openssl
|
|
32
|
+
# @return [RaptorIO::Socket::TCP::SSL]
|
|
33
|
+
# @raise [IO::WaitWritable]
|
|
34
|
+
def accept_nonblock
|
|
35
|
+
RaptorIO::Socket::TCP::SSL.from_openssl(@socket.accept_nonblock)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Close this SSL stream and the underlying socket
|
|
39
|
+
#
|
|
40
|
+
# @return [void]
|
|
41
|
+
def close
|
|
42
|
+
begin
|
|
43
|
+
@socket.close
|
|
44
|
+
ensure
|
|
45
|
+
if (!@plaintext_socket.closed?)
|
|
46
|
+
@plaintext_socket.close
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
end
|
|
File without changes
|
data/lib/tasks/yard.rake
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @note All options not specific to any given rake task should go in the .yardopts file so they are available to both
|
|
2
|
+
# the below rake tasks and when invoking `yard` from the command line
|
|
3
|
+
|
|
4
|
+
if defined? YARD
|
|
5
|
+
namespace :yard do
|
|
6
|
+
YARD::Rake::YardocTask.new(:doc) do |t|
|
|
7
|
+
# --no-stats here as 'stats' task called after will print fuller stats
|
|
8
|
+
t.options = ['--no-stats']
|
|
9
|
+
|
|
10
|
+
t.after = Proc.new {
|
|
11
|
+
Rake::Task['yard:stats'].execute
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc "Shows stats for YARD Documentation including listing undocumented modules, classes, constants, and methods"
|
|
16
|
+
task :stats => :environment do
|
|
17
|
+
stats = YARD::CLI::Stats.new
|
|
18
|
+
stats.run('--compact', '--list-undoc')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @todo Figure out how to just clone description from yard:doc
|
|
23
|
+
desc "Generate YARD documentation"
|
|
24
|
+
# allow calling namespace to as a task that goes to default task for namespace
|
|
25
|
+
task :yard => ['yard:doc']
|
|
26
|
+
end
|