rails-threaded-proxy 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.
- checksums.yaml +7 -0
- data/.bundle/config +2 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +164 -0
- data/LICENSE +21 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/bin/bundle +109 -0
- data/bin/htmldiff +27 -0
- data/bin/jeweler +27 -0
- data/bin/ldiff +27 -0
- data/bin/nokogiri +27 -0
- data/bin/racc +27 -0
- data/bin/rackup +27 -0
- data/bin/rake +27 -0
- data/bin/rdoc +27 -0
- data/bin/ri +27 -0
- data/bin/rspec +27 -0
- data/bin/semver +27 -0
- data/lib/rails-threaded-proxy.rb +1 -0
- data/lib/threaded-proxy.rb +1 -0
- data/lib/threaded_proxy/client.rb +89 -0
- data/lib/threaded_proxy/controller.rb +34 -0
- data/lib/threaded_proxy/http.rb +34 -0
- data/lib/threaded_proxy.rb +10 -0
- data/rails-threaded-proxy.gemspec +68 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/threaded_proxy/client_spec.rb +60 -0
- metadata +196 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 97a50696507952bcd8658bcecce9e784ed9f627a10c7add96e0942d0e7806e9a
|
|
4
|
+
data.tar.gz: 75767119d8493f4913b977e27e0d67dadfab57e6ed3cbade742d2ca5db9e4c49
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c04a9f03a0b19c139c9de59c00dfa7f49a5e6b3bdaafe1cb1db6f23b0d6ef623c60c30be5e5e08f68517915317f2764bc394bd82da36e65ef52c365641b1dc81
|
|
7
|
+
data.tar.gz: e6368a368ca91d818de566c6884b1840c95ff76665e18d5b8256a88b28c18048f22c52e1f771a8c5348bb9e4d02f9f91022e62c682d3cf7b4f5bd7601ec4891a
|
data/.bundle/config
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.3.5
|
data/Gemfile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "actionpack"
|
|
6
|
+
gem "addressable"
|
|
7
|
+
|
|
8
|
+
group :development do
|
|
9
|
+
gem "bundler", "~> 2.0"
|
|
10
|
+
gem "jeweler", "~> 2.3.9"
|
|
11
|
+
gem "nokogiri", ">= 1.16.7"
|
|
12
|
+
gem "rdoc", "~> 6.7.0"
|
|
13
|
+
gem "rspec", ">= 0"
|
|
14
|
+
gem "webrick", ">= 0"
|
|
15
|
+
end
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: https://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
actionpack (7.2.1)
|
|
5
|
+
actionview (= 7.2.1)
|
|
6
|
+
activesupport (= 7.2.1)
|
|
7
|
+
nokogiri (>= 1.8.5)
|
|
8
|
+
racc
|
|
9
|
+
rack (>= 2.2.4, < 3.2)
|
|
10
|
+
rack-session (>= 1.0.1)
|
|
11
|
+
rack-test (>= 0.6.3)
|
|
12
|
+
rails-dom-testing (~> 2.2)
|
|
13
|
+
rails-html-sanitizer (~> 1.6)
|
|
14
|
+
useragent (~> 0.16)
|
|
15
|
+
actionview (7.2.1)
|
|
16
|
+
activesupport (= 7.2.1)
|
|
17
|
+
builder (~> 3.1)
|
|
18
|
+
erubi (~> 1.11)
|
|
19
|
+
rails-dom-testing (~> 2.2)
|
|
20
|
+
rails-html-sanitizer (~> 1.6)
|
|
21
|
+
activesupport (7.2.1)
|
|
22
|
+
base64
|
|
23
|
+
bigdecimal
|
|
24
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
25
|
+
connection_pool (>= 2.2.5)
|
|
26
|
+
drb
|
|
27
|
+
i18n (>= 1.6, < 2)
|
|
28
|
+
logger (>= 1.4.2)
|
|
29
|
+
minitest (>= 5.1)
|
|
30
|
+
securerandom (>= 0.3)
|
|
31
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
32
|
+
addressable (2.4.0)
|
|
33
|
+
base64 (0.2.0)
|
|
34
|
+
bigdecimal (3.1.8)
|
|
35
|
+
builder (3.3.0)
|
|
36
|
+
concurrent-ruby (1.3.4)
|
|
37
|
+
connection_pool (2.4.1)
|
|
38
|
+
crass (1.0.6)
|
|
39
|
+
descendants_tracker (0.0.4)
|
|
40
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
|
41
|
+
diff-lcs (1.5.1)
|
|
42
|
+
drb (2.2.1)
|
|
43
|
+
erubi (1.13.0)
|
|
44
|
+
faraday (0.9.2)
|
|
45
|
+
multipart-post (>= 1.2, < 3)
|
|
46
|
+
git (1.11.0)
|
|
47
|
+
rchardet (~> 1.8)
|
|
48
|
+
github_api (0.16.0)
|
|
49
|
+
addressable (~> 2.4.0)
|
|
50
|
+
descendants_tracker (~> 0.0.4)
|
|
51
|
+
faraday (~> 0.8, < 0.10)
|
|
52
|
+
hashie (>= 3.4)
|
|
53
|
+
mime-types (>= 1.16, < 3.0)
|
|
54
|
+
oauth2 (~> 1.0)
|
|
55
|
+
hashie (5.0.0)
|
|
56
|
+
highline (3.1.1)
|
|
57
|
+
reline
|
|
58
|
+
i18n (1.14.6)
|
|
59
|
+
concurrent-ruby (~> 1.0)
|
|
60
|
+
io-console (0.7.2)
|
|
61
|
+
jeweler (2.3.9)
|
|
62
|
+
builder
|
|
63
|
+
bundler
|
|
64
|
+
git (>= 1.2.5)
|
|
65
|
+
github_api (~> 0.16.0)
|
|
66
|
+
highline (>= 1.6.15)
|
|
67
|
+
nokogiri (>= 1.5.10)
|
|
68
|
+
psych
|
|
69
|
+
rake
|
|
70
|
+
rdoc
|
|
71
|
+
semver2
|
|
72
|
+
jwt (2.9.3)
|
|
73
|
+
base64
|
|
74
|
+
logger (1.6.1)
|
|
75
|
+
loofah (2.22.0)
|
|
76
|
+
crass (~> 1.0.2)
|
|
77
|
+
nokogiri (>= 1.12.0)
|
|
78
|
+
mime-types (2.99.3)
|
|
79
|
+
minitest (5.25.1)
|
|
80
|
+
multi_json (1.15.0)
|
|
81
|
+
multi_xml (0.7.1)
|
|
82
|
+
bigdecimal (~> 3.1)
|
|
83
|
+
multipart-post (2.4.1)
|
|
84
|
+
nokogiri (1.16.7-aarch64-linux)
|
|
85
|
+
racc (~> 1.4)
|
|
86
|
+
nokogiri (1.16.7-arm-linux)
|
|
87
|
+
racc (~> 1.4)
|
|
88
|
+
nokogiri (1.16.7-arm64-darwin)
|
|
89
|
+
racc (~> 1.4)
|
|
90
|
+
nokogiri (1.16.7-x86-linux)
|
|
91
|
+
racc (~> 1.4)
|
|
92
|
+
nokogiri (1.16.7-x86_64-darwin)
|
|
93
|
+
racc (~> 1.4)
|
|
94
|
+
nokogiri (1.16.7-x86_64-linux)
|
|
95
|
+
racc (~> 1.4)
|
|
96
|
+
oauth2 (1.4.8)
|
|
97
|
+
faraday (>= 0.8, < 3.0)
|
|
98
|
+
jwt (>= 1.0, < 3.0)
|
|
99
|
+
multi_json (~> 1.3)
|
|
100
|
+
multi_xml (~> 0.5)
|
|
101
|
+
rack (>= 1.2, < 3)
|
|
102
|
+
psych (5.1.2)
|
|
103
|
+
stringio
|
|
104
|
+
racc (1.8.1)
|
|
105
|
+
rack (2.2.10)
|
|
106
|
+
rack-session (1.0.2)
|
|
107
|
+
rack (< 3)
|
|
108
|
+
rack-test (2.1.0)
|
|
109
|
+
rack (>= 1.3)
|
|
110
|
+
rails-dom-testing (2.2.0)
|
|
111
|
+
activesupport (>= 5.0.0)
|
|
112
|
+
minitest
|
|
113
|
+
nokogiri (>= 1.6)
|
|
114
|
+
rails-html-sanitizer (1.6.0)
|
|
115
|
+
loofah (~> 2.21)
|
|
116
|
+
nokogiri (~> 1.14)
|
|
117
|
+
rake (13.2.1)
|
|
118
|
+
rchardet (1.8.0)
|
|
119
|
+
rdoc (6.7.0)
|
|
120
|
+
psych (>= 4.0.0)
|
|
121
|
+
reline (0.5.10)
|
|
122
|
+
io-console (~> 0.5)
|
|
123
|
+
rspec (3.13.0)
|
|
124
|
+
rspec-core (~> 3.13.0)
|
|
125
|
+
rspec-expectations (~> 3.13.0)
|
|
126
|
+
rspec-mocks (~> 3.13.0)
|
|
127
|
+
rspec-core (3.13.1)
|
|
128
|
+
rspec-support (~> 3.13.0)
|
|
129
|
+
rspec-expectations (3.13.3)
|
|
130
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
131
|
+
rspec-support (~> 3.13.0)
|
|
132
|
+
rspec-mocks (3.13.2)
|
|
133
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
134
|
+
rspec-support (~> 3.13.0)
|
|
135
|
+
rspec-support (3.13.1)
|
|
136
|
+
securerandom (0.3.1)
|
|
137
|
+
semver2 (3.4.2)
|
|
138
|
+
stringio (3.1.1)
|
|
139
|
+
thread_safe (0.3.6)
|
|
140
|
+
tzinfo (2.0.6)
|
|
141
|
+
concurrent-ruby (~> 1.0)
|
|
142
|
+
useragent (0.16.10)
|
|
143
|
+
webrick (1.8.2)
|
|
144
|
+
|
|
145
|
+
PLATFORMS
|
|
146
|
+
aarch64-linux
|
|
147
|
+
arm-linux
|
|
148
|
+
arm64-darwin
|
|
149
|
+
x86-linux
|
|
150
|
+
x86_64-darwin
|
|
151
|
+
x86_64-linux
|
|
152
|
+
|
|
153
|
+
DEPENDENCIES
|
|
154
|
+
actionpack
|
|
155
|
+
addressable
|
|
156
|
+
bundler (~> 2.0)
|
|
157
|
+
jeweler (~> 2.3.9)
|
|
158
|
+
nokogiri (>= 1.16.7)
|
|
159
|
+
rdoc (~> 6.7.0)
|
|
160
|
+
rspec
|
|
161
|
+
webrick
|
|
162
|
+
|
|
163
|
+
BUNDLED WITH
|
|
164
|
+
2.5.7
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 James Hu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'bundler'
|
|
5
|
+
begin
|
|
6
|
+
Bundler.setup(:default, :development)
|
|
7
|
+
rescue Bundler::BundlerError => e
|
|
8
|
+
$stderr.puts e.message
|
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
|
10
|
+
exit e.status_code
|
|
11
|
+
end
|
|
12
|
+
require 'rake'
|
|
13
|
+
|
|
14
|
+
require 'jeweler'
|
|
15
|
+
Jeweler::Tasks.new do |gem|
|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
|
17
|
+
gem.name = "rails-threaded-proxy"
|
|
18
|
+
gem.homepage = "http://github.com/mnutt/rails-threaded-proxy"
|
|
19
|
+
gem.license = "MIT"
|
|
20
|
+
gem.summary = %Q{Threaded reverse proxy for Ruby on Rails}
|
|
21
|
+
gem.description = %Q{Threaded reverse proxy for Ruby on Rails}
|
|
22
|
+
gem.email = "michael@nuttnet.net"
|
|
23
|
+
gem.authors = ["Michael Nutt"]
|
|
24
|
+
# dependencies defined in Gemfile
|
|
25
|
+
end
|
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
data/bin/bundle
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'bundle' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require "rubygems"
|
|
12
|
+
|
|
13
|
+
m = Module.new do
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def invoked_as_script?
|
|
17
|
+
File.expand_path($0) == File.expand_path(__FILE__)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def env_var_version
|
|
21
|
+
ENV["BUNDLER_VERSION"]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def cli_arg_version
|
|
25
|
+
return unless invoked_as_script? # don't want to hijack other binstubs
|
|
26
|
+
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
|
|
27
|
+
bundler_version = nil
|
|
28
|
+
update_index = nil
|
|
29
|
+
ARGV.each_with_index do |a, i|
|
|
30
|
+
if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
|
|
31
|
+
bundler_version = a
|
|
32
|
+
end
|
|
33
|
+
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
|
|
34
|
+
bundler_version = $1
|
|
35
|
+
update_index = i
|
|
36
|
+
end
|
|
37
|
+
bundler_version
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def gemfile
|
|
41
|
+
gemfile = ENV["BUNDLE_GEMFILE"]
|
|
42
|
+
return gemfile if gemfile && !gemfile.empty?
|
|
43
|
+
|
|
44
|
+
File.expand_path("../Gemfile", __dir__)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def lockfile
|
|
48
|
+
lockfile =
|
|
49
|
+
case File.basename(gemfile)
|
|
50
|
+
when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
|
|
51
|
+
else "#{gemfile}.lock"
|
|
52
|
+
end
|
|
53
|
+
File.expand_path(lockfile)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def lockfile_version
|
|
57
|
+
return unless File.file?(lockfile)
|
|
58
|
+
lockfile_contents = File.read(lockfile)
|
|
59
|
+
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
|
|
60
|
+
Regexp.last_match(1)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def bundler_requirement
|
|
64
|
+
@bundler_requirement ||=
|
|
65
|
+
env_var_version ||
|
|
66
|
+
cli_arg_version ||
|
|
67
|
+
bundler_requirement_for(lockfile_version)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def bundler_requirement_for(version)
|
|
71
|
+
return "#{Gem::Requirement.default}.a" unless version
|
|
72
|
+
|
|
73
|
+
bundler_gem_version = Gem::Version.new(version)
|
|
74
|
+
|
|
75
|
+
bundler_gem_version.approximate_recommendation
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def load_bundler!
|
|
79
|
+
ENV["BUNDLE_GEMFILE"] ||= gemfile
|
|
80
|
+
|
|
81
|
+
activate_bundler
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def activate_bundler
|
|
85
|
+
gem_error = activation_error_handling do
|
|
86
|
+
gem "bundler", bundler_requirement
|
|
87
|
+
end
|
|
88
|
+
return if gem_error.nil?
|
|
89
|
+
require_error = activation_error_handling do
|
|
90
|
+
require "bundler/version"
|
|
91
|
+
end
|
|
92
|
+
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
|
93
|
+
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
|
|
94
|
+
exit 42
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def activation_error_handling
|
|
98
|
+
yield
|
|
99
|
+
nil
|
|
100
|
+
rescue StandardError, LoadError => e
|
|
101
|
+
e
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
m.load_bundler!
|
|
106
|
+
|
|
107
|
+
if m.invoked_as_script?
|
|
108
|
+
load Gem.bin_path("bundler", "bundle")
|
|
109
|
+
end
|
data/bin/htmldiff
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'htmldiff' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("diff-lcs", "htmldiff")
|
data/bin/jeweler
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'jeweler' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("jeweler", "jeweler")
|
data/bin/ldiff
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'ldiff' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("diff-lcs", "ldiff")
|
data/bin/nokogiri
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'nokogiri' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("nokogiri", "nokogiri")
|
data/bin/racc
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'racc' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("racc", "racc")
|
data/bin/rackup
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rackup' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rack", "rackup")
|
data/bin/rake
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/rdoc
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rdoc' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rdoc", "rdoc")
|
data/bin/ri
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'ri' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rdoc", "ri")
|
data/bin/rspec
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/semver
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'semver' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("semver2", "semver")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/threaded_proxy'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/threaded_proxy'
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'addressable/uri'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require_relative 'http'
|
|
4
|
+
|
|
5
|
+
module ThreadedProxy
|
|
6
|
+
class Client
|
|
7
|
+
DISALLOWED_RESPONSE_HEADERS = %w[keep-alive]
|
|
8
|
+
|
|
9
|
+
METHODS = {
|
|
10
|
+
'get' => Net::HTTP::Get,
|
|
11
|
+
'post' => Net::HTTP::Post,
|
|
12
|
+
'put' => Net::HTTP::Put,
|
|
13
|
+
'delete' => Net::HTTP::Delete,
|
|
14
|
+
'head' => Net::HTTP::Head,
|
|
15
|
+
'options' => Net::HTTP::Options,
|
|
16
|
+
'trace' => Net::HTTP::Trace
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
DEFAULT_OPTIONS = {
|
|
20
|
+
headers: {},
|
|
21
|
+
debug: false
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def initialize(origin_url, options={})
|
|
25
|
+
@origin_url = Addressable::URI.parse(origin_url)
|
|
26
|
+
@options = options.merge(DEFAULT_OPTIONS)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def log(message)
|
|
30
|
+
$stderr.puts message if @options[:debug]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def start(socket)
|
|
34
|
+
request_method = METHODS[(@options[:method] || 'GET').to_s.downcase]
|
|
35
|
+
http_request = request_method.new(@origin_url, (@options[:headers] || {}).merge('Connection' => 'close'))
|
|
36
|
+
if IO === @options[:body]
|
|
37
|
+
http_request.body_stream = @options[:body]
|
|
38
|
+
elsif String === @options[:body]
|
|
39
|
+
http_request.body = @options[:body]
|
|
40
|
+
@options[:headers]['Content-Length'] = @options[:body].bytesize.to_s
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
http = HTTP.new(@origin_url.host, @origin_url.port || default_port(@origin_url))
|
|
44
|
+
http.use_ssl = (@origin_url.scheme == 'https')
|
|
45
|
+
http.set_debug_output($stderr) if @options[:debug]
|
|
46
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @options[:ignore_ssl_errors]
|
|
47
|
+
|
|
48
|
+
http.start do
|
|
49
|
+
http.request(http_request) do |client_response|
|
|
50
|
+
# We don't support reusing connections once we have disconnected them from rack
|
|
51
|
+
client_response['connection'] = 'close'
|
|
52
|
+
|
|
53
|
+
yield client_response if block_given?
|
|
54
|
+
|
|
55
|
+
# start writing response
|
|
56
|
+
log("Writing response status and headers")
|
|
57
|
+
socket.write "HTTP/1.1 #{client_response.code} #{client_response.message}\r\n"
|
|
58
|
+
|
|
59
|
+
client_response.each_header do |key, value|
|
|
60
|
+
socket.write "#{key}: #{value}\r\n" unless DISALLOWED_RESPONSE_HEADERS.include?(key.downcase)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Done with headers
|
|
64
|
+
socket.write "\r\n"
|
|
65
|
+
|
|
66
|
+
# There may have been some existing data in client_response's read buffer, flush it out
|
|
67
|
+
# before we manually connect the raw sockets
|
|
68
|
+
log("Flushing existing response buffer to client")
|
|
69
|
+
http.flush_existing_buffer_to(socket)
|
|
70
|
+
|
|
71
|
+
# Copy the rest of the client response to the socket
|
|
72
|
+
log("Copying response body to client")
|
|
73
|
+
http.copy_to(socket)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def default_port(uri)
|
|
79
|
+
case uri.scheme
|
|
80
|
+
when 'http'
|
|
81
|
+
80
|
|
82
|
+
when 'https'
|
|
83
|
+
443
|
|
84
|
+
else
|
|
85
|
+
nil
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require_relative 'client'
|
|
2
|
+
|
|
3
|
+
module ThreadedProxy
|
|
4
|
+
module Controller
|
|
5
|
+
def proxy_fetch(origin_url, options={})
|
|
6
|
+
# hijack the response so we can take it outside of the rack request/response cycle
|
|
7
|
+
request.env['rack.hijack'].call
|
|
8
|
+
socket = request.env['rack.hijack_io']
|
|
9
|
+
|
|
10
|
+
Thread.new do
|
|
11
|
+
if options[:body] == :rack
|
|
12
|
+
options[:headers] ||= {}
|
|
13
|
+
options[:body] = request.body_stream
|
|
14
|
+
if request.env['HTTP_TRANSFER_ENCODING'] == 'chunked'
|
|
15
|
+
options[:headers]['Transfer-Encoding'] = 'chunked'
|
|
16
|
+
elsif request.env['CONTENT_LENGTH']
|
|
17
|
+
options[:headers]['Content-Length'] = request.env['CONTENT_LENGTH'].to_s
|
|
18
|
+
else
|
|
19
|
+
raise "Cannot proxy a non-chunked POST request without content-length"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
client = Client.new(origin_url, options)
|
|
24
|
+
client.start(socket)
|
|
25
|
+
rescue Errno::EPIPE
|
|
26
|
+
# client disconnected before request finished; not an error
|
|
27
|
+
ensure
|
|
28
|
+
socket.close unless socket.closed?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
head :ok
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
|
|
3
|
+
module ThreadedProxy
|
|
4
|
+
class HTTP < Net::HTTP
|
|
5
|
+
def flush_existing_buffer_to(dest_socket)
|
|
6
|
+
while (data = @socket.send(:rbuf_consume))
|
|
7
|
+
break if data.empty?
|
|
8
|
+
dest_socket.write data
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
dest_socket.flush
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def copy_to(dest_socket)
|
|
15
|
+
IO.copy_stream(@socket.io, dest_socket)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def request(*args)
|
|
19
|
+
if block_given?
|
|
20
|
+
super { |res| yield hijack_response(res) }
|
|
21
|
+
else
|
|
22
|
+
hijack_response(super)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
# We read the response ourselves; don't need net/http to try to read it again
|
|
29
|
+
def hijack_response(res)
|
|
30
|
+
res.instance_variable_set("@read", true)
|
|
31
|
+
res
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
# stub: rails-threaded-proxy 0.1.0 ruby lib
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |s|
|
|
8
|
+
s.name = "rails-threaded-proxy".freeze
|
|
9
|
+
s.version = "0.1.0".freeze
|
|
10
|
+
|
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
|
12
|
+
s.require_paths = ["lib".freeze]
|
|
13
|
+
s.authors = ["Michael Nutt".freeze]
|
|
14
|
+
s.date = "2024-10-14"
|
|
15
|
+
s.description = "Threaded reverse proxy for Ruby on Rails".freeze
|
|
16
|
+
s.email = "michael@nuttnet.net".freeze
|
|
17
|
+
s.executables = ["bundle".freeze, "htmldiff".freeze, "jeweler".freeze, "ldiff".freeze, "nokogiri".freeze, "racc".freeze, "rackup".freeze, "rake".freeze, "rdoc".freeze, "ri".freeze, "rspec".freeze, "semver".freeze]
|
|
18
|
+
s.extra_rdoc_files = [
|
|
19
|
+
"LICENSE"
|
|
20
|
+
]
|
|
21
|
+
s.files = [
|
|
22
|
+
".bundle/config",
|
|
23
|
+
".rspec",
|
|
24
|
+
".ruby-version",
|
|
25
|
+
"Gemfile",
|
|
26
|
+
"Gemfile.lock",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"Rakefile",
|
|
29
|
+
"VERSION",
|
|
30
|
+
"bin/bundle",
|
|
31
|
+
"bin/htmldiff",
|
|
32
|
+
"bin/jeweler",
|
|
33
|
+
"bin/ldiff",
|
|
34
|
+
"bin/nokogiri",
|
|
35
|
+
"bin/racc",
|
|
36
|
+
"bin/rackup",
|
|
37
|
+
"bin/rake",
|
|
38
|
+
"bin/rdoc",
|
|
39
|
+
"bin/ri",
|
|
40
|
+
"bin/rspec",
|
|
41
|
+
"bin/semver",
|
|
42
|
+
"lib/rails-threaded-proxy.rb",
|
|
43
|
+
"lib/threaded-proxy.rb",
|
|
44
|
+
"lib/threaded_proxy.rb",
|
|
45
|
+
"lib/threaded_proxy/client.rb",
|
|
46
|
+
"lib/threaded_proxy/controller.rb",
|
|
47
|
+
"lib/threaded_proxy/http.rb",
|
|
48
|
+
"rails-threaded-proxy.gemspec",
|
|
49
|
+
"spec/spec_helper.rb",
|
|
50
|
+
"spec/threaded_proxy/client_spec.rb"
|
|
51
|
+
]
|
|
52
|
+
s.homepage = "http://github.com/mnutt/rails-threaded-proxy".freeze
|
|
53
|
+
s.licenses = ["MIT".freeze]
|
|
54
|
+
s.rubygems_version = "3.5.16".freeze
|
|
55
|
+
s.summary = "Threaded reverse proxy for Ruby on Rails".freeze
|
|
56
|
+
|
|
57
|
+
s.specification_version = 4
|
|
58
|
+
|
|
59
|
+
s.add_runtime_dependency(%q<actionpack>.freeze, [">= 0".freeze])
|
|
60
|
+
s.add_runtime_dependency(%q<addressable>.freeze, [">= 0".freeze])
|
|
61
|
+
s.add_development_dependency(%q<bundler>.freeze, ["~> 2.0".freeze])
|
|
62
|
+
s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.3.9".freeze])
|
|
63
|
+
s.add_development_dependency(%q<nokogiri>.freeze, [">= 1.16.7".freeze])
|
|
64
|
+
s.add_development_dependency(%q<rdoc>.freeze, ["~> 6.7.0".freeze])
|
|
65
|
+
s.add_development_dependency(%q<rspec>.freeze, [">= 0".freeze])
|
|
66
|
+
s.add_development_dependency(%q<webrick>.freeze, [">= 0".freeze])
|
|
67
|
+
end
|
|
68
|
+
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'webrick'
|
|
2
|
+
|
|
3
|
+
RSpec.configure do |config|
|
|
4
|
+
config.expect_with :rspec do |expectations|
|
|
5
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
config.mock_with :rspec do |mocks|
|
|
9
|
+
mocks.verify_partial_doubles = true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
|
13
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'rails-threaded-proxy'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
RSpec.describe ThreadedProxy::Client do
|
|
5
|
+
BACKEND_PORT = 38293
|
|
6
|
+
|
|
7
|
+
before(:all) do
|
|
8
|
+
@backend_server = WEBrick::HTTPServer.new(Port: BACKEND_PORT,
|
|
9
|
+
Logger: WEBrick::Log.new("/dev/null"),
|
|
10
|
+
AccessLog: [])
|
|
11
|
+
@backend_server.mount_proc '/get' do |req, res|
|
|
12
|
+
raise unless req.request_method == 'GET'
|
|
13
|
+
res.body = "Received request: #{req.path}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@backend_server.mount_proc '/post' do |req, res|
|
|
17
|
+
raise unless req.request_method == 'POST'
|
|
18
|
+
res.content_type = 'application/json'
|
|
19
|
+
res.body = JSON.generate(path: req.path,
|
|
20
|
+
headers: req.header,
|
|
21
|
+
body: req.body)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
@server_thread = Thread.new { @backend_server.start }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
after(:all) do
|
|
28
|
+
@backend_server.shutdown
|
|
29
|
+
@server_thread.kill
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "proxies a GET request" do
|
|
33
|
+
socket = StringIO.new
|
|
34
|
+
|
|
35
|
+
client = ThreadedProxy::Client.new("http://localhost:#{BACKEND_PORT}/get")
|
|
36
|
+
client.start(socket)
|
|
37
|
+
|
|
38
|
+
expect(socket.string).to include("Received request: /get")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "proxies a POST request with content-length" do
|
|
42
|
+
socket = StringIO.new
|
|
43
|
+
|
|
44
|
+
client = ThreadedProxy::Client.new("http://localhost:#{BACKEND_PORT}/post",
|
|
45
|
+
method: 'post',
|
|
46
|
+
body: 'hello world')
|
|
47
|
+
client.start(socket)
|
|
48
|
+
|
|
49
|
+
status, rest = socket.string.split("\r\n", 2)
|
|
50
|
+
headers, body = rest.split("\r\n\r\n", 2)
|
|
51
|
+
|
|
52
|
+
parsed_body = JSON.parse(body)
|
|
53
|
+
parsed_headers = headers.split("\r\n").map { |h| h.split(': ', 2) }.to_h
|
|
54
|
+
|
|
55
|
+
expect(status).to eq('HTTP/1.1 200 OK')
|
|
56
|
+
expect(parsed_headers['content-type']).to eq('application/json')
|
|
57
|
+
expect(parsed_body['path']).to eq('/post')
|
|
58
|
+
expect(parsed_body['headers']['content-length']).to eq(['11'])
|
|
59
|
+
end
|
|
60
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails-threaded-proxy
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Michael Nutt
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2024-10-14 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: actionpack
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: addressable
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: bundler
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '2.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '2.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: jeweler
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 2.3.9
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 2.3.9
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: nokogiri
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 1.16.7
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 1.16.7
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rdoc
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 6.7.0
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 6.7.0
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rspec
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: webrick
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
description: Threaded reverse proxy for Ruby on Rails
|
|
126
|
+
email: michael@nuttnet.net
|
|
127
|
+
executables:
|
|
128
|
+
- bundle
|
|
129
|
+
- htmldiff
|
|
130
|
+
- jeweler
|
|
131
|
+
- ldiff
|
|
132
|
+
- nokogiri
|
|
133
|
+
- racc
|
|
134
|
+
- rackup
|
|
135
|
+
- rake
|
|
136
|
+
- rdoc
|
|
137
|
+
- ri
|
|
138
|
+
- rspec
|
|
139
|
+
- semver
|
|
140
|
+
extensions: []
|
|
141
|
+
extra_rdoc_files:
|
|
142
|
+
- LICENSE
|
|
143
|
+
files:
|
|
144
|
+
- ".bundle/config"
|
|
145
|
+
- ".rspec"
|
|
146
|
+
- ".ruby-version"
|
|
147
|
+
- Gemfile
|
|
148
|
+
- Gemfile.lock
|
|
149
|
+
- LICENSE
|
|
150
|
+
- Rakefile
|
|
151
|
+
- VERSION
|
|
152
|
+
- bin/bundle
|
|
153
|
+
- bin/htmldiff
|
|
154
|
+
- bin/jeweler
|
|
155
|
+
- bin/ldiff
|
|
156
|
+
- bin/nokogiri
|
|
157
|
+
- bin/racc
|
|
158
|
+
- bin/rackup
|
|
159
|
+
- bin/rake
|
|
160
|
+
- bin/rdoc
|
|
161
|
+
- bin/ri
|
|
162
|
+
- bin/rspec
|
|
163
|
+
- bin/semver
|
|
164
|
+
- lib/rails-threaded-proxy.rb
|
|
165
|
+
- lib/threaded-proxy.rb
|
|
166
|
+
- lib/threaded_proxy.rb
|
|
167
|
+
- lib/threaded_proxy/client.rb
|
|
168
|
+
- lib/threaded_proxy/controller.rb
|
|
169
|
+
- lib/threaded_proxy/http.rb
|
|
170
|
+
- rails-threaded-proxy.gemspec
|
|
171
|
+
- spec/spec_helper.rb
|
|
172
|
+
- spec/threaded_proxy/client_spec.rb
|
|
173
|
+
homepage: http://github.com/mnutt/rails-threaded-proxy
|
|
174
|
+
licenses:
|
|
175
|
+
- MIT
|
|
176
|
+
metadata: {}
|
|
177
|
+
post_install_message:
|
|
178
|
+
rdoc_options: []
|
|
179
|
+
require_paths:
|
|
180
|
+
- lib
|
|
181
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
182
|
+
requirements:
|
|
183
|
+
- - ">="
|
|
184
|
+
- !ruby/object:Gem::Version
|
|
185
|
+
version: '0'
|
|
186
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
187
|
+
requirements:
|
|
188
|
+
- - ">="
|
|
189
|
+
- !ruby/object:Gem::Version
|
|
190
|
+
version: '0'
|
|
191
|
+
requirements: []
|
|
192
|
+
rubygems_version: 3.5.16
|
|
193
|
+
signing_key:
|
|
194
|
+
specification_version: 4
|
|
195
|
+
summary: Threaded reverse proxy for Ruby on Rails
|
|
196
|
+
test_files: []
|