rack-reproxy 1.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/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: []
|