rack-tunnel 0.1.0

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.
@@ -0,0 +1,63 @@
1
+ require 'socket'
2
+ require 'uri'
3
+ require 'open4'
4
+
5
+ module Rack
6
+ class Tunnel
7
+ VERSION = '0.1.0'
8
+ HEADER = 'X-Tunnel-Uri'
9
+
10
+ def initialize(app, uri)
11
+ @app, @uri = app, URI.parse(uri)
12
+
13
+ if @uri.port <= 1024 && @uri.user != 'root'
14
+ raise Error, "root user required for port #{@uri.port}"
15
+ end
16
+ end
17
+
18
+ def call(env)
19
+ establish_tunnel(env['SERVER_PORT']) unless @tunnel_established
20
+ @app.call(env.merge(HEADER => @uri.to_s))
21
+ end
22
+
23
+ def establish_tunnel(local_port)
24
+ pid, _ = Open4.popen4(command(local_port))
25
+
26
+ at_exit do
27
+ Process.kill(9, pid)
28
+ Process.wait
29
+ end
30
+
31
+ wait_for_tunnel
32
+ @tunnel_established = true
33
+ end
34
+
35
+ def command(local_port)
36
+ cmd = %w"ssh"
37
+ cmd << "-R 0.0.0.0:#{@uri.port}:localhost:#{local_port}"
38
+ cmd << @uri.host
39
+ cmd << "-l #{@uri.user}"
40
+ cmd << "-o TCPKeepAlive=yes"
41
+ cmd << "-o ServerAliveInterval=30"
42
+ cmd << "-o ServerAliveCountMax=10"
43
+ cmd << "-o GatewayPorts=yes"
44
+ cmd << "-N"
45
+
46
+ cmd.join(' ')
47
+ end
48
+
49
+ def wait_for_tunnel
50
+ Timeout::timeout(30) do
51
+ begin
52
+ return TCPSocket.new(@uri.host, @uri.port)
53
+ rescue Errno::ECONNREFUSED
54
+ retry
55
+ rescue => e
56
+ raise Error, e.message
57
+ end
58
+ end
59
+ end
60
+
61
+ class Error < StandardError ; end
62
+ end
63
+ end
@@ -0,0 +1,24 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Rack::Tunnel do
4
+ it 'adds the "X-Tunnel-Uri" header' do
5
+ env = JSON.parse(@client.get('/').body)
6
+ env['X-Tunnel-Uri'].should =~ %r{^http://}
7
+ end
8
+
9
+ it 'tunnels over ssh' do
10
+ env = JSON.parse(@client.get('/').body)
11
+ uri = env['X-Tunnel-Uri']
12
+
13
+ Rack::Client.new(uri).get('/').status.should == 200
14
+ end
15
+
16
+ it 'raise an exception if the port is restricted and the user is not root' do
17
+ lambda {
18
+ Rack::Client.new do
19
+ use Rack::Tunnel, "http://#{ENV['USER']}@localhost"
20
+ run lambda { [200, {}, []] }
21
+ end
22
+ }.should raise_error(Rack::Tunnel::Error)
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'rack/tunnel'
4
+ require 'realweb'
5
+ require 'rack/client'
6
+ require 'json'
7
+
8
+ RSpec.configure do |config|
9
+ config.color_enabled = true
10
+
11
+ config.before(:all) do
12
+ @server = RealWeb.start_server_in_thread(File.join(File.dirname(__FILE__), 'config.ru'))
13
+ @client = Rack::Client.new("http://127.0.0.1:#{@server.port}")
14
+ end
15
+ end
16
+
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-tunnel
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Ben Burkert
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-17 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rack
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: open4
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rack-client
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 1923832053
58
+ segments:
59
+ - 0
60
+ - 3
61
+ - 1
62
+ - pre
63
+ - b
64
+ version: 0.3.1.pre.b
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: json
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ type: :development
94
+ version_requirements: *id005
95
+ - !ruby/object:Gem::Dependency
96
+ name: realweb
97
+ prerelease: false
98
+ requirement: &id006 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ type: :development
108
+ version_requirements: *id006
109
+ - !ruby/object:Gem::Dependency
110
+ name: rake
111
+ prerelease: false
112
+ requirement: &id007 !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ type: :development
122
+ version_requirements: *id007
123
+ description: Automatic port forwading via SSH tunneling.
124
+ email:
125
+ - ben@benburkert.com
126
+ executables: []
127
+
128
+ extensions: []
129
+
130
+ extra_rdoc_files: []
131
+
132
+ files:
133
+ - ./lib/rack/tunnel.rb
134
+ - ./spec/rack_tunnel_spec.rb
135
+ - ./spec/spec_helper.rb
136
+ has_rdoc: true
137
+ homepage: http://github.com/benburkert/rack-tunnel
138
+ licenses: []
139
+
140
+ post_install_message:
141
+ rdoc_options: []
142
+
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ hash: 3
151
+ segments:
152
+ - 0
153
+ version: "0"
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ none: false
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ hash: 3
160
+ segments:
161
+ - 0
162
+ version: "0"
163
+ requirements: []
164
+
165
+ rubyforge_project:
166
+ rubygems_version: 1.3.7
167
+ signing_key:
168
+ specification_version: 3
169
+ summary: Automatic port forwading via SSH tunneling.
170
+ test_files:
171
+ - ./spec/rack_tunnel_spec.rb
172
+ - ./spec/spec_helper.rb