Skip to content

Commit

Permalink
feature(runtime): add JavaScript runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
jackwakefield committed Sep 15, 2014
1 parent 7eabf9c commit 3b0a66d
Show file tree
Hide file tree
Showing 2 changed files with 319 additions and 0 deletions.
165 changes: 165 additions & 0 deletions runtime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// Copyright 2014 Jack Wakefield
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gopac

import "github.com/robertkrimen/otto"

type runtime struct {
vm *otto.Otto
}

func newRuntime() (*runtime, error) {
rt := &runtime{
vm: otto.New(),
}

rt.vm.Set("isPlainHostName", rt.isPlainHostName)
rt.vm.Set("dnsDomainIs", rt.dnsDomainIs)
rt.vm.Set("localHostOrDomainIs", rt.localHostOrDomainIs)
rt.vm.Set("isResolvable", rt.isResolvable)
rt.vm.Set("isInNet", rt.isInNet)
rt.vm.Set("dnsResolve", rt.dnsResolve)
rt.vm.Set("myIpAddress", rt.myIpAddress)
rt.vm.Set("dnsDomainLevels", rt.dnsDomainLevels)
rt.vm.Set("shExpMatch", rt.shExpMatch)

if _, err := rt.vm.Run(javascriptUtils); err != nil {
return nil, err
}

return rt, nil
}

func (rt *runtime) run(content string) error {
if _, err := rt.vm.Run(content); err != nil {
return err
}

return nil
}

func (rt *runtime) findProxyForURL(url, host string) (string, error) {
value, err := rt.vm.Call("FindProxyForURL", nil, url, host)

if err != nil {
return "", err
}

var proxy string

if proxy, err = otto.Value.ToString(value); err != nil {
return "", err
}

return proxy, nil
}

func (rt *runtime) isPlainHostName(call otto.FunctionCall) otto.Value {
if host, err := call.Argument(0).ToString(); err == nil {
if value, err := rt.vm.ToValue(isPlainHostName(host)); err == nil {
return value
}
}

return otto.Value{}
}

func (rt *runtime) dnsDomainIs(call otto.FunctionCall) otto.Value {
if host, err := call.Argument(0).ToString(); err == nil {
if domain, err := call.Argument(1).ToString(); err == nil {
if value, err := rt.vm.ToValue(dnsDomainIs(host, domain)); err == nil {
return value
}
}
}

return otto.Value{}
}

func (rt *runtime) localHostOrDomainIs(call otto.FunctionCall) otto.Value {
if host, err := call.Argument(0).ToString(); err == nil {
if hostdom, err := call.Argument(1).ToString(); err == nil {
if value, err := rt.vm.ToValue(localHostOrDomainIs(host, hostdom)); err == nil {
return value
}
}
}

return otto.Value{}
}

func (rt *runtime) isResolvable(call otto.FunctionCall) otto.Value {
if host, err := call.Argument(0).ToString(); err == nil {
if value, err := rt.vm.ToValue(isResolvable(host)); err == nil {
return value
}
}

return otto.Value{}
}

func (rt *runtime) isInNet(call otto.FunctionCall) otto.Value {
if host, err := call.Argument(0).ToString(); err == nil {
if pattern, err := call.Argument(1).ToString(); err == nil {
if mask, err := call.Argument(2).ToString(); err == nil {
if value, err := rt.vm.ToValue(isInNet(host, pattern, mask)); err == nil {
return value
}
}
}
}

return otto.Value{}
}

func (rt *runtime) dnsResolve(call otto.FunctionCall) otto.Value {
if host, err := call.Argument(0).ToString(); err == nil {
if value, err := rt.vm.ToValue(dnsResolve(host)); err == nil {
return value
}
}

return otto.Value{}
}

func (rt *runtime) myIpAddress(call otto.FunctionCall) otto.Value {
if value, err := rt.vm.ToValue(myIpAddress()); err == nil {
return value
}

return otto.Value{}
}

func (rt *runtime) dnsDomainLevels(call otto.FunctionCall) otto.Value {
if host, err := call.Argument(0).ToString(); err == nil {
if value, err := rt.vm.ToValue(dnsDomainLevels(host)); err == nil {
return value
}
}

return otto.Value{}
}

func (rt *runtime) shExpMatch(call otto.FunctionCall) otto.Value {
if str, err := call.Argument(0).ToString(); err == nil {
if shexp, err := call.Argument(1).ToString(); err == nil {
if value, err := rt.vm.ToValue(shExpMatch(str, shexp)); err == nil {
return value
}
}
}

return otto.Value{}
}
154 changes: 154 additions & 0 deletions runtime_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright 2014 Jack Wakefield
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gopac

import (
"testing"

"github.com/robertkrimen/otto"
"github.com/stretchr/testify/assert"
)

func callBooleanFunction(rt *runtime, method string, params ...interface{}) (bool, error) {
value, err := rt.vm.Call(method, nil, params...)

if err != nil {
return false, err
}

return otto.Value.ToBoolean(value)
}

func callStringFunction(rt *runtime, method string, params ...interface{}) (string, error) {
value, err := rt.vm.Call(method, nil, params...)

if err != nil {
return "", err
}

return otto.Value.ToString(value)
}

func callNumberFunction(rt *runtime, method string, params ...interface{}) (int64, error) {
value, err := rt.vm.Call(method, nil, params...)

if err != nil {
return 0, err
}

return otto.Value.ToInteger(value)
}

func TestRuntimeInit(t *testing.T) {
rt, err := newRuntime()
assert.NotNil(t, rt, "runtime should not be nil")
assert.Nil(t, err, "err should be nil")
}

func TestRuntimeIsPlainHostName(t *testing.T) {
rt, _ := newRuntime()

www, err := callBooleanFunction(rt, "isPlainHostName", "www")
assert.Nil(t, err, "should not error")
assert.True(t, www, "'www' should be a valid plain host")

netscape, err := callBooleanFunction(rt, "isPlainHostName", "www.netscape.com")
assert.Nil(t, err, "should not error")
assert.False(t, netscape, "'www.netscape.com' should not be a valid plain host")
}

func TestRuntimeDnsDomainIs(t *testing.T) {
rt, _ := newRuntime()

netscape, err := callBooleanFunction(rt, "dnsDomainIs", "www.netscape.com", ".netscape.com")
assert.Nil(t, err, "should not error")
assert.True(t, netscape, "'www.netscape.com' should be a valid host for domain '.netscape.com'")

www, err := callBooleanFunction(rt, "dnsDomainIs", "www", ".netscape.com")
assert.Nil(t, err, "should not error")
assert.False(t, www, "'www' should not be a valid host for domain '.netscape.com'")

mcom, err := callBooleanFunction(rt, "dnsDomainIs", "w.mcom.com", ".netscape.com")
assert.Nil(t, err, "should not error")
assert.False(t, mcom, "'www.mcom.com' should not be a valid host for domain '.netscape.com'")
}

func TestRuntimeLocalHostOrDomainIs(t *testing.T) {
rt, _ := newRuntime()

netscape, err := callBooleanFunction(rt, "localHostOrDomainIs", "www.netscape.com", "www.netscape.com")
assert.Nil(t, err, "should not error")
assert.True(t, netscape, "'www.netscape.com' should be valid as it equals the domain 'www.netscape.com'")

www, err := callBooleanFunction(rt, "localHostOrDomainIs", "www", "www.netscape.com")
assert.Nil(t, err, "should not error")
assert.True(t, www, "'www' should be valid as it contains no domain part")

mcom, err := callBooleanFunction(rt, "localHostOrDomainIs", "www.mcom.com", "wwww.netscape.com")
assert.Nil(t, err, "should not error")
assert.False(t, mcom, "'www.mcom.com' should not be as it contains a domain part")

home, err := callBooleanFunction(rt, "localHostOrDomainIs", "home.netscape.com", "wwww.netscape.com")
assert.Nil(t, err, "should not error")
assert.False(t, home, "'home.netscape.com' should not be as it contains a domain part")
}

func TestRuntimeIsResolvable(t *testing.T) {
rt, _ := newRuntime()

localhost1, err := callBooleanFunction(rt, "isInNet", "localhost", "127.0.0.1", "255.255.255.255")
assert.Nil(t, err, "should not error")
assert.True(t, localhost1, "'localhost' should equal 127.0.0.1 with the mask 255.255.255.255")

localhost2, err := callBooleanFunction(rt, "isInNet", "localhost", "127.0.0.0", "255.0.0.0")
assert.Nil(t, err, "should not error")
assert.True(t, localhost2, "'localhost' should equal 127.0.0.1 with the mask 255.0.0.0")

localhost3, err := callBooleanFunction(rt, "isInNet", "localhost", "127.0.0.0", "255.0.0.255")
assert.Nil(t, err, "should not error")
assert.False(t, localhost3, "'localhost' should not equal 127.0.0.1 with the mask 255.0.0.255")
}

func TestRuntimeDnsResolve(t *testing.T) {
rt, _ := newRuntime()

localhost, err := callStringFunction(rt, "dnsResolve", "localhost")
assert.Nil(t, err, "should not error")
assert.Equal(t, localhost, "127.0.0.1", "'localhost' should equal 127.0.0.1")
}

func TestRuntimeDnsDomainLevels(t *testing.T) {
rt, _ := newRuntime()

www, err := callNumberFunction(rt, "dnsDomainLevels", "www")
assert.Nil(t, err, "should not error")
assert.Equal(t, www, 0, "'www' should contain 0 domain levels")

netscape, err := callNumberFunction(rt, "dnsDomainLevels", "www.netscape.com")
assert.Nil(t, err, "should not error")
assert.Equal(t, netscape, 2, "'www.netscape.com' should contain 2 domain levels")
}

func TestRuntimeShExpMatch(t *testing.T) {
rt, _ := newRuntime()

ari, err := callBooleanFunction(rt, "shExpMatch", "http://home.netscape.com/people/ari/index.html", "*/ari/*")
assert.Nil(t, err, "should not error")
assert.True(t, ari, "'http://home.netscape.com/people/ari/index.html' should match '*/ari/*'")

montulli, err := callBooleanFunction(rt, "shExpMatch", "http://home.netscape.com/people/montulli/index.html", "*/ari/*")
assert.Nil(t, err, "should not error")
assert.False(t, montulli, "'http://home.netscape.com/people/montulli/index.html' should not match '*/ari/*'")
}

0 comments on commit 3b0a66d

Please sign in to comment.