proxy_pac_rb 0.0.2
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.
- data/.gitignore +5 -0
- data/Gemfile +50 -0
- data/LICENSE.md +19 -0
- data/README.md +94 -0
- data/Rakefile +81 -0
- data/bin/parsepac +10 -0
- data/files/sample.pac +3 -0
- data/lib/proxy_pac_rb/exceptions.rb +10 -0
- data/lib/proxy_pac_rb/file.rb +17 -0
- data/lib/proxy_pac_rb/functions.rb +128 -0
- data/lib/proxy_pac_rb/runtimes/rubyracer.rb +87 -0
- data/lib/proxy_pac_rb/runtimes/rubyrhino.rb +77 -0
- data/lib/proxy_pac_rb/runtimes.rb +38 -0
- data/lib/proxy_pac_rb/version.rb +4 -0
- data/lib/proxy_pac_rb.rb +38 -0
- data/proxy_pac_rb.gemspec +26 -0
- data/spec/proxy_pac_rb/functions_spec.rb +18 -0
- data/spec/proxy_pac_rb_spec.rb +112 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/environment.rb +17 -0
- data/spec/support/filesystem.rb +20 -0
- data/spec/support/reporting.rb +2 -0
- data/spec/support/rspec.rb +6 -0
- data/spec/support/string.rb +2 -0
- metadata +94 -0
data/Gemfile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in local_pac.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :test do
|
7
|
+
gem 'rspec', require: false
|
8
|
+
gem 'fuubar', require: false
|
9
|
+
gem 'simplecov', require: false
|
10
|
+
gem 'rubocop', require: false
|
11
|
+
gem 'coveralls', require: false
|
12
|
+
gem 'cucumber', require: false
|
13
|
+
gem 'aruba', require: false
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development do
|
17
|
+
gem 'debugger'
|
18
|
+
gem 'debugger-completion'
|
19
|
+
gem 'github-markup'
|
20
|
+
gem 'pry'
|
21
|
+
gem 'pry-debugger', require: false
|
22
|
+
gem 'pry-doc', require: false
|
23
|
+
gem 'redcarpet', require: false
|
24
|
+
gem 'tmrb', require: false
|
25
|
+
gem 'yard', require: false
|
26
|
+
gem 'inch', require: false
|
27
|
+
end
|
28
|
+
|
29
|
+
group :profile do
|
30
|
+
gem 'ruby-prof'
|
31
|
+
end
|
32
|
+
|
33
|
+
gem 'rake', group: [:development, :test], require: false
|
34
|
+
gem 'fedux_org-stdlib', group: [:development, :test], require: false
|
35
|
+
gem 'bundler', '~> 1.3', group: [:development, :test], require: false
|
36
|
+
gem 'erubis', group: [:development, :test]
|
37
|
+
gem 'versionomy', group: [:development, :test], require: false
|
38
|
+
gem 'activesupport', '~> 4.0.0', group: [:development, :test], require: false
|
39
|
+
|
40
|
+
gem 'awesome_print', group: [:development, :test], require: 'ap'
|
41
|
+
|
42
|
+
group :runtimes do
|
43
|
+
group :therubyracer do
|
44
|
+
gem 'therubyracer', require: 'v8'
|
45
|
+
end
|
46
|
+
|
47
|
+
group :therubyrhino do
|
48
|
+
gem 'therubyrhino', require: 'rhino'
|
49
|
+
end
|
50
|
+
end
|
data/LICENSE.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2014 by Denis Günnewig
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# Proxy Pac Rb
|
2
|
+
|
3
|
+
`proxy_pac_rb` is a gem to parse [proxy auto-config](http://en.wikipedia.org/wiki/Proxy_auto-config) files.
|
4
|
+
`proxy_pac_rb` uses a JavaScript runtime to evaulate a proxy auto-config file the same way a browser does to determine what proxy (if
|
5
|
+
any at all) should a program use to connect to a server. You must install on of the supported JavaScript runtimes:
|
6
|
+
therubyracer, therubyrhino
|
7
|
+
|
8
|
+
Big thanks to [sstephenson](https://github.com/sstephenson)'s [execjs](https://github.com/sstephenson/execjs) for the
|
9
|
+
runtime wrapper code and to
|
10
|
+
[samuelkadolph](https://github.com/samuelkadolph/ruby-pac)'s
|
11
|
+
[ruby-pac](https://github.com/samuelkadolph/ruby-pac) for the foundation of this gem.
|
12
|
+
|
13
|
+
## Installing
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
gem 'proxy_pac_rb'
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install proxy_pac_rb
|
26
|
+
|
27
|
+
|
28
|
+
## Requirements
|
29
|
+
|
30
|
+
After installing the `proxy_pac_rb` gem you must install a JavaScript runtime. Compatible runtimes include:
|
31
|
+
|
32
|
+
* [therubyracer](https://rubygems.org/gems/therubyracer) Google V8 embedded within Ruby
|
33
|
+
* [therubyrhino](https://rubygems.org/gems/therubyrhino/) Mozilla Rhino embedded within JRuby
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
### Command Line
|
38
|
+
|
39
|
+
```
|
40
|
+
parsepac https://github.com/dg-vrnetze/proxy_pac_rb/raw/master/files/sample.pac https://github.com
|
41
|
+
parsepac https://github.com/dg-vrnetze/proxy_pac_rb/raw/master/files/sample.pac http://ruby-lang.com
|
42
|
+
parsepac https://github.com/dg-vrnetze/proxy_pac_rb/raw/master/files/sample.pac http://samuel.kadolph.com
|
43
|
+
```
|
44
|
+
|
45
|
+
### Ruby
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require "rubygems"
|
49
|
+
require "pac"
|
50
|
+
|
51
|
+
pac = PAC.load('https://github.com/dg-vrnetze/proxy_pac_rb/raw/master/files/sample.pac')
|
52
|
+
pac.find('https://github.com') # => "PROXY proxy:8080"
|
53
|
+
pac.find('http://ruby-lang.com') # => "PROXY proxy:8080; DIRECT"
|
54
|
+
pac.find('http://samuel.kadolph.com') # => "DIRECT"
|
55
|
+
|
56
|
+
pac = PAC.read("sample.pac")
|
57
|
+
|
58
|
+
pac = PAC.source <<-JS
|
59
|
+
function FindProxyForURL(url, host) {
|
60
|
+
return "DIRECT";
|
61
|
+
}
|
62
|
+
JS
|
63
|
+
pac.find('http://localhost') # => "DIRECT"
|
64
|
+
```
|
65
|
+
|
66
|
+
## Available JavaScript Functions
|
67
|
+
|
68
|
+
* isPlainHostName(host)
|
69
|
+
* dnsDomainIs(host, domain)
|
70
|
+
* localHostOrDomainIs(host, hostdom)
|
71
|
+
* isResolvable(host)
|
72
|
+
* isInNet(host, pattern, mask)
|
73
|
+
* dnsResolve(host)
|
74
|
+
* myIpAddress()
|
75
|
+
* dnsDomainLevels(host)
|
76
|
+
* shExpMatch(str, shexp)
|
77
|
+
* weekdayRange(wd1, wd2, gmt)
|
78
|
+
* dateRange(*args)
|
79
|
+
* timeRange(*args)
|
80
|
+
|
81
|
+
## Developers
|
82
|
+
|
83
|
+
### Contributing
|
84
|
+
|
85
|
+
If you want to contribute: fork, branch & pull request.
|
86
|
+
|
87
|
+
### Running Tests
|
88
|
+
|
89
|
+
```
|
90
|
+
bundle install
|
91
|
+
rake test:rspec
|
92
|
+
rake test:rubyracer
|
93
|
+
rake test:rubyrhino
|
94
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
#
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'fedux_org/stdlib/rake'
|
5
|
+
require 'proxy_pac_rb/version'
|
6
|
+
|
7
|
+
def software
|
8
|
+
'proxy_pac_rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
def version
|
12
|
+
ProxyPacRb::VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
def root_directory
|
16
|
+
::File.expand_path('../', __FILE__)
|
17
|
+
end
|
18
|
+
|
19
|
+
def tar_file
|
20
|
+
::File.join(pkg_directory, "#{software}-#{version}.tar.gz")
|
21
|
+
end
|
22
|
+
|
23
|
+
def tmp_directory
|
24
|
+
::File.join(root_directory, 'tmp', "#{software}-#{version}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def gem_file
|
28
|
+
::File.join(root_directory, 'pkg', "#{software}-#{version}.gem")
|
29
|
+
end
|
30
|
+
|
31
|
+
def pkg_directory
|
32
|
+
::File.join(root_directory, 'pkg')
|
33
|
+
end
|
34
|
+
|
35
|
+
def gem_directory
|
36
|
+
::File.join(root_directory, 'vendor', 'cache')
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => 'gem:build'
|
40
|
+
|
41
|
+
file gem_file => 'gem:build'
|
42
|
+
|
43
|
+
file tmp_directory do
|
44
|
+
FileUtils.mkdir_p tmp_directory
|
45
|
+
end
|
46
|
+
|
47
|
+
namespace :gem do
|
48
|
+
desc 'build tar file'
|
49
|
+
task :package => [gem_file, tmp_directory] do
|
50
|
+
FileUtils.mv ::File.join(pkg_directory, "#{software}-#{version}.gem"), tmp_directory
|
51
|
+
|
52
|
+
Dir.chdir('tmp') do
|
53
|
+
sh "tar -czf #{tar_file} #{::File.basename tmp_directory}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
namespace 'test' do
|
59
|
+
require 'bundler'
|
60
|
+
|
61
|
+
desc 'Run tests with the rubyracer runtime'
|
62
|
+
task 'rubyracer' do
|
63
|
+
Bundler.require :default, :test, :development, :therubyracer
|
64
|
+
Rake::Task['test:rspec'].invoke
|
65
|
+
end
|
66
|
+
|
67
|
+
desc 'Run tests with the therubyrhino runtime'
|
68
|
+
task 'rubyrhino' do
|
69
|
+
Bundler.require :default, :test, :development, :therubyrhino
|
70
|
+
Rake::Task['test:rspec'].invoke
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
require 'coveralls/rake/task'
|
76
|
+
Coveralls::RakeTask.new
|
77
|
+
|
78
|
+
namespace :test do
|
79
|
+
desc 'Test with coveralls'
|
80
|
+
task :coveralls => ['test:rspec', 'test:cucumber', 'coveralls:push']
|
81
|
+
end
|
data/bin/parsepac
ADDED
data/files/sample.pac
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module ProxyPacRb
|
2
|
+
class File
|
3
|
+
attr_reader :source, :context
|
4
|
+
|
5
|
+
def initialize(source)
|
6
|
+
@source = source.dup.freeze
|
7
|
+
@context = ProxyPacRb.runtime.compile(@source)
|
8
|
+
@context.include Functions
|
9
|
+
end
|
10
|
+
|
11
|
+
def find(url)
|
12
|
+
uri = URI.parse(url)
|
13
|
+
fail ArgumentError, "url is missing host" unless uri.host
|
14
|
+
context.call("FindProxyForURL", url, uri.host)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module ProxyPacRb
|
2
|
+
module Functions
|
3
|
+
DAYS = { "MON" => 1, "TUE" => 2, "WED" => 3, "THU" => 4, "FRI" => 5, "SAT" => 6, "SUN" => 7 }
|
4
|
+
MONTHS = { "JAN" => 1, "FEB" => 2, "MAR" => 3, "APR" => 4, "MAY" => 5, "JUN" => 6,
|
5
|
+
"JUL" => 7, "AUG" => 8, "SEP" => 9, "OCT" => 10, "NOV" => 11, "DEC" => 12 }
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def isPlainHostName(host)
|
9
|
+
not host.include? "."
|
10
|
+
end
|
11
|
+
|
12
|
+
def dnsDomainIs(host, domain)
|
13
|
+
host.end_with? domain
|
14
|
+
end
|
15
|
+
|
16
|
+
def localHostOrDomainIs(host, hostdom)
|
17
|
+
host == hostdom or hostdom.include? host
|
18
|
+
end
|
19
|
+
|
20
|
+
def isResolvable(host)
|
21
|
+
!!resolve_host(host)
|
22
|
+
end
|
23
|
+
|
24
|
+
def isInNet(host, pattern, mask)
|
25
|
+
IPAddr.new(pattern).mask(mask).include? resolve_host(host)
|
26
|
+
end
|
27
|
+
|
28
|
+
def dnsResolve(host)
|
29
|
+
resolve_host(host)
|
30
|
+
end
|
31
|
+
|
32
|
+
def myIpAddress()
|
33
|
+
resolve_host(Socket.gethostname)
|
34
|
+
end
|
35
|
+
|
36
|
+
def dnsDomainLevels(host)
|
37
|
+
host.scan(".").size
|
38
|
+
end
|
39
|
+
|
40
|
+
def shExpMatch(str, shexp)
|
41
|
+
::File.fnmatch(shexp, str)
|
42
|
+
end
|
43
|
+
|
44
|
+
def weekdayRange(wd1, wd2 = nil, gmt = nil)
|
45
|
+
time = Time.now
|
46
|
+
time = time.utc if gmt == "GMT"
|
47
|
+
|
48
|
+
(DAYS[wd1]..DAYS[wd2 || wd1]).include? time.wday
|
49
|
+
end
|
50
|
+
|
51
|
+
def dateRange(*args)
|
52
|
+
time = Time.now
|
53
|
+
time = time.utc if args.last == "GMT" and args.pop
|
54
|
+
|
55
|
+
case args.size
|
56
|
+
when 1
|
57
|
+
check_date_part(time, args[0])
|
58
|
+
when 2
|
59
|
+
check_date_part(time, args[0]..args[1])
|
60
|
+
when 4
|
61
|
+
check_date_part(time, args[0]..args[2]) and
|
62
|
+
check_date_part(time, args[1]..args[3])
|
63
|
+
when 6
|
64
|
+
check_date_part(time, args[0]..args[3]) and
|
65
|
+
check_date_part(time, args[1]..args[4]) and
|
66
|
+
check_date_part(time, args[2]..args[5])
|
67
|
+
else
|
68
|
+
raise ArgumentError, "wrong number of arguments"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def timeRange(*args)
|
73
|
+
time = Time.now
|
74
|
+
time = time.utc if args.last == "GMT" and args.pop
|
75
|
+
|
76
|
+
case args.size
|
77
|
+
when 1
|
78
|
+
time.hour == args[0]
|
79
|
+
when 2
|
80
|
+
(args[0]..args[1]).include? time.hour
|
81
|
+
when 4
|
82
|
+
(args[0]..args[2]).include? time.hour and
|
83
|
+
(args[1]..args[3]).include? time.min
|
84
|
+
when 6
|
85
|
+
(args[0]..args[3]).include? time.hour and
|
86
|
+
(args[1]..args[4]).include? time.min and
|
87
|
+
(args[2]..args[5]).include? time.sec
|
88
|
+
else
|
89
|
+
raise ArgumentError, "wrong number of arguments"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
def check_date_part(time, part, operation = :==)
|
95
|
+
case part
|
96
|
+
when String
|
97
|
+
time.month.send(operation, MONTHS[part])
|
98
|
+
when Integer
|
99
|
+
if part < 100
|
100
|
+
time.day.send(operation, part)
|
101
|
+
else
|
102
|
+
time.year.send(operation, part)
|
103
|
+
end
|
104
|
+
when Range
|
105
|
+
check_date_part(time, part.begin, :>=) and check_date_part(time, part.end, :<=)
|
106
|
+
else
|
107
|
+
raise ArgumentError, "wrong type"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def resolve_host(host)
|
112
|
+
Resolv.each_address(host) do |address|
|
113
|
+
begin
|
114
|
+
return address if IPAddr.new(address).ipv4?
|
115
|
+
rescue ArgumentError
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# We couldn't find an IPv4 address for the host
|
120
|
+
nil
|
121
|
+
rescue Resolv::ResolvError, NoMethodError
|
122
|
+
# Have to rescue NoMethodError because jruby has a bug with non existant hostnames
|
123
|
+
# See http://jira.codehaus.org/browse/JRUBY-6054
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module ProxyPacRb
|
2
|
+
module Runtimes
|
3
|
+
class RubyRacerRuntime
|
4
|
+
class Context
|
5
|
+
def initialize(source = "")
|
6
|
+
source = source.encode("UTF-8") if source.respond_to?(:encode)
|
7
|
+
|
8
|
+
lock do
|
9
|
+
@v8_context = V8::Context.new
|
10
|
+
@v8_context.eval(source)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def include(mod)
|
15
|
+
(mod.methods - Module.methods).each do |name|
|
16
|
+
@v8_context[name] = mod.method(name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(properties, *args)
|
21
|
+
lock do
|
22
|
+
begin
|
23
|
+
unbox @v8_context.eval(properties).call(*args)
|
24
|
+
rescue ::V8::JSError => e
|
25
|
+
if e.value["name"] == "SyntaxError"
|
26
|
+
raise RuntimeError, e.message
|
27
|
+
else
|
28
|
+
raise Exceptions::ProgramError, e.message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def unbox(value)
|
35
|
+
case value
|
36
|
+
when ::V8::Function
|
37
|
+
nil
|
38
|
+
when ::V8::Array
|
39
|
+
value.map { |v| unbox(v) }
|
40
|
+
when ::V8::Object
|
41
|
+
value.inject({}) do |vs, (k, v)|
|
42
|
+
vs[k] = unbox(v) unless v.is_a?(::V8::Function)
|
43
|
+
vs
|
44
|
+
end
|
45
|
+
when String
|
46
|
+
value.respond_to?(:force_encoding) ? value.force_encoding("UTF-8") : value
|
47
|
+
else
|
48
|
+
value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def lock
|
54
|
+
result, exception = nil, nil
|
55
|
+
V8::C::Locker() do
|
56
|
+
begin
|
57
|
+
result = yield
|
58
|
+
rescue Exception => e
|
59
|
+
exception = e
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if exception
|
64
|
+
raise exception
|
65
|
+
else
|
66
|
+
result
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def name
|
72
|
+
"therubyracer (V8)"
|
73
|
+
end
|
74
|
+
|
75
|
+
def compile(source)
|
76
|
+
Context.new(source)
|
77
|
+
end
|
78
|
+
|
79
|
+
def available?
|
80
|
+
require "v8"
|
81
|
+
true
|
82
|
+
rescue LoadError
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module ProxyPacRb
|
2
|
+
module Runtimes
|
3
|
+
class RubyRhinoRuntime
|
4
|
+
class Context
|
5
|
+
def initialize(source = "")
|
6
|
+
source = source.encode("UTF-8") if source.respond_to?(:encode)
|
7
|
+
|
8
|
+
@rhino_context = Rhino::Context.new
|
9
|
+
fix_memory_limit! @rhino_context
|
10
|
+
@rhino_context.eval(source)
|
11
|
+
end
|
12
|
+
|
13
|
+
def include(mod)
|
14
|
+
(mod.methods - Module.methods).each do |name|
|
15
|
+
@rhino_context[name] = mod.method(name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(properties, *args)
|
20
|
+
unbox @rhino_context.eval(properties).call(*args)
|
21
|
+
rescue ::Rhino::JavascriptError => e
|
22
|
+
if e.message == "syntax error"
|
23
|
+
raise RuntimeError, e.message
|
24
|
+
else
|
25
|
+
raise Exceptions::ProgramError, e.message
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def unbox(value)
|
30
|
+
case value = ::Rhino::To.ruby(value)
|
31
|
+
when ::Rhino::NativeFunction
|
32
|
+
nil
|
33
|
+
when ::Rhino::NativeObject
|
34
|
+
value.inject({}) do |vs, (k, v)|
|
35
|
+
case v
|
36
|
+
when ::Rhino::NativeFunction, ::Rhino::J::Function
|
37
|
+
nil
|
38
|
+
else
|
39
|
+
vs[k] = unbox(v)
|
40
|
+
end
|
41
|
+
vs
|
42
|
+
end
|
43
|
+
when Array
|
44
|
+
value.map { |v| unbox(v) }
|
45
|
+
else
|
46
|
+
value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
# Disables bytecode compiling which limits you to 64K scripts
|
52
|
+
def fix_memory_limit!(context)
|
53
|
+
if context.respond_to?(:optimization_level=)
|
54
|
+
context.optimization_level = -1
|
55
|
+
else
|
56
|
+
context.instance_eval { @native.setOptimizationLevel(-1) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def name
|
62
|
+
"therubyrhino (Rhino)"
|
63
|
+
end
|
64
|
+
|
65
|
+
def compile(source)
|
66
|
+
Context.new(source)
|
67
|
+
end
|
68
|
+
|
69
|
+
def available?
|
70
|
+
require "rhino"
|
71
|
+
true
|
72
|
+
rescue LoadError
|
73
|
+
false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ProxyPacRb
|
2
|
+
module Runtimes
|
3
|
+
RubyRacer = RubyRacerRuntime.new
|
4
|
+
RubyRhino = RubyRhinoRuntime.new
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def autodetect
|
8
|
+
from_environment || best_available || fail(Exceptions::RuntimeUnavailable, "Could not find a JavaScript runtime. See https://github.com/dg-vrnetze/proxy_pac_rb for a list of runtimes.")
|
9
|
+
end
|
10
|
+
|
11
|
+
def from_environment
|
12
|
+
if name = ENV["JS_RUNTIME"]
|
13
|
+
if runtime = const_get(name)
|
14
|
+
if runtime.available?
|
15
|
+
runtime if runtime.available?
|
16
|
+
else
|
17
|
+
fail Exceptions::RuntimeUnavailable, "#{runtime.name} runtime is not available on this system"
|
18
|
+
end
|
19
|
+
elsif !name.empty?
|
20
|
+
fail Exceptions::RuntimeUnavailable, "#{name} runtime is not defined"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def best_available
|
26
|
+
runtimes.find(&:available?)
|
27
|
+
end
|
28
|
+
|
29
|
+
def runtimes
|
30
|
+
@runtimes ||= [RubyRacer, RubyRhino]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.runtimes
|
36
|
+
Runtimes.runtimes
|
37
|
+
end
|
38
|
+
end
|
data/lib/proxy_pac_rb.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'ipaddr'
|
3
|
+
require 'resolv'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
require 'proxy_pac_rb/version'
|
7
|
+
require 'proxy_pac_rb/exceptions'
|
8
|
+
require 'proxy_pac_rb/functions'
|
9
|
+
require 'proxy_pac_rb/file'
|
10
|
+
require 'proxy_pac_rb/runtimes/rubyracer'
|
11
|
+
require 'proxy_pac_rb/runtimes/rubyrhino'
|
12
|
+
require 'proxy_pac_rb/runtimes'
|
13
|
+
|
14
|
+
module ProxyPacRb
|
15
|
+
class << self
|
16
|
+
attr_reader :runtime
|
17
|
+
|
18
|
+
def runtime=(runtime)
|
19
|
+
fail Exceptions::RuntimeUnavailable, "#{runtime.name} is unavailable on this system" unless runtime.available?
|
20
|
+
@runtime = runtime
|
21
|
+
end
|
22
|
+
|
23
|
+
def load(url, options = {})
|
24
|
+
require "open-uri"
|
25
|
+
File.new(open(url, { :proxy => false }.merge(options)).read)
|
26
|
+
end
|
27
|
+
|
28
|
+
def read(file)
|
29
|
+
File.new(::File.read(file))
|
30
|
+
end
|
31
|
+
|
32
|
+
def source(source)
|
33
|
+
File.new(source)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
self.runtime = Runtimes.autodetect
|
38
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
lib = ::File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'proxy_pac_rb/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'proxy_pac_rb'
|
8
|
+
spec.version = ProxyPacRb::VERSION
|
9
|
+
spec.authors = ['Dennis Günnewig']
|
10
|
+
spec.email = ['dg1@vrnetze.de']
|
11
|
+
spec.homepage = 'https://github.com/dg-vrnetze/proxy_pac_rb'
|
12
|
+
spec.summary = %q{gem to parse proxy auto-config files.}
|
13
|
+
spec.description = <<-DESC
|
14
|
+
This gem uses a JavaScript runtime to evaulate a proxy auto-config file the same way a browser does to determine what proxy (if
|
15
|
+
any at all) should a program use to connect to a server. You must install on of the supported JavaScript runtimes:
|
16
|
+
therubyracer, therubyrhino, johnson or mustang.
|
17
|
+
DESC
|
18
|
+
|
19
|
+
spec.homepage = 'https://github.com/dg-vrnetze/ruby_pac_rb'
|
20
|
+
spec.license = 'MIT'
|
21
|
+
|
22
|
+
spec.files = `git ls-files -z`.split("\x0")
|
23
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| ::File.basename(f) }
|
24
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
25
|
+
spec.require_paths = ['lib']
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe ProxyPacRb::Functions do
|
5
|
+
describe "isResolvable()" do
|
6
|
+
let(:tester) do
|
7
|
+
ProxyPacRb::Functions
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return true for localhost" do
|
11
|
+
expect(tester.isResolvable("localhost")).to be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return false for awidhaowuhuiuhiuug" do
|
15
|
+
expect(tester.isResolvable('asdfasdfasdfasdf')).to be_false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe ProxyPacRb do
|
5
|
+
|
6
|
+
let(:sample_pac) do
|
7
|
+
create_file 'sample.pac', <<-EOS.strip_heredoc
|
8
|
+
function FindProxyForURL(url, host) {
|
9
|
+
return "DIRECT";
|
10
|
+
}
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:example_1) do
|
15
|
+
create_file 'example_1.pac', <<-EOS.strip_heredoc
|
16
|
+
// Taken from http://findproxyforurl.com/pac_file_examples.html
|
17
|
+
function FindProxyForURL(url, host) {
|
18
|
+
|
19
|
+
// If URL has no dots in host name, send traffic direct.
|
20
|
+
if (isPlainHostName(host))
|
21
|
+
return "DIRECT";
|
22
|
+
|
23
|
+
// If specific URL needs to bypass proxy, send traffic direct.
|
24
|
+
if (shExpMatch(url,"*domain.com*") ||
|
25
|
+
shExpMatch(url,"*vpn.domain.com*"))
|
26
|
+
return "DIRECT";
|
27
|
+
|
28
|
+
// If IP address is internal or hostname resolves to internal IP, send direct.
|
29
|
+
var resolved_ip = dnsResolve(host);
|
30
|
+
|
31
|
+
if (isInNet(resolved_ip, "10.0.0.0", "255.0.0.0") ||
|
32
|
+
isInNet(resolved_ip, "172.16.0.0", "255.240.0.0") ||
|
33
|
+
isInNet(resolved_ip, "192.168.0.0", "255.255.0.0") ||
|
34
|
+
isInNet(resolved_ip, "127.0.0.0", "255.255.255.0"))
|
35
|
+
return "DIRECT";
|
36
|
+
|
37
|
+
// If not on a internal/LAN IP address, send traffic direct.
|
38
|
+
if (!isInNet(myIpAddress(), "10.10.1.0", "255.255.255.0"))
|
39
|
+
return "DIRECT";
|
40
|
+
|
41
|
+
// All other traffic uses below proxies, in fail-over order.
|
42
|
+
return "PROXY 1.2.3.4:8080; PROXY 4.5.6.7:8080; DIRECT";
|
43
|
+
|
44
|
+
}
|
45
|
+
EOS
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:example_2) do
|
49
|
+
create_file 'example_2.pac', <<-EOS.strip_heredoc
|
50
|
+
// Taken from http://findproxyforurl.com/pac_file_examples.html
|
51
|
+
function FindProxyForURL(url, host) {
|
52
|
+
|
53
|
+
// If IP address is internal or hostname resolves to internal IP, send direct.
|
54
|
+
var resolved_ip = dnsResolve(host);
|
55
|
+
|
56
|
+
if (isInNet(resolved_ip, "10.0.0.0", "255.0.0.0") ||
|
57
|
+
isInNet(resolved_ip, "172.16.0.0", "255.240.0.0") ||
|
58
|
+
isInNet(resolved_ip, "192.168.0.0", "255.255.0.0") ||
|
59
|
+
isInNet(resolved_ip, "127.0.0.0", "255.255.255.0"))
|
60
|
+
return "DIRECT";
|
61
|
+
|
62
|
+
// Use a different proxy for each protocol.
|
63
|
+
if (shExpMatch(url, "http:*")) return "PROXY proxy1.domain.com:3128";
|
64
|
+
if (shExpMatch(url, "https:*")) return "PROXY proxy2.domain.com:3128";
|
65
|
+
if (shExpMatch(url, "ftp:*")) return "PROXY proxy3.domain.com:3128";
|
66
|
+
|
67
|
+
}
|
68
|
+
EOS
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:everything_but_local) do
|
72
|
+
create_file 'everything_but_local.pac', <<-EOS.strip_heredoc
|
73
|
+
function FindProxyForURL(url, host) {
|
74
|
+
if (isPlainHostName(host))
|
75
|
+
return "DIRECT";
|
76
|
+
else
|
77
|
+
return "PROXY proxy:8080; DIRECT";
|
78
|
+
}
|
79
|
+
EOS
|
80
|
+
end
|
81
|
+
|
82
|
+
describe ".read" do
|
83
|
+
it "should load a file from a path" do
|
84
|
+
pac = ProxyPacRb.read(sample_pac)
|
85
|
+
expect(pac).not_to be_nil
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return DIRECT for a url" do
|
89
|
+
pac = ProxyPacRb.read(sample_pac)
|
90
|
+
expect(pac.find('http://localhost')).to eq('DIRECT')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe ".source" do
|
95
|
+
let(:source) do <<-JS.strip_heredoc
|
96
|
+
function FindProxyForURL(url, host) {
|
97
|
+
return "DIRECT";
|
98
|
+
}
|
99
|
+
JS
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should load source" do
|
103
|
+
pac = ProxyPacRb.source(source)
|
104
|
+
expect(pac).not_to be_nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should return DIRECT for a url" do
|
108
|
+
pac = ProxyPacRb.source(source)
|
109
|
+
expect(pac.find('http://localhost')).to eq('DIRECT')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH << ::File.expand_path('../../lib', __FILE__)
|
4
|
+
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.command_name 'rspec'
|
7
|
+
SimpleCov.start
|
8
|
+
|
9
|
+
# Pull in all of the gems including those in the `test` group
|
10
|
+
require 'bundler'
|
11
|
+
Bundler.require :default, :test, :development
|
12
|
+
|
13
|
+
# Loading support files
|
14
|
+
Dir.glob(::File.expand_path('../support/*.rb', __FILE__)).each { |f| require_relative f }
|
15
|
+
|
16
|
+
# Avoid writing "describe LocalPac::MyClass do [..]" but "describe MyClass do [..]"
|
17
|
+
include ProxyPacRb
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'fedux_org/stdlib/environment'
|
3
|
+
|
4
|
+
module ProxyPacRb
|
5
|
+
module SpecHelper
|
6
|
+
module Environment
|
7
|
+
include FeduxOrg::Stdlib::Environment
|
8
|
+
alias_method :with_environment, :isolated_environment
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# encoding: utf-8
|
14
|
+
RSpec.configure do |c|
|
15
|
+
c.include ProxyPacRb::SpecHelper::Environment
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'fedux_org/stdlib/filesystem'
|
3
|
+
|
4
|
+
module ProxyPacRb
|
5
|
+
module SpecHelper
|
6
|
+
module Filesystem
|
7
|
+
include FeduxOrg::Stdlib::Filesystem
|
8
|
+
|
9
|
+
def root_directory
|
10
|
+
::File.expand_path('../../../', __FILE__)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# encoding: utf-8
|
17
|
+
RSpec.configure do |c|
|
18
|
+
c.include ProxyPacRb::SpecHelper::Filesystem
|
19
|
+
c.before(:each) { cleanup_working_directory }
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: proxy_pac_rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dennis Günnewig
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-03-07 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! 'This gem uses a JavaScript runtime to evaulate a proxy auto-config
|
15
|
+
file the same way a browser does to determine what proxy (if
|
16
|
+
|
17
|
+
any at all) should a program use to connect to a server. You must install on of
|
18
|
+
the supported JavaScript runtimes:
|
19
|
+
|
20
|
+
therubyracer, therubyrhino, johnson or mustang.
|
21
|
+
|
22
|
+
'
|
23
|
+
email:
|
24
|
+
- dg1@vrnetze.de
|
25
|
+
executables:
|
26
|
+
- parsepac
|
27
|
+
extensions: []
|
28
|
+
extra_rdoc_files: []
|
29
|
+
files:
|
30
|
+
- .gitignore
|
31
|
+
- Gemfile
|
32
|
+
- LICENSE.md
|
33
|
+
- README.md
|
34
|
+
- Rakefile
|
35
|
+
- bin/parsepac
|
36
|
+
- files/sample.pac
|
37
|
+
- lib/proxy_pac_rb.rb
|
38
|
+
- lib/proxy_pac_rb/exceptions.rb
|
39
|
+
- lib/proxy_pac_rb/file.rb
|
40
|
+
- lib/proxy_pac_rb/functions.rb
|
41
|
+
- lib/proxy_pac_rb/runtimes.rb
|
42
|
+
- lib/proxy_pac_rb/runtimes/rubyracer.rb
|
43
|
+
- lib/proxy_pac_rb/runtimes/rubyrhino.rb
|
44
|
+
- lib/proxy_pac_rb/version.rb
|
45
|
+
- proxy_pac_rb.gemspec
|
46
|
+
- spec/proxy_pac_rb/functions_spec.rb
|
47
|
+
- spec/proxy_pac_rb_spec.rb
|
48
|
+
- spec/spec_helper.rb
|
49
|
+
- spec/support/environment.rb
|
50
|
+
- spec/support/filesystem.rb
|
51
|
+
- spec/support/reporting.rb
|
52
|
+
- spec/support/rspec.rb
|
53
|
+
- spec/support/string.rb
|
54
|
+
homepage: https://github.com/dg-vrnetze/ruby_pac_rb
|
55
|
+
licenses:
|
56
|
+
- MIT
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
hash: 3395524059172055841
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
hash: 3395524059172055841
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.8.23
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: gem to parse proxy auto-config files.
|
85
|
+
test_files:
|
86
|
+
- spec/proxy_pac_rb/functions_spec.rb
|
87
|
+
- spec/proxy_pac_rb_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/support/environment.rb
|
90
|
+
- spec/support/filesystem.rb
|
91
|
+
- spec/support/reporting.rb
|
92
|
+
- spec/support/rspec.rb
|
93
|
+
- spec/support/string.rb
|
94
|
+
has_rdoc:
|