forked from suvajitgupta/Tasks
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathproxy-patch.rb
144 lines (120 loc) · 5.42 KB
/
proxy-patch.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
require 'net/http'
require 'net/https'
RootCA = '/etc/ssl/certs'
module SC
module Rack
# Rack application proxies requests as needed for the given project.
class Proxy
def initialize(project)
@project = project
@proxies = project.buildfile.proxies
end
def call(env)
url = env['PATH_INFO']
@proxies.each do |proxy, value|
if url.match(/^#{Regexp.escape(proxy.to_s)}/)
return handle_proxy(value, proxy.to_s, env)
end
end
return [404, {}, "not found"]
end
def handle_proxy(proxy, proxy_url, env)
origin_host = env['SERVER_NAME'] # capture the origin host for cookies
http_method = env['REQUEST_METHOD'].to_s.downcase
url = env['PATH_INFO']
params = env['QUERY_STRING']
# collect headers...
headers = {}
env.each do |key, value|
next unless key =~ /^HTTP_/
next if key =~/^HTTP_ACCEPT_ENCODING/ # we can't proxy gzip'd or zip'd stuff
key = key.gsub(/^HTTP_/,'').downcase.sub(/^\w/){|l| l.upcase}.gsub(/_(\w)/){|l| "-#{$1.upcase}"} # remove HTTP_, dasherize and titleize
headers[key] = value
end
# Rack documentation says CONTENT_TYPE and CONTENT_LENGTH aren't prefixed by HTTP_
headers['Content-Type'] = env['CONTENT_TYPE'] if env['CONTENT_TYPE']
headers['Content-Length'] = env['CONTENT_LENGTH'] if env['CONTENT_LENGTH']
http_host, http_port = proxy[:to].split(':')
http_port = '443' if http_port.nil? and proxy[:https]
http_port = '80' if http_port.nil?
# added 4/23/09 per Charles Jolley, corrects problem
# when making requests to virtual hosts
headers['Host'] = "#{http_host}:#{http_port}"
if proxy[:url]
url = url.sub(/^#{Regexp.escape proxy_url}/, proxy[:url])
end
http_path = [url]
http_path << params if params && params.size>0
http_path = http_path.join('?')
response = nil
no_body_method = %w(delete get copy head move options trace)
# headers.each do |key, value|
# SC.logger << " #{key}: #{value}\n"
# end
if proxy[:username] and proxy[:password]
SC.logger << "Using basic HTTP authentication\n"
headers['Authorization'] = 'Basic ' + ["#{proxy[:username]}:#{proxy[:password]}"].pack('m').strip
end
if proxy[:https]
#Eloqua specific
headers['COOKIE'] = $cookies[http_host] if $cookies
SC.logger << "The Cookie is: #{headers['COOKIE']} for #{http_host}\n"
headers.delete("HOST")
SC.logger << "Sending HTTPS request\n"
http = ::Net::HTTP.new(http_host, http_port)
http.use_ssl = true
if File.directory? RootCA
http.ca_path = RootCA
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_depth = 5
else
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
http.start do |http|
if no_body_method.include?(http_method)
response = http.send(http_method, http_path, headers)
else
http_body = env['rack.input'].gets || ''
response = http.send(http_method, http_path, http_body, headers)
end
end
SC.logger << "~ PROXY: #{http_method.upcase} #{response.code} #{url} -> https://#{http_host}:#{http_port}#{http_path}\n"
else
::Net::HTTP.start(http_host, http_port) do |http|
if no_body_method.include?(http_method)
response = http.send(http_method, http_path, headers)
else
http_body = env['rack.input'].gets || ''
response = http.send(http_method, http_path, http_body, headers)
end
end
SC.logger << "~ PROXY: #{http_method.upcase} #{response.code} #{url} -> http://#{http_host}:#{http_port}#{http_path}\n"
end
body = response.body
body = "[]" if body == nil
# display and construct specific response headers
response_headers = {}
ignore_headers = ['transfer-encoding', 'keep-alive', 'connection']
$cookies = {} unless $cookies
response.each do |key, value|
next if ignore_headers.include?(key.downcase)
# If this is a cookie, strip out the domain. This technically may
# break certain scenarios where services try to set cross-domain
# cookies, but those services should not be doing that anyway...
if key.downcase == 'set-cookie'
value.gsub!(/domain=[^\;]+\;? ?/,'')
value.gsub!(/expires=[^\;]+\;? ?/,'')
value.gsub!(/path=[^\;]+\;? ?/,'')
value.gsub!(/secure; HttpOnly, /,'')
$cookies[http_host] = value #get the cookie for other sessions
end
# Location headers should rewrite the hostname if it is included.
value.gsub!(/^https?:\/\/#{http_host}(:[0-9]+)?\//, "http://#{http_host}/") if key.downcase == 'location'
SC.logger << " #{key}: #{value}\n"
response_headers[key] = value
end
return [response.code, ::Rack::Utils::HeaderHash.new(response_headers), [body]]
end
end
end
end