rack-reproxy 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/rack-reproxy.rb +1 -0
- data/lib/rack/reproxy.rb +172 -0
- metadata +88 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dc6068d5884538676a120ab16acf3048fbce97b9
|
4
|
+
data.tar.gz: ba82d90ae5890d41e15f2444c959ac9a0012d26e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9f230747d266b2407b772d593f22dbe8c0454a7b4cf6f204a62e98642d15c987d013d4d78c67ebf9f2408ef5a92d33cfdb33f950e65b7aa97f340c2cd405a586
|
7
|
+
data.tar.gz: 67ea7ea085e4d11de1c5a210a6c776d93870a5f517123020be16eccd8ee1ded654dc4a979593bc2046d5c656916846913188f877d9ee1d9cb1bc1b3792749c0d
|
data/lib/rack-reproxy.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rack/reproxy'
|
data/lib/rack/reproxy.rb
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
module Rack
|
2
|
+
# = Reproxy
|
3
|
+
#
|
4
|
+
# Allow Rack responses to be proxied from a different URL. It's like
|
5
|
+
# Rack::Sendfile, but for any HTTP backend.
|
6
|
+
#
|
7
|
+
# Rack apps can return a URI as a response body (or an X-Reproxy-Url header)
|
8
|
+
# and we pass it upstream to Nginx/Apache/Lighttpd to serve.
|
9
|
+
#
|
10
|
+
# This is an approach pioneered by MogileFS using perlbal to reproxy file
|
11
|
+
# requests to an internal storage backend.
|
12
|
+
#
|
13
|
+
# === Proxing to an internal app: serving private files
|
14
|
+
#
|
15
|
+
# Rack::Sendfile can efficiently serve files from the local filesystem.
|
16
|
+
# But that means you have to have your files NFS-mounted on all your app
|
17
|
+
# servers, and you have to know their physical paths.
|
18
|
+
#
|
19
|
+
# Instead, you can expose your file server as a private HTTP service and
|
20
|
+
# reproxy requests to it. Get rid of fussy NFS mounts and just stream files
|
21
|
+
# back from your internal server.
|
22
|
+
#
|
23
|
+
# === Proxying to yourself
|
24
|
+
#
|
25
|
+
# You can reproxy requests back to your own app, too. This is useful when you
|
26
|
+
# you'd like to HTTP-cache private, authenticated content. You can't put a
|
27
|
+
# public HTTP cache in front of your app, but you can put it in the middle!
|
28
|
+
#
|
29
|
+
# Your app receives a request, authenticates, and proxies its own response
|
30
|
+
# via an internal HTTP cache that's backed by... your app.
|
31
|
+
#
|
32
|
+
# === Nginx
|
33
|
+
#
|
34
|
+
# # In config.ru
|
35
|
+
# use Rack::Reproxy::Nginx, location: '/reproxy'
|
36
|
+
#
|
37
|
+
# # Nginx config
|
38
|
+
# location /reproxy {
|
39
|
+
# internal;
|
40
|
+
# set $reproxy_url $upstream_http_x_reproxy_url;
|
41
|
+
# proxy_pass $reproxy_url;
|
42
|
+
# }
|
43
|
+
#
|
44
|
+
# === Apache with mod_reproxy
|
45
|
+
#
|
46
|
+
# # In config.ru
|
47
|
+
# use Rack::Reproxy::Apache
|
48
|
+
#
|
49
|
+
# # Apache config
|
50
|
+
# <Location />
|
51
|
+
# AllowReproxy on
|
52
|
+
# PreserveHeaders Content-Type Content-Disposition ETag Last-Modified
|
53
|
+
# </Location>
|
54
|
+
#
|
55
|
+
# === Lighttpd
|
56
|
+
#
|
57
|
+
# # In config.ru
|
58
|
+
# use Rack::Reproxy::Lighttpd
|
59
|
+
#
|
60
|
+
# # Lighttpd config
|
61
|
+
# proxy-core.allow-x-rewrite = "enable"
|
62
|
+
#
|
63
|
+
# === Rack
|
64
|
+
#
|
65
|
+
# Wait, what? Yeah, you can reproxy without doing an HTTP roundtrip by
|
66
|
+
# immediately redispatching back to your own app. This only becomes useful
|
67
|
+
# when you do something like reproxy through Rack::Cache.
|
68
|
+
#
|
69
|
+
# # In config.ru
|
70
|
+
# use Rack::Reproxy::Rack
|
71
|
+
#
|
72
|
+
# # To proxy to a different Rack app
|
73
|
+
# use Rack::Reproxy::Rack, app: SomeInternalApp.new
|
74
|
+
#
|
75
|
+
module Reproxy
|
76
|
+
class Middleware
|
77
|
+
def initialize(app, options = {})
|
78
|
+
@app = app
|
79
|
+
@header = options.fetch(:header, 'X-Reproxy-Url')
|
80
|
+
@scrub_reproxy_header = "HTTP_#{@header.gsub('-', '_').upcase}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def call(env)
|
84
|
+
# Don't let clients ask us to reproxy URLs.
|
85
|
+
env.delete(@scrub_reproxy_header)
|
86
|
+
|
87
|
+
# In case the Rack app would like to know which header to set.
|
88
|
+
env['rack.reproxy.header'] ||= @header
|
89
|
+
|
90
|
+
status, headers, body = @app.call(env)
|
91
|
+
|
92
|
+
# Reproxy URI response bodies.
|
93
|
+
if body.is_a?(URI)
|
94
|
+
reproxy env, status, headers.merge(@header => body.to_s), body
|
95
|
+
|
96
|
+
# Reproxy explicit requests to respond with a different URL.
|
97
|
+
elsif headers.include?(@header)
|
98
|
+
reproxy env, status, headers, body
|
99
|
+
|
100
|
+
# Pass through the response, otherwise.
|
101
|
+
else
|
102
|
+
[status, headers, body]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
def reproxy(env, status, headers, body)
|
108
|
+
[status, headers.merge('X-Reproxied' => '1'), []]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Nginx relies on an upstream /reproxy location that proxies to
|
113
|
+
# X-Reproxy-Url. So we just return an X-Accel-Redirect: /reproxy header.
|
114
|
+
class Nginx < Middleware
|
115
|
+
def initialize(app, options = {})
|
116
|
+
super
|
117
|
+
@location = options.fetch(:location, '/reproxy')
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
def reproxy(env, status, headers, body)
|
122
|
+
super.tap do |response|
|
123
|
+
response[1]['X-Accel-Redirect'] = @location
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Apache with mod_reproxy uses X-Reproxy-Url directly.
|
129
|
+
class Apache < Middleware
|
130
|
+
end
|
131
|
+
|
132
|
+
# Lighttpd uses X-Rewrite-URI and X-Rewrite-Host response headers.
|
133
|
+
# Be sure to set proxy-core.allow-x-rewrite in your lighty config.
|
134
|
+
class Lighttpd < Middleware
|
135
|
+
private
|
136
|
+
def reproxy(env, status, headers, body)
|
137
|
+
super.tap do |response|
|
138
|
+
uri = URI(headers[@header])
|
139
|
+
response[1]['X-Rewrite-Host'] = uri.hostname
|
140
|
+
response[1]['X-Rewrite-URI'] = uri.request_uri
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Rack dispatches the request again and returns the proxied response
|
146
|
+
# with its headers merged onto the original response's.
|
147
|
+
class Rack < Middleware
|
148
|
+
def initialize(app, options = {})
|
149
|
+
super
|
150
|
+
@proxy_to = options.fetch(:app, self)
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
def reproxy(env, status, headers, body)
|
155
|
+
uri = URI(headers.delete(@header))
|
156
|
+
|
157
|
+
path_info = uri.path
|
158
|
+
if script_name = env['SCRIPT_NAME']
|
159
|
+
path_info.sub! /\A#{Regexp.escape(script_name)}/, ''
|
160
|
+
end
|
161
|
+
|
162
|
+
proxy_env = env.merge 'HTTP_X_REPROXIED' => '1',
|
163
|
+
'HTTP_HOST' => uri.host,
|
164
|
+
'PATH_INFO' => path_info,
|
165
|
+
'QUERY_STRING' => uri.query
|
166
|
+
|
167
|
+
proxied_status, proxied_headers, proxied_body = @proxy_to.call(proxy_env)
|
168
|
+
[proxied_status, headers.merge(proxied_headers), proxied_body]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-reproxy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeremy Kemper
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
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: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.2'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.3'
|
55
|
+
description:
|
56
|
+
email: jeremykemper@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- "./lib/rack-reproxy.rb"
|
62
|
+
- "./lib/rack/reproxy.rb"
|
63
|
+
homepage:
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.9'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 2.2.2
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: Redispatch your response via another URL. Like a transparent, internal HTTP
|
87
|
+
redirect.
|
88
|
+
test_files: []
|