Skip to content
master
Switch branches/tags
Go to file
Code
This branch is 297 commits ahead of samuelkadolph:master.

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
bin
 
 
 
 
 
 
 
 
lib
 
 
 
 
 
 
 
 
tmp
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Proxy Pac Rb

Build Status Code Climate Coverage Status Gem Version Downloads

proxy_pac_rb is a gem to compress, lint and parse proxy auto-config files. It comes with a cli program, some rack middlewares and can be used from within ruby scripts as well. 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 any at all) should a program use to connect to a server. You must install on of the supported JavaScript runtimes: therubyracer or therubyrhino.

Big thanks to sstephenson's execjs for the runtime wrapper code and to samuelkadolph's ruby-pac for the foundation of this gem.

Installing

Add this line to your application's Gemfile:

gem 'proxy_pac_rb'

And then execute:

$ bundle

Or install it yourself as:

$ gem install proxy_pac_rb

Requirements

After installing the proxy_pac_rb gem you must install a JavaScript runtime. Compatible runtimes include:

Usage

Command Line

Find proxy for url

Arguments

  • -p|--proxy-pac FILE: Path to proxy pac file
  • -t|--time YYYY-MM-DD HH:MM:SS: Time to use in proxy.pac
  • -c|--client-ip x.x.x.x: Client-IP to use in proxy.pac
  • -h|--help: Show help

Use

# Download via curl and parse pac
curl -L -o sample.pac https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample.pac
pprb find proxy -c 127.0.0.1 -t "2014-03-09 12:00:00" -p sample.pac -u https://github.com

# Or download via pprb directly and parse pac #2
pprb find proxy -c 127.0.0.1 -t "2014-03-09 12:00:00" -p https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample.pac -u https://github.com

# Or download this example if you are behind a coporate proxy via pprb directly and parse pac #3
pprb find proxy -c 127.0.0.1 -t "2014-03-09 12:00:00" -p https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample.pac -u https://github.com --use-proxy

# =>                url: result
# => https://github.com: DIRECT

Compress proxy.pac-file

You can compress a proxy.pac with pprb to reduce the amount of data transferred to download the proxy.pac.

# Download pac
curl -L -o sample.pac https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample.pac

# Compress pac
pprb compress proxy_pac -p sample.pac

Lint proxy.pac-file

You can lint a proxy.pac with pprb to check a proxy.pac before deploying it.

# Download pac
curl -L -o sample.pac https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample.pac

# Lint pac
pprb lint proxy_pac -p sample.pac

Init new proxy.pac

You can use the following command to start a new proxy.pac:

Plain

pprb init proxy_pac

Add rspec

To test your proxy.pac you can use rspec.

pprb init proxy_pac --test rspec

Add middleman

To build your proxy.pac you can use middleman.

pprb init proxy_pac --build middleman

"rack"-middleware

The middleware which comes with proxy_pac_rb is compliant with the rack-specification - tested via rack/lint and should work with every rack-compliant-server.

Prerequisites

Make sure the content is served with "Content-Type": 'application/x-ns-proxy-autoconfig'. Otherwise the content is ignored by both middlewares.

Warning

The linter-rack-middleware needs to be activated before ANY other middleman-extension, rack-middleware or whatever framework you are using can instantiate the V8-runtime! Only the first time the V8-javascript-engine - aka therubyracer - is instantiated, it is possible to create a binding to ruby code. Every other V8-object created later re-uses this binding.

You might an error like this if you ignore this warning!

error  build/proxy.pac
Unexpected token: name (is) (line: 1, col: 10, pos: 10)

Error
    at new JS_Parse_Error (<eval>:2359:10623)
    at js_error (<eval>:2359:10842)
    at croak (<eval>:2359:19086)
    at token_error (<eval>:2359:19223)
    at unexpected (<eval>:2359:19311)
    at semicolon (<eval>:2359:19784)
    at simple_statement (<eval>:2359:22580)
    at <eval>:2359:20553
    at <eval>:2359:19957
    at <eval>:2359:31968
There were errors during this build

Linter Middleware

require 'proxy_pac_rb/rack/proxy_pac_linter'
use ProxyPacRb::Rack::ProxyPacLinter

Compressor Middleware

require 'proxy_pac_rb/rack/proxy_pac_compressor'
use ProxyPacRb::Rack::ProxyPacCompressor

If you need to change some settings, please pass it a options-parameter. Please see the (uglifier)[https://github.com/lautis/uglifier] for more information about this.

require 'proxy_pac_rb/rack/proxy_pac_compressor'
use ProxyPacRb::Rack::ProxyPacCompressor.new(options: {})

Using "rack"-middleware with "middleman"

If you want to use the rack-middleware with middleman look at the following code snippet captured from the middleman-configuration file config.rb:

  • config.rb:

    # IMPORTANT: Needs to come first before compressor
      require 'proxy_pac_rb/rack/proxy_pac_linter'
      use ProxyPacRb::Rack::ProxyPacLinter
    
      require 'proxy_pac_rb/rack/proxy_pac_compressor'
      use ProxyPacRb::Rack::ProxyPacCompressor
    
    # The middleware works on content served with 
    # "Content-Type" 'application/x-ns-proxy-autoconfig'
      page "*.pac", content_type: 'application/x-ns-proxy-autoconfig', layout: false
    
    # This provides an uncompressed copy of the proxy.pac to make it
    # possible for your support to review it by hand
    Dir.glob(File.join(source_dir, '**', '*.pac*')).each do |f|
      # Path should be relative to source dir
      relative_path = Pathname.new(f).relative_path_from(Pathname.new(source_dir))
      relative_path = relative_path.to_s.gsub(/(?<path>.*\.pac)\..*/, '\k<path>')
    
      # "text/plain" prevents the middlewares to handle it
      proxy(format('%s.raw', relative_path), relative_path, content_type: 'text/plain', layout: false)
    end

Ruby

Load from website

require 'proxy_pac_rb'

file = ProxyPacRb::Parser.new.parse('https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample.pac')
file.find('https://github.com')        # => "DIRECT"

Load from filesystem

curl -L -o sample.pac https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample.pac
require 'proxy_pac_rb'

file = ProxyPacRb::Parser.new.parse("sample.pac")
file.find('https://github.com')        # => "DIRECT"

Use string

require 'proxy_pac_rb'

file = ProxyPacRb::Parser.new.parse <<-JS
  function FindProxyForURL(url, host) {
    return "DIRECT";
  }
JS

file.find('http://localhost') # => "DIRECT"

Use Client IP

require 'proxy_pac_rb'

environment = ProxyPacRb::Environment.new(client_ip: '127.0.0.1')
file = ProxyPacRb::Parser.new(environment).parse('https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample2.pac')
file.find('https://github.com')        # => "PROXY localhost:8080"

environment = ProxyPacRb::Environment.new(client_ip: '127.0.0.2')
file = ProxyPacRb::Parser.new(environment).parse('https://github.com/fedux-org/proxy_pac_rb/raw/master/files/sample2.pac')
file.find('https://github.com')        # => "DIRECT"

Use Date Time

require 'proxy_pac_rb'

string = <<~EOS
function FindProxyForURL(url, host) {
  if (dateRange("JUL", "SEP")) {
    return "PROXY localhost:8080";                                                                                                          
  } else {
    return "DIRECT";
  }
}
EOS

environment = ProxyPacRb::Environment.new(time: Time.parse('2014-07-06 12:00'))
file = ProxyPacRb::Parser.new(environment).parse(string)
file.find('http://localhost') # => 'PROXY localhost:8080'

environment = ProxyPacRb::Environment.new(time: Time.parse('2014-03-08 6:00'))
file = ProxyPacRb::Parser.new(environment).parse(string)
file.find('http://localhost') # => 'DIRECT'

Available JavaScript Functions

  • isPlainHostName(host)
  • dnsDomainIs(host, domain)
  • localHostOrDomainIs(host, hostdom)
  • isResolvable(host)
  • isInNet(host, pattern, mask)
  • dnsResolve(host)
  • myIpAddress()
  • dnsDomainLevels(host)
  • shExpMatch(str, shexp)
  • weekdayRange(wd1, wd2, gmt)
  • dateRange(*args)
  • timeRange(*args)
  • alert(msg) (output on stderr by default)

RSpec-integration

proxy_pac_rb comes with helpers and matchers for rspec. To make those helpers and matchers available in your project, add this code snippet in your project:

require 'proxy_pac_rb/rspec'

Helpers

  • proxy_pac:

    This helper makes a proxy.pac available. It requires a source for your proxy.pac given in subject { } - e.g. a file, a string, or a url. It represents a ProxyPacFile.

  • time:

    The time-helper makes 1970-01-01 00:00:00 as time available. Overwrite this helper at will with another time string or a time-object - e.g let(:time) { Time.now }.

  • client_ip:

    The client_ip-helper makes 127.0.0.1 available. Overwrite it with a different ip-address as string or an object which returns an ip-address on #to_s.

  • root_path:

    The root_path-helper is meant for overriding. It is used to find your "proxy.pac"-files. By default its value is Dir.getwd which is set by rspec.

Configuration

You can either configure ProxyPacRb either via a global ProxyPacRb.configure-block:

ProxyPacRb.configure do |config|
  config.use_proxy = true
end

or via RSpec-metadata:

RSpec.describe 'proxy.pac', type: :proxy_pac, use_proxy: true do
end

Examples

To make it easier for you to start, you find some examples below.

Type for specs

It is important that you flag your specs with type: :proxy_pac. Otherwise the helpers are not included and not available in your examples.

RSpec.describe 'proxy.pac', type: :proxy_pac do

Supported sources

String

RSpec.describe 'String', type: :proxy_pac do
  subject do
    <<~EOS.chomp
      function FindProxyForURL(url, host) {
        return "DIRECT";
      }
    EOS
  end
end

Local File

RSpec.describe 'proxy.pac', type: :proxy_pac do
  subject { 'proxy.pac' }
end

URL

RSpec.describe 'http://server/proxy.pac', type: :proxy_pac do
  subject { 'http://server/proxy.pac' }
end

Matchers

Readable

To check if a proxy.pac could be read from filesystem or downloaded via HTTP, check be_readable.

require 'proxy_pac_rb/rspec'

RSpec.describe 'proxy.pac', type: :proxy_pac do
  context 'when proxy pac exist' do
    context 'when is file' do
      subject { 'proxy.pac' }
      it { expect(proxy_pac).to be_readable }
    end

    context 'when is url' do
      subject { 'http://www.example.com/proxy.pac' }
      it { expect(proxy_pac).to be_readable }
    end
  end
end

Equal

If you want to check if a proxy.pac is the same you can use the be_the_same_proxy_pac_file-matcher.

require 'proxy_pac_rb/rspec'

RSpec.describe 'proxy.pac', type: :proxy_pac do
  subject do
    <<~EOS.chomp
      function FindProxyForURL(url, host) {
        return "DIRECT";
      }
    EOS
  end
  context 'Check equality of proxy pac' do
    context 'when proxy.pac is eq' do
      it { expect(proxy_pac).to be_the_same_proxy_pac_file 'proxy.pac' }
    end

    context 'when proxy.pac is not eq' do
      it { expect(proxy_pac).not_to be_the_same_proxy_pac_file 'proxy.pac' }
    end
  end
end

This is quite handy to compare a local proxy.pac with a remote one - e.g. a deployed one.

require 'proxy_pac_rb/rspec'

RSpec.describe 'proxy.pac', type: :proxy_pac do
  let(:local_proxy_pac) { ProxyPacRb::ProxyPacFile.new(source: file) }

  before(:each) do
    ProxyPacRb::ProxyPacLoader.new.load(local_proxy_pac)
    ProxyPacRb::ProxyPacCompressor.new.compress(local_proxy_pac) if local_proxy_pac.readable?
  end

  context 'when no proxy.pac is given' do
    subject { 'http://server.example.com/proxy.pac' }
    let(:file) { 'source/proxy.pac' }

    it { expect(proxy_pac).to be_the_same_proxy_pac_file(local_proxy_pac) }
  end
end

Valid

You want to check if your proxy.pac is valid. This will find reference errors (e.g. unknown variables) and syntax errors.

require 'proxy_pac_rb/rspec'

RSpec.describe 'proxy.pac', type: :proxy_pac do
  subject do
    <<~EOS.chomp
      function FindProxyForURL(url, host) {
        return "DIRECT";
      }
    EOS
  end
  context 'Check validity of proxy pac' do
    context 'when proxy.pac is valid' do
      it { expect(proxy_pac).to be_valid }
    end

    context 'when proxy.pac is not valid' do
      subject do
        <<~EOS.chomp
          function FindProxyForURL(url, host) {
            return adsf;
          }
        EOS
      end
      it { expect(proxy_pac).not_to be_valid }
    end
  end
end

Parse proxy.pac

To make some logic checks use the be_downloaded_via-matcher. This will parse the proxy.pac and returns the proxy to be used for a given url.

require 'proxy_pac_rb/rspec'
RSpec.describe 'proxy.pac', type: :proxy_pac do
  subject do
    <<~EOS.chomp
      function FindProxyForURL(url, host) {
        if (dnsDomainIs(host, 'www1.example.com'')) {
          return "PROXY proxy1.example.com:8080";
        } else {
          return "PROXY proxy2.example.net:8080";
        }
      }
    EOS
  end
  context 'Parse Proxy Pac' do
    context 'when url is forwarded via' do
      let(:url) { 'http://www1.example.com' }
      it { expect(url).to be_downloaded_via 'PROXY proxy.example.com:8080' }
    end

    context 'when url is not forwarded via' do
      let(:url) { 'http://www2.example.com' }
      it { expect(url).not_to be_downloaded_via 'PROXY proxy.example.com:8080' }
    end
  end
end

Developers

After checking out the repo, run script/bootstrap to install dependencies. Then, run script/console for an interactive prompt that will allow you to experiment. To run tests execute script/test.

To install this gem onto your local machine, run bundle exec rake gem:install. To release a new version, update the version number in version.rb, and then run bundle exec rake gem:release to create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

If you want to contribute: fork, branch & pull request and please see CONTRIBUTING.md.

Running Tests

bundle install
rake test:rspec
rake test:rubyracer
rake test:rubyrhino

If you want to open an issue. Please send a PR with a test describing the bug.

About

proxy_pac _rb is a gem to test, compress, lint, and parse proxy auto-config files

Resources

License

Packages

No packages published