Import Upstream version 0.6.1
This commit is contained in:
commit
a803b2684b
16 changed files with 721 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
pkg/*
|
||||
*.gem
|
||||
.bundle
|
19
.travis.yml
Normal file
19
.travis.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
sudo: false
|
||||
cache: bundler
|
||||
language: ruby
|
||||
before_install:
|
||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||
- gem install bundler
|
||||
- gem update bundler
|
||||
script: bundle exec rake test
|
||||
rvm:
|
||||
- 2.0.0
|
||||
- 2.1.5
|
||||
- 2.2.2
|
||||
- 2.2.3
|
||||
- 2.3.0
|
||||
- 2.3.1
|
||||
env:
|
||||
- RAILS_ENV=test RACK_ENV=test
|
||||
notifications:
|
||||
email: false
|
6
Gemfile
Normal file
6
Gemfile
Normal file
|
@ -0,0 +1,6 @@
|
|||
source "http://rubygems.org"
|
||||
|
||||
gem 'rake'
|
||||
|
||||
# Specify your gem's dependencies in rack-proxy.gemspec
|
||||
gemspec
|
28
Gemfile.lock
Normal file
28
Gemfile.lock
Normal file
|
@ -0,0 +1,28 @@
|
|||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
rack-proxy (0.6.1)
|
||||
rack
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
power_assert (0.2.6)
|
||||
rack (1.2.1)
|
||||
rack-test (0.5.6)
|
||||
rack (>= 1.0)
|
||||
rake (0.9.2.2)
|
||||
test-unit (3.1.5)
|
||||
power_assert
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
rack-proxy!
|
||||
rack-test
|
||||
rake
|
||||
test-unit
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.6
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Jacek Becela jacek.becela@gmail.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
96
README.md
Normal file
96
README.md
Normal file
|
@ -0,0 +1,96 @@
|
|||
A request/response rewriting HTTP proxy. A Rack app. Subclass `Rack::Proxy` and provide your `rewrite_env` and `rewrite_response` methods.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
```ruby
|
||||
class Foo < Rack::Proxy
|
||||
|
||||
def rewrite_env(env)
|
||||
env["HTTP_HOST"] = "example.com"
|
||||
|
||||
env
|
||||
end
|
||||
|
||||
def rewrite_response(triplet)
|
||||
status, headers, body = triplet
|
||||
|
||||
headers["X-Foo"] = "Bar"
|
||||
|
||||
triplet
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
### Disable SSL session verification when proxying a server with e.g. self-signed SSL certs
|
||||
|
||||
```ruby
|
||||
class TrustingProxy < Rack::Proxy
|
||||
|
||||
def rewrite_env(env)
|
||||
env["rack.ssl_verify_none"] = true
|
||||
|
||||
env
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
The same can be achieved for *all* requests going through the `Rack::Proxy` instance by using
|
||||
|
||||
```ruby
|
||||
Rack::Proxy.new(ssl_verify_none: true)
|
||||
```
|
||||
|
||||
Using it as a middleware:
|
||||
-------------------------
|
||||
|
||||
Example: Proxying only requests that end with ".php" could be done like this:
|
||||
|
||||
```ruby
|
||||
require 'rack/proxy'
|
||||
class RackPhpProxy < Rack::Proxy
|
||||
|
||||
def perform_request(env)
|
||||
request = Rack::Request.new(env)
|
||||
if request.path =~ %r{\.php}
|
||||
env["HTTP_HOST"] = "localhost"
|
||||
env["REQUEST_PATH"] = "/php/#{request.fullpath}"
|
||||
super(env)
|
||||
else
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
To use the middleware, please consider the following:
|
||||
|
||||
1) For Rails we could add a configuration in config/application.rb
|
||||
|
||||
```ruby
|
||||
config.middleware.use RackPhpProxy, {ssl_verify_none: true}
|
||||
```
|
||||
|
||||
2) For Sinatra or any Rack-based application:
|
||||
|
||||
```ruby
|
||||
class MyAwesomeSinatra < Sinatra::Base
|
||||
use RackPhpProxy, {ssl_verify_none: true}
|
||||
end
|
||||
```
|
||||
|
||||
This will allow to run the other requests through the application and only proxy the requests that match the condition from the middleware.
|
||||
|
||||
See tests for more examples.
|
||||
|
||||
WARNING
|
||||
-------
|
||||
|
||||
Doesn't work with fakeweb/webmock. Both libraries monkey-patch net/http code.
|
||||
|
||||
Todos
|
||||
-----
|
||||
|
||||
- Make the docs up to date with the current use case for this code: everything except streaming which involved a rather ugly monkey patch and only worked in 1.8, but does not work now.
|
14
Rakefile
Normal file
14
Rakefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
require 'rubygems'
|
||||
require 'bundler'
|
||||
Bundler::GemHelper.install_tasks
|
||||
|
||||
require "rake/testtask"
|
||||
task :test do
|
||||
Rake::TestTask.new do |t|
|
||||
t.libs << "test"
|
||||
t.test_files = FileList['test/*_test.rb']
|
||||
t.verbose = true
|
||||
end
|
||||
end
|
||||
|
||||
task :default => :test
|
90
lib/net_http_hacked.rb
Normal file
90
lib/net_http_hacked.rb
Normal file
|
@ -0,0 +1,90 @@
|
|||
# We are hacking net/http to change semantics of streaming handling
|
||||
# from "block" semantics to regular "return" semnatics.
|
||||
# We need it to construct a streamable rack triplet:
|
||||
#
|
||||
# [status, headers, streamable_body]
|
||||
#
|
||||
# See http://github.com/aniero/rack-streaming-proxy
|
||||
# for alternative that uses additional process.
|
||||
#
|
||||
# BTW I don't like monkey patching either
|
||||
# but this is not real monkey patching.
|
||||
# I just added some methods and named them very uniquely
|
||||
# to avoid eventual conflicts. You're safe. Trust me.
|
||||
#
|
||||
# Also, in Ruby 1.9.2 you could use Fibers to avoid hacking net/http.
|
||||
|
||||
require 'net/https'
|
||||
|
||||
class Net::HTTP
|
||||
# Original #request with block semantics.
|
||||
#
|
||||
# def request(req, body = nil, &block)
|
||||
# unless started?
|
||||
# start {
|
||||
# req['connection'] ||= 'close'
|
||||
# return request(req, body, &block)
|
||||
# }
|
||||
# end
|
||||
# if proxy_user()
|
||||
# unless use_ssl?
|
||||
# req.proxy_basic_auth proxy_user(), proxy_pass()
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# req.set_body_internal body
|
||||
# begin_transport req
|
||||
# req.exec @socket, @curr_http_version, edit_path(req.path)
|
||||
# begin
|
||||
# res = HTTPResponse.read_new(@socket)
|
||||
# end while res.kind_of?(HTTPContinue)
|
||||
# res.reading_body(@socket, req.response_body_permitted?) {
|
||||
# yield res if block_given?
|
||||
# }
|
||||
# end_transport req, res
|
||||
#
|
||||
# res
|
||||
# end
|
||||
|
||||
def begin_request_hacked(req)
|
||||
begin_transport req
|
||||
req.exec @socket, @curr_http_version, edit_path(req.path)
|
||||
begin
|
||||
res = Net::HTTPResponse.read_new(@socket)
|
||||
end while res.kind_of?(Net::HTTPContinue)
|
||||
res.begin_reading_body_hacked(@socket, req.response_body_permitted?)
|
||||
@req_hacked, @res_hacked = req, res
|
||||
@res_hacked
|
||||
end
|
||||
|
||||
def end_request_hacked
|
||||
@res_hacked.end_reading_body_hacked
|
||||
end_transport @req_hacked, @res_hacked
|
||||
@res_hacked
|
||||
end
|
||||
end
|
||||
|
||||
class Net::HTTPResponse
|
||||
# Original #reading_body with block semantics
|
||||
#
|
||||
# def reading_body(sock, reqmethodallowbody) #:nodoc: internal use only
|
||||
# @socket = sock
|
||||
# @body_exist = reqmethodallowbody && self.class.body_permitted?
|
||||
# begin
|
||||
# yield
|
||||
# self.body # ensure to read body
|
||||
# ensure
|
||||
# @socket = nil
|
||||
# end
|
||||
# end
|
||||
|
||||
def begin_reading_body_hacked(sock, reqmethodallowbody)
|
||||
@socket = sock
|
||||
@body_exist = reqmethodallowbody && self.class.body_permitted?
|
||||
end
|
||||
|
||||
def end_reading_body_hacked
|
||||
self.body
|
||||
@socket = nil
|
||||
end
|
||||
end
|
1
lib/rack-proxy.rb
Normal file
1
lib/rack-proxy.rb
Normal file
|
@ -0,0 +1 @@
|
|||
require "rack/proxy"
|
77
lib/rack/http_streaming_response.rb
Normal file
77
lib/rack/http_streaming_response.rb
Normal file
|
@ -0,0 +1,77 @@
|
|||
require "net_http_hacked"
|
||||
|
||||
module Rack
|
||||
|
||||
# Wraps the hacked net/http in a Rack way.
|
||||
class HttpStreamingResponse
|
||||
attr_accessor :use_ssl
|
||||
attr_accessor :verify_mode
|
||||
attr_accessor :read_timeout
|
||||
attr_accessor :ssl_version
|
||||
|
||||
def initialize(request, host, port = nil)
|
||||
@request, @host, @port = request, host, port
|
||||
end
|
||||
|
||||
def body
|
||||
self
|
||||
end
|
||||
|
||||
def code
|
||||
response.code.to_i
|
||||
end
|
||||
# #status is deprecated
|
||||
alias_method :status, :code
|
||||
|
||||
def headers
|
||||
h = Utils::HeaderHash.new
|
||||
|
||||
response.to_hash.each do |k, v|
|
||||
h[k] = v
|
||||
end
|
||||
|
||||
h
|
||||
end
|
||||
|
||||
# Can be called only once!
|
||||
def each(&block)
|
||||
response.read_body(&block)
|
||||
ensure
|
||||
session.end_request_hacked
|
||||
session.finish
|
||||
end
|
||||
|
||||
def to_s
|
||||
@body ||= begin
|
||||
lines = []
|
||||
|
||||
each do |line|
|
||||
lines << line
|
||||
end
|
||||
|
||||
lines.join
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Net::HTTPResponse
|
||||
def response
|
||||
@response ||= session.begin_request_hacked(@request)
|
||||
end
|
||||
|
||||
# Net::HTTP
|
||||
def session
|
||||
@session ||= begin
|
||||
http = Net::HTTP.new @host, @port
|
||||
http.use_ssl = self.use_ssl
|
||||
http.verify_mode = self.verify_mode
|
||||
http.read_timeout = self.read_timeout
|
||||
http.ssl_version = self.ssl_version if self.use_ssl
|
||||
http.start
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
129
lib/rack/proxy.rb
Normal file
129
lib/rack/proxy.rb
Normal file
|
@ -0,0 +1,129 @@
|
|||
require "net_http_hacked"
|
||||
require "rack/http_streaming_response"
|
||||
|
||||
module Rack
|
||||
|
||||
# Subclass and bring your own #rewrite_request and #rewrite_response
|
||||
class Proxy
|
||||
VERSION = "0.6.1"
|
||||
|
||||
class << self
|
||||
def extract_http_request_headers(env)
|
||||
headers = env.reject do |k, v|
|
||||
!(/^HTTP_[A-Z0-9_]+$/ === k) || v.nil?
|
||||
end.map do |k, v|
|
||||
[reconstruct_header_name(k), v]
|
||||
end.inject(Utils::HeaderHash.new) do |hash, k_v|
|
||||
k, v = k_v
|
||||
hash[k] = v
|
||||
hash
|
||||
end
|
||||
|
||||
x_forwarded_for = (headers["X-Forwarded-For"].to_s.split(/, +/) << env["REMOTE_ADDR"]).join(", ")
|
||||
|
||||
headers.merge!("X-Forwarded-For" => x_forwarded_for)
|
||||
end
|
||||
|
||||
def normalize_headers(headers)
|
||||
mapped = headers.map do |k, v|
|
||||
[k, if v.is_a? Array then v.join("\n") else v end]
|
||||
end
|
||||
Utils::HeaderHash.new Hash[mapped]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def reconstruct_header_name(name)
|
||||
name.sub(/^HTTP_/, "").gsub("_", "-")
|
||||
end
|
||||
end
|
||||
|
||||
# @option opts [String, URI::HTTP] :backend Backend host to proxy requests to
|
||||
def initialize(app = nil, opts= {})
|
||||
if app.is_a?(Hash)
|
||||
opts = app
|
||||
@app = nil
|
||||
else
|
||||
@app = app
|
||||
end
|
||||
@streaming = opts.fetch(:streaming, true)
|
||||
@ssl_verify_none = opts.fetch(:ssl_verify_none, false)
|
||||
@backend = URI(opts[:backend]) if opts[:backend]
|
||||
@read_timeout = opts.fetch(:read_timeout, 60)
|
||||
@ssl_version = opts[:ssl_version] if opts[:ssl_version]
|
||||
end
|
||||
|
||||
def call(env)
|
||||
rewrite_response(perform_request(rewrite_env(env)))
|
||||
end
|
||||
|
||||
# Return modified env
|
||||
def rewrite_env(env)
|
||||
env
|
||||
end
|
||||
|
||||
# Return a rack triplet [status, headers, body]
|
||||
def rewrite_response(triplet)
|
||||
triplet
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def perform_request(env)
|
||||
source_request = Rack::Request.new(env)
|
||||
|
||||
# Initialize request
|
||||
if source_request.fullpath == ""
|
||||
full_path = URI.parse(env['REQUEST_URI']).request_uri
|
||||
else
|
||||
full_path = source_request.fullpath
|
||||
end
|
||||
|
||||
target_request = Net::HTTP.const_get(source_request.request_method.capitalize).new(full_path)
|
||||
|
||||
# Setup headers
|
||||
target_request.initialize_http_header(self.class.extract_http_request_headers(source_request.env))
|
||||
|
||||
# Setup body
|
||||
if target_request.request_body_permitted? && source_request.body
|
||||
target_request.body_stream = source_request.body
|
||||
target_request.content_length = source_request.content_length.to_i
|
||||
target_request.content_type = source_request.content_type if source_request.content_type
|
||||
target_request.body_stream.rewind
|
||||
end
|
||||
|
||||
backend = env.delete('rack.backend') || @backend || source_request
|
||||
use_ssl = backend.scheme == "https"
|
||||
ssl_verify_none = (env.delete('rack.ssl_verify_none') || @ssl_verify_none) == true
|
||||
read_timeout = env.delete('http.read_timeout') || @read_timeout
|
||||
|
||||
# Create the response
|
||||
if @streaming
|
||||
# streaming response (the actual network communication is deferred, a.k.a. streamed)
|
||||
target_response = HttpStreamingResponse.new(target_request, backend.host, backend.port)
|
||||
target_response.use_ssl = use_ssl
|
||||
target_response.read_timeout = read_timeout
|
||||
target_response.verify_mode = OpenSSL::SSL::VERIFY_NONE if use_ssl && ssl_verify_none
|
||||
target_response.ssl_version = @ssl_version if @ssl_version
|
||||
else
|
||||
http = Net::HTTP.new(backend.host, backend.port)
|
||||
http.use_ssl = use_ssl if use_ssl
|
||||
http.read_timeout = read_timeout
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if use_ssl && ssl_verify_none
|
||||
http.ssl_version = @ssl_version if @ssl_version
|
||||
|
||||
target_response = http.start do
|
||||
http.request(target_request)
|
||||
end
|
||||
end
|
||||
|
||||
headers = (target_response.respond_to?(:headers) && target_response.headers) || self.class.normalize_headers(target_response.to_hash)
|
||||
body = target_response.body || [""]
|
||||
body = [body] unless body.respond_to?(:each)
|
||||
|
||||
[target_response.code, headers, body]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
25
rack-proxy.gemspec
Normal file
25
rack-proxy.gemspec
Normal file
|
@ -0,0 +1,25 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
$:.push File.expand_path("../lib", __FILE__)
|
||||
require "rack-proxy"
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "rack-proxy"
|
||||
s.version = Rack::Proxy::VERSION
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.authors = ["Jacek Becela"]
|
||||
s.email = ["jacek.becela@gmail.com"]
|
||||
s.homepage = "http://rubygems.org/gems/rack-proxy"
|
||||
s.summary = %q{A request/response rewriting HTTP proxy. A Rack app.}
|
||||
s.description = %q{A Rack app that provides request/response rewriting proxy capabilities with streaming.}
|
||||
|
||||
s.rubyforge_project = "rack-proxy"
|
||||
|
||||
s.files = `git ls-files`.split("\n")
|
||||
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
||||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||
s.require_paths = ["lib"]
|
||||
|
||||
s.add_dependency("rack")
|
||||
s.add_development_dependency("rack-test")
|
||||
s.add_development_dependency("test-unit")
|
||||
end
|
47
test/http_streaming_response_test.rb
Normal file
47
test/http_streaming_response_test.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
require "test_helper"
|
||||
require "rack/http_streaming_response"
|
||||
|
||||
class HttpStreamingResponseTest < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
host, req = "www.trix.pl", Net::HTTP::Get.new("/")
|
||||
@response = Rack::HttpStreamingResponse.new(req, host)
|
||||
end
|
||||
|
||||
def test_streaming
|
||||
# Response status
|
||||
assert @response.code == 200
|
||||
assert @response.status == 200
|
||||
|
||||
# Headers
|
||||
headers = @response.headers
|
||||
|
||||
assert headers.size > 0
|
||||
|
||||
assert headers["content-type"] == ["text/html;charset=utf-8"]
|
||||
assert headers["CoNtEnT-TyPe"] == headers["content-type"]
|
||||
assert headers["content-length"].first.to_i > 0
|
||||
|
||||
# Body
|
||||
chunks = []
|
||||
@response.body.each do |chunk|
|
||||
chunks << chunk
|
||||
end
|
||||
|
||||
assert chunks.size > 0
|
||||
chunks.each do |chunk|
|
||||
assert chunk.is_a?(String)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def test_to_s
|
||||
assert_equal @response.headers["Content-Length"].first.to_i, @response.body.to_s.size
|
||||
end
|
||||
|
||||
def test_to_s_called_twice
|
||||
body = @response.body
|
||||
assert_equal body.to_s, body.to_s
|
||||
end
|
||||
|
||||
end
|
36
test/net_http_hacked_test.rb
Normal file
36
test/net_http_hacked_test.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
require "test_helper"
|
||||
require "net_http_hacked"
|
||||
|
||||
class NetHttpHackedTest < Test::Unit::TestCase
|
||||
|
||||
def test_net_http_hacked
|
||||
req = Net::HTTP::Get.new("/")
|
||||
http = Net::HTTP.start("www.iana.org", "80")
|
||||
|
||||
# Response code
|
||||
res = http.begin_request_hacked(req)
|
||||
assert res.code == "200"
|
||||
|
||||
# Headers
|
||||
headers = {}
|
||||
res.each_header { |k, v| headers[k] = v }
|
||||
|
||||
assert headers.size > 0
|
||||
assert headers["content-type"] == "text/html; charset=UTF-8"
|
||||
assert !headers["date"].nil?
|
||||
|
||||
# Body
|
||||
chunks = []
|
||||
res.read_body do |chunk|
|
||||
chunks << chunk
|
||||
end
|
||||
|
||||
assert chunks.size > 0
|
||||
chunks.each do |chunk|
|
||||
assert chunk.is_a?(String)
|
||||
end
|
||||
|
||||
http.end_request_hacked
|
||||
end
|
||||
|
||||
end
|
118
test/rack_proxy_test.rb
Normal file
118
test/rack_proxy_test.rb
Normal file
|
@ -0,0 +1,118 @@
|
|||
require "test_helper"
|
||||
require "rack/proxy"
|
||||
|
||||
class RackProxyTest < Test::Unit::TestCase
|
||||
class HostProxy < Rack::Proxy
|
||||
attr_accessor :host
|
||||
|
||||
def rewrite_env(env)
|
||||
env["HTTP_HOST"] = self.host || 'www.trix.pl'
|
||||
env
|
||||
end
|
||||
end
|
||||
|
||||
def app(opts = {})
|
||||
return @app ||= HostProxy.new(opts)
|
||||
end
|
||||
|
||||
def test_http_streaming
|
||||
get "/"
|
||||
assert last_response.ok?
|
||||
assert_match(/Jacek Becela/, last_response.body)
|
||||
end
|
||||
|
||||
def test_http_full_request
|
||||
app(:streaming => false)
|
||||
get "/"
|
||||
assert last_response.ok?
|
||||
assert_match(/Jacek Becela/, last_response.body)
|
||||
end
|
||||
|
||||
def test_http_full_request_headers
|
||||
app(:streaming => false)
|
||||
app.host = 'www.google.com'
|
||||
get "/"
|
||||
assert !Array(last_response['Set-Cookie']).empty?, 'Google always sets a cookie, yo. Where my cookies at?!'
|
||||
end
|
||||
|
||||
def test_https_streaming
|
||||
app.host = 'www.apple.com'
|
||||
get 'https://example.com'
|
||||
assert last_response.ok?
|
||||
assert_match(/(itunes|iphone|ipod|mac|ipad)/, last_response.body)
|
||||
end
|
||||
|
||||
def test_https_streaming_tls
|
||||
app(:ssl_version => :TLSv1).host = 'www.apple.com'
|
||||
get 'https://example.com'
|
||||
assert last_response.ok?
|
||||
assert_match(/(itunes|iphone|ipod|mac|ipad)/, last_response.body)
|
||||
end
|
||||
|
||||
def test_https_full_request
|
||||
app(:streaming => false).host = 'www.apple.com'
|
||||
get 'https://example.com'
|
||||
assert last_response.ok?
|
||||
assert_match(/(itunes|iphone|ipod|mac|ipad)/, last_response.body)
|
||||
end
|
||||
|
||||
def test_https_full_request_tls
|
||||
app({:streaming => false, :ssl_version => :TLSv1}).host = 'www.apple.com'
|
||||
get 'https://example.com'
|
||||
assert last_response.ok?
|
||||
assert_match(/(itunes|iphone|ipod|mac|ipad)/, last_response.body)
|
||||
end
|
||||
|
||||
def test_normalize_headers
|
||||
proxy_class = Rack::Proxy
|
||||
headers = { 'header_array' => ['first_entry'], 'header_non_array' => :entry }
|
||||
|
||||
normalized_headers = proxy_class.send(:normalize_headers, headers)
|
||||
assert normalized_headers.instance_of?(Rack::Utils::HeaderHash)
|
||||
assert normalized_headers['header_array'] == 'first_entry'
|
||||
assert normalized_headers['header_non_array'] == :entry
|
||||
end
|
||||
|
||||
def test_header_reconstruction
|
||||
proxy_class = Rack::Proxy
|
||||
|
||||
header = proxy_class.send(:reconstruct_header_name, "HTTP_ABC")
|
||||
assert header == "ABC"
|
||||
|
||||
header = proxy_class.send(:reconstruct_header_name, "HTTP_ABC_D")
|
||||
assert header == "ABC-D"
|
||||
end
|
||||
|
||||
def test_extract_http_request_headers
|
||||
proxy_class = Rack::Proxy
|
||||
env = {
|
||||
'NOT-HTTP-HEADER' => 'test-value',
|
||||
'HTTP_ACCEPT' => 'text/html',
|
||||
'HTTP_CONNECTION' => nil,
|
||||
'HTTP_CONTENT_MD5' => 'deadbeef'
|
||||
}
|
||||
|
||||
headers = proxy_class.extract_http_request_headers(env)
|
||||
assert headers.key?('ACCEPT')
|
||||
assert headers.key?('CONTENT-MD5')
|
||||
assert !headers.key?('CONNECTION')
|
||||
assert !headers.key?('NOT-HTTP-HEADER')
|
||||
end
|
||||
|
||||
def test_duplicate_headers
|
||||
proxy_class = Rack::Proxy
|
||||
env = { 'Set-Cookie' => ["cookie1=foo", "cookie2=bar"] }
|
||||
|
||||
headers = proxy_class.normalize_headers(env)
|
||||
assert headers['Set-Cookie'].include?('cookie1=foo'), "Include the first value"
|
||||
assert headers['Set-Cookie'].include?("\n"), "Join multiple cookies with newlines"
|
||||
assert headers['Set-Cookie'].include?('cookie2=bar'), "Include the second value"
|
||||
end
|
||||
|
||||
|
||||
def test_handles_missing_content_length
|
||||
assert_nothing_thrown do
|
||||
post "/", nil, "CONTENT_LENGTH" => nil
|
||||
end
|
||||
end
|
||||
end
|
11
test/test_helper.rb
Normal file
11
test/test_helper.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require "rubygems"
|
||||
require 'bundler/setup'
|
||||
require 'bundler/gem_tasks'
|
||||
require "test/unit"
|
||||
|
||||
require "rack"
|
||||
require "rack/test"
|
||||
|
||||
Test::Unit::TestCase.class_eval do
|
||||
include Rack::Test::Methods
|
||||
end
|
Loading…
Reference in a new issue