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.
Files changed (91) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +30 -0
  3. data/README.md +51 -0
  4. data/lib/rack/handler/raptor-io.rb +130 -0
  5. data/lib/raptor-io.rb +11 -0
  6. data/lib/raptor-io/error.rb +19 -0
  7. data/lib/raptor-io/protocol.rb +6 -0
  8. data/lib/raptor-io/protocol/error.rb +10 -0
  9. data/lib/raptor-io/protocol/http.rb +34 -0
  10. data/lib/raptor-io/protocol/http/client.rb +685 -0
  11. data/lib/raptor-io/protocol/http/error.rb +16 -0
  12. data/lib/raptor-io/protocol/http/headers.rb +132 -0
  13. data/lib/raptor-io/protocol/http/message.rb +67 -0
  14. data/lib/raptor-io/protocol/http/request.rb +307 -0
  15. data/lib/raptor-io/protocol/http/request/manipulator.rb +117 -0
  16. data/lib/raptor-io/protocol/http/request/manipulators.rb +217 -0
  17. data/lib/raptor-io/protocol/http/request/manipulators/authenticator.rb +110 -0
  18. data/lib/raptor-io/protocol/http/request/manipulators/authenticators/basic.rb +36 -0
  19. data/lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb +135 -0
  20. data/lib/raptor-io/protocol/http/request/manipulators/authenticators/negotiate.rb +69 -0
  21. data/lib/raptor-io/protocol/http/request/manipulators/authenticators/ntlm.rb +29 -0
  22. data/lib/raptor-io/protocol/http/request/manipulators/redirect_follower.rb +65 -0
  23. data/lib/raptor-io/protocol/http/response.rb +166 -0
  24. data/lib/raptor-io/protocol/http/server.rb +446 -0
  25. data/lib/raptor-io/ruby.rb +4 -0
  26. data/lib/raptor-io/ruby/hash.rb +24 -0
  27. data/lib/raptor-io/ruby/ipaddr.rb +15 -0
  28. data/lib/raptor-io/ruby/openssl.rb +23 -0
  29. data/lib/raptor-io/ruby/string.rb +27 -0
  30. data/lib/raptor-io/socket.rb +175 -0
  31. data/lib/raptor-io/socket/comm.rb +143 -0
  32. data/lib/raptor-io/socket/comm/local.rb +94 -0
  33. data/lib/raptor-io/socket/comm/sapni.rb +75 -0
  34. data/lib/raptor-io/socket/comm/socks.rb +237 -0
  35. data/lib/raptor-io/socket/comm_chain.rb +30 -0
  36. data/lib/raptor-io/socket/error.rb +45 -0
  37. data/lib/raptor-io/socket/switch_board.rb +183 -0
  38. data/lib/raptor-io/socket/switch_board/route.rb +42 -0
  39. data/lib/raptor-io/socket/tcp.rb +231 -0
  40. data/lib/raptor-io/socket/tcp/ssl.rb +77 -0
  41. data/lib/raptor-io/socket/tcp_server.rb +16 -0
  42. data/lib/raptor-io/socket/tcp_server/ssl.rb +52 -0
  43. data/lib/raptor-io/socket/udp.rb +0 -0
  44. data/lib/raptor-io/version.rb +6 -0
  45. data/lib/tasks/yard.rake +26 -0
  46. data/spec/rack/handler/raptor_spec.rb +140 -0
  47. data/spec/raptor-io/protocol/http/client_spec.rb +671 -0
  48. data/spec/raptor-io/protocol/http/headers_spec.rb +189 -0
  49. data/spec/raptor-io/protocol/http/message_spec.rb +5 -0
  50. data/spec/raptor-io/protocol/http/request/manipulators/authenticator_spec.rb +193 -0
  51. data/spec/raptor-io/protocol/http/request/manipulators/authenticators/basic_spec.rb +32 -0
  52. data/spec/raptor-io/protocol/http/request/manipulators/authenticators/digest_spec.rb +76 -0
  53. data/spec/raptor-io/protocol/http/request/manipulators/authenticators/negotiate_spec.rb +52 -0
  54. data/spec/raptor-io/protocol/http/request/manipulators/authenticators/ntlm_spec.rb +37 -0
  55. data/spec/raptor-io/protocol/http/request/manipulators/redirect_follower_spec.rb +51 -0
  56. data/spec/raptor-io/protocol/http/request/manipulators_spec.rb +202 -0
  57. data/spec/raptor-io/protocol/http/request_spec.rb +965 -0
  58. data/spec/raptor-io/protocol/http/response_spec.rb +236 -0
  59. data/spec/raptor-io/protocol/http/server_spec.rb +345 -0
  60. data/spec/raptor-io/ruby/hash_spec.rb +20 -0
  61. data/spec/raptor-io/ruby/string_spec.rb +20 -0
  62. data/spec/raptor-io/socket/comm/local_spec.rb +50 -0
  63. data/spec/raptor-io/socket/switch_board/route_spec.rb +49 -0
  64. data/spec/raptor-io/socket/switch_board_spec.rb +87 -0
  65. data/spec/raptor-io/socket/tcp/ssl_spec.rb +18 -0
  66. data/spec/raptor-io/socket/tcp_server/ssl_spec.rb +59 -0
  67. data/spec/raptor-io/socket/tcp_server_spec.rb +19 -0
  68. data/spec/raptor-io/socket/tcp_spec.rb +14 -0
  69. data/spec/raptor-io/socket_spec.rb +16 -0
  70. data/spec/raptor-io/version_spec.rb +10 -0
  71. data/spec/spec_helper.rb +56 -0
  72. data/spec/support/fixtures/raptor/protocol/http/request/manipulators/manifoolators/fooer.rb +25 -0
  73. data/spec/support/fixtures/raptor/protocol/http/request/manipulators/niccolo_machiavelli.rb +20 -0
  74. data/spec/support/fixtures/raptor/protocol/http/request/manipulators/options_validator.rb +28 -0
  75. data/spec/support/fixtures/raptor/socket/ssl_server.crt +18 -0
  76. data/spec/support/fixtures/raptor/socket/ssl_server.key +15 -0
  77. data/spec/support/lib/path_helpers.rb +11 -0
  78. data/spec/support/lib/webserver_option_parser.rb +26 -0
  79. data/spec/support/lib/webservers.rb +120 -0
  80. data/spec/support/shared/contexts/with_ssl_server.rb +70 -0
  81. data/spec/support/shared/contexts/with_tcp_server.rb +58 -0
  82. data/spec/support/shared/examples/raptor/comm_examples.rb +26 -0
  83. data/spec/support/shared/examples/raptor/protocols/http/message.rb +106 -0
  84. data/spec/support/shared/examples/raptor/socket_examples.rb +135 -0
  85. data/spec/support/webservers/raptor/protocols/http/client.rb +100 -0
  86. data/spec/support/webservers/raptor/protocols/http/client_close_connection.rb +29 -0
  87. data/spec/support/webservers/raptor/protocols/http/client_https.rb +43 -0
  88. data/spec/support/webservers/raptor/protocols/http/request/manipulators/authenticators/basic.rb +9 -0
  89. data/spec/support/webservers/raptor/protocols/http/request/manipulators/authenticators/digest.rb +22 -0
  90. data/spec/support/webservers/raptor/protocols/http/request/manipulators/redirect_follower.rb +11 -0
  91. metadata +336 -0
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash do
4
+ describe '#stringify' do
5
+ it 'returns a Hash with keys and values recursively converted to strings' do
6
+ {
7
+ test: 'blah',
8
+ another_hash: {
9
+ stuff: 'test'
10
+ }
11
+ }.stringify.should == {
12
+ 'test' => 'blah',
13
+ 'another_hash' => {
14
+ 'stuff' => 'test'
15
+ }
16
+ }
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe String do
4
+
5
+ describe '#binary?' do
6
+ context 'when the content is' do
7
+ context 'binary' do
8
+ it 'returns true' do
9
+ "\ff\ff\ff".binary?.should be_true
10
+ end
11
+ end
12
+ context 'text' do
13
+ it 'returns false' do
14
+ 'test'.binary?.should be_false
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ require 'raptor-io/socket'
4
+
5
+ describe RaptorIO::Socket::Comm::Local do
6
+ subject(:comm_local) { described_class.new }
7
+
8
+ context "with a server to connect to" do
9
+ let(:tcp_port) { 9999 }
10
+ let(:udp_port) { 9090 }
11
+ before do
12
+ @tcp_server = ::TCPServer.new(tcp_port)
13
+ end
14
+ after do
15
+ @tcp_server.close
16
+ end
17
+
18
+ subject(:comm) { described_class.new }
19
+ it_behaves_like "a comm"
20
+ end
21
+
22
+ describe '#resolve' do
23
+ it 'should resolve a hostname to an IP address' do
24
+ # OSX uses a link-local address on the loopback interface
25
+ # (fe80::1%lo0) to be 'localhost'
26
+ ['127.0.0.1', '::1', 'fe80::1%lo0'].should include(comm_local.resolve('localhost'))
27
+ end
28
+ end
29
+
30
+ describe "#support_ipv6?" do
31
+ # These are ghetto tests. It assumes the implementation for
32
+ # determining support.
33
+ it "should be true if we can create ipv6 sockets" do
34
+ socket_inst = double("sock")
35
+ socket_inst.stub(:close)
36
+
37
+ ::Socket.should_receive(:new).with(::Socket::AF_INET6, ::Socket::SOCK_DGRAM, ::Socket::IPPROTO_UDP).and_return(socket_inst)
38
+ comm_local.support_ipv6?.should be_true
39
+ end
40
+ it "should be false if ::Socket::AF_INET6 is not defined" do
41
+ ::Socket.should_receive(:const_defined?).and_return(false)
42
+ comm_local.support_ipv6?.should be_false
43
+ end
44
+ it "should be false if we cannot create ipv6 sockets" do
45
+ ::Socket.should_receive(:new).and_raise(RuntimeError)
46
+ comm_local.support_ipv6?.should be_false
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ require 'raptor-io/socket'
4
+
5
+ describe RaptorIO::Socket::SwitchBoard::Route do
6
+
7
+ context "class methods" do
8
+ describe ".new" do
9
+ it "should accept an IPAddr for subnet and netmask" do
10
+ expect {
11
+ described_class.new(IPAddr.new("1.2.3.4"), IPAddr.new("255.255.0.0"), nil)
12
+ }.not_to raise_error
13
+ end
14
+ it "should accept a String for subnet and netmask" do
15
+ expect {
16
+ described_class.new("1.2.3.4", "255.255.0.0", nil)
17
+ }.not_to raise_error
18
+ end
19
+ end
20
+ end
21
+
22
+ context "instance methods" do
23
+ subject(:route) do
24
+ RaptorIO::Socket::SwitchBoard::Route.new("1.2.3.4", "255.255.255.0", nil)
25
+ end
26
+
27
+ describe "#==" do
28
+ it "should be equal if attributes are the same" do
29
+ RaptorIO::Socket::SwitchBoard::Route.new("1.2.3.4", "255.255.255.0", nil).should == route
30
+ end
31
+ it "should NOT be equal if any attributes are different" do
32
+ RaptorIO::Socket::SwitchBoard::Route.new("1.2.3.4", "255.0.0.0", nil).should_not == route
33
+ RaptorIO::Socket::SwitchBoard::Route.new("2.2.3.4", "255.255.255.0", nil).should_not == route
34
+ end
35
+ end
36
+
37
+ describe "#<=>" do
38
+ it "should compare the subnet" do
39
+ other = RaptorIO::Socket::SwitchBoard::Route.new("0.0.0.0", "255.255.0.0", nil)
40
+ (route.<=> other).should == 1
41
+ other = RaptorIO::Socket::SwitchBoard::Route.new("0.0.0.0", "255.255.255.0", nil)
42
+ (route.<=> other).should == 0
43
+ other = RaptorIO::Socket::SwitchBoard::Route.new("0.0.0.0", "255.255.255.255", nil)
44
+ (route.<=> other).should == -1
45
+ end
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ require 'raptor-io/socket'
4
+
5
+ describe RaptorIO::Socket::SwitchBoard do
6
+ subject(:switch_board) do
7
+ described_class.new
8
+ end
9
+
10
+ it { should be_an Enumerable }
11
+
12
+ describe "#add_route" do
13
+ it "should add a route" do
14
+ switch_board.routes.should be_empty
15
+ switch_board.add_route("1.2.3.4", "255.255.255.0", nil)
16
+ switch_board.routes.length.should == 1
17
+ end
18
+ it "should accept IPAddrs" do
19
+ switch_board.routes.should be_empty
20
+ switch_board.add_route(IPAddr.new("1.2.3.4"), IPAddr.new("255.255.255.0"), nil)
21
+ switch_board.routes.length.should == 1
22
+ end
23
+ end
24
+
25
+ describe "#each" do
26
+ subject(:switch_board) do
27
+ sb = described_class.new
28
+ 4.times do |i|
29
+ sb.add_route("#{i}.2.3.4", "255.255.255.0", nil)
30
+ end
31
+ sb
32
+ end
33
+
34
+ it "should return all routes" do
35
+ routes = []
36
+ switch_board.each do |r|
37
+ routes << r
38
+ end
39
+ routes.length.should == 4
40
+ routes.should == switch_board.routes
41
+ end
42
+ end
43
+
44
+ describe "#flush_routes" do
45
+ it "should empty the routes" do
46
+ switch_board.routes.should be_empty
47
+ switch_board.add_route("1.1.1.1", "255.255.255.0", nil)
48
+ switch_board.add_route("2.2.2.2", "255.255.255.0", nil)
49
+ switch_board.routes.should_not be_empty
50
+ switch_board.flush_routes
51
+ switch_board.routes.should be_empty
52
+ end
53
+ end
54
+
55
+ describe "#remove_route" do
56
+
57
+ end
58
+
59
+ describe "#best_comm" do
60
+ it "should return the comm for the most specific route" do
61
+ comm0 = double("more specific")
62
+ comm1 = double("less specific")
63
+ comm2 = double("even less specific")
64
+ comm3 = double("different net")
65
+
66
+ switch_board.add_route("1.1.1.0", "255.255.255.0", comm0)
67
+ switch_board.add_route("1.1.0.0", "255.255.0.0", comm1)
68
+ switch_board.add_route("1.0.0.0", "255.0.0.0", comm2)
69
+ switch_board.add_route("2.2.2.0", "255.255.255.255", comm3)
70
+
71
+ switch_board.best_comm("1.1.1.1").should == comm0
72
+ end
73
+
74
+ it "should fall back to less specific routes" do
75
+ comm0 = double("more specific")
76
+ comm1 = double("less specific")
77
+ comm2 = double("different net")
78
+
79
+ switch_board.add_route("1.1.1.0", "255.255.255.0", comm0)
80
+ switch_board.add_route("1.1.0.0", "255.255.0.0", comm1)
81
+
82
+ switch_board.best_comm("1.1.2.1").should == comm1
83
+
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'raptor-io/socket'
3
+
4
+ describe RaptorIO::Socket::TCP::SSL do
5
+ let(:opts) do
6
+ {
7
+ ssl_version: :TLSv1,
8
+ ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE
9
+ }
10
+ end
11
+
12
+ #include_context 'with ssl server'
13
+
14
+ #it_behaves_like "a client socket"
15
+
16
+ end
17
+
18
+
@@ -0,0 +1,59 @@
1
+ =begin
2
+ require 'spec_helper'
3
+ require 'raptor-io/socket'
4
+
5
+ describe RaptorIO::Socket::TCPServer::SSL do
6
+ include_context 'with tcp server'
7
+
8
+ let(:server_cert) { File.read(File.join(fixtures_path, 'raptor', 'socket', 'ssl_server.crt')) }
9
+ let(:server_key) { File.read(File.join(fixtures_path, 'raptor', 'socket', 'ssl_server.key')) }
10
+ let(:server_context) do
11
+ OpenSSL::SSL::SSLContext.new.tap do |context|
12
+ context.cert = OpenSSL::X509::Certificate.new(server_cert)
13
+ context.key = OpenSSL::PKey::RSA.new(server_key)
14
+ end
15
+ end
16
+
17
+ subject(:ssl_server) do
18
+ described_class.new(server_sock, context: server_context )
19
+ end
20
+
21
+ let(:data) { 'test'.force_encoding( 'binary' ) }
22
+
23
+ describe '#accept_nonblock' do
24
+ it 'returns a connected peer as a RaptorIO::Socket::TCP::SSL socket' do
25
+ ssl_server
26
+ ssl_client = OpenSSL::SSL::SSLSocket.new(client_sock)
27
+
28
+ Thread.new do
29
+ Thread.pass
30
+ #$stderr.puts "ssl_client connecting"
31
+ ssl_client.connect
32
+ #$stderr.puts "ssl_client CONNECTED"
33
+ end
34
+
35
+ ssl_peer = nil
36
+
37
+ begin
38
+ #$stderr.puts "ssl_server accepting"
39
+ ssl_peer = ssl_server.accept_nonblock
40
+ #$stderr.puts "ssl_server ACCEPTED"
41
+ rescue IO::WaitReadable
42
+ #$stderr.puts "ssl_server waiting for a client"
43
+ RaptorIO::Socket.select([ssl_server])
44
+ retry
45
+ end
46
+
47
+ #$stderr.puts("ssl_server accepted peer #{ssl_peer}")
48
+ ssl_peer.should be_kind_of RaptorIO::Socket::TCP::SSL
49
+
50
+ select( [], [ssl_peer] )
51
+ ssl_peer.write data
52
+
53
+ select( [ssl_client] )
54
+ ssl_client.read(data.size).should == data
55
+
56
+ end
57
+ end
58
+ end
59
+ =end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ require 'raptor-io/socket'
3
+
4
+ describe RaptorIO::Socket::TCPServer do
5
+ subject { described_class.new(io, opts) }
6
+ let(:opts) { {} }
7
+ let(:io) {
8
+ sio = StringIO.new
9
+ # Bind, listen, and connect all return 0 unless an exception is
10
+ # raised
11
+ sio.stub(:bind).and_return(0)
12
+ sio.stub(:listen).and_return(0)
13
+ sio.stub(:accept).and_return { StringIO.new }
14
+
15
+ sio
16
+ }
17
+
18
+ it_behaves_like 'a server socket'
19
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'raptor-io/socket'
3
+
4
+ describe RaptorIO::Socket::TCP do
5
+
6
+ subject { described_class.new(io, opts) }
7
+
8
+ let(:io) { StringIO.new }
9
+ let(:opts) { {} }
10
+
11
+ it_behaves_like 'a client socket'
12
+
13
+ it { should respond_to(:to_ssl) }
14
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ require 'raptor-io/socket'
4
+
5
+ describe RaptorIO::Socket do
6
+ subject { described_class.new(io) }
7
+ let(:io) { StringIO.new }
8
+
9
+ it "should not swallow errors in method_missing" do
10
+ subject.should_not respond_to(:asdfjkl)
11
+ expect {
12
+ subject.asdfjkl
13
+ }.to raise_error(NoMethodError)
14
+ end
15
+ end
16
+
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe "RaptorIO::VERSION" do
4
+ it 'holds the version number of the library' do
5
+ splits = RaptorIO::VERSION.to_s.split( '.' )
6
+
7
+ splits.should be_any
8
+ splits.each { |number| number.should match /\d+/ }
9
+ end
10
+ end
@@ -0,0 +1,56 @@
1
+
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+
5
+ require 'raptor-io'
6
+
7
+ # This file was generated by the `rspec --init` command. Conventionally, all
8
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
9
+ # Require this file using `require "spec_helper"` to ensure that it is only
10
+ # loaded once.
11
+ #
12
+
13
+ # Requires supporting ruby files with custom matchers and macros, etc,
14
+ # in spec/support/ and its subdirectories.
15
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
16
+ next if f.include? '/webservers/'
17
+ require f
18
+ end
19
+
20
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
21
+ RSpec.configure do |config|
22
+ config.treat_symbols_as_metadata_keys_with_true_values = true
23
+ config.run_all_when_everything_filtered = true
24
+ config.filter_run :focus
25
+
26
+ # Run specs in random order to surface order dependencies. If you find an
27
+ # order dependency and want to debug it, you can fix the order by providing
28
+ # the seed, which is printed after each run.
29
+ # --seed 1234
30
+ config.order = 'random'
31
+
32
+ config.before( :all ) do
33
+ RaptorIO::Protocol::HTTP::Client.reset
34
+ RaptorIO::Protocol::HTTP::Request::Manipulators.reset
35
+ WebServers.killall
36
+ end
37
+
38
+ config.after( :all ) do
39
+ RaptorIO::Protocol::HTTP::Client.reset
40
+ RaptorIO::Protocol::HTTP::Request::Manipulators.reset
41
+ end
42
+
43
+ config.after( :suite ) do
44
+ RaptorIO::Protocol::HTTP::Client.reset
45
+ RaptorIO::Protocol::HTTP::Request::Manipulators.reset
46
+ WebServers.killall
47
+ end
48
+
49
+ end
50
+
51
+ EXAMPLE_PORT = 12345
52
+
53
+ def example_addr; '127.0.0.1'; end
54
+ def example_port; EXAMPLE_PORT; end
55
+ def example_ssl_port; EXAMPLE_PORT + 1; end
56
+
@@ -0,0 +1,25 @@
1
+ module RaptorIO
2
+ module Protocol::HTTP
3
+ class Request
4
+
5
+ module Manipulators
6
+ module Manifoolators
7
+
8
+ #
9
+ # Test manipulator, shows that manipulators can be namespaced.
10
+ #
11
+ # @author Tasos Laskos <tasos_laskos@rapid7.com>
12
+ #
13
+ class Fooer < Manipulator
14
+
15
+ def run
16
+ request.url += ('foo' * options[:times])
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end