wiki:ObjectReference

Object reference

There are 4 types of scripts running inside GlimmerBlocker, and some objects are only defined for some of the script types:

  • global proxy: this sets the global proxy settings, and can test for e.g. location name, AirPort network.
  • request modification: this can change the requested URL, send back a redirect response to the browser, or send text/html back to the browser.
  • keyword expansion.
  • transform: modify the response received by the web-server before it is sent back to Safari.

Sections:

  • general: logging, debug flags
  • request
  • response
  • content modification
  • network state
  • other considerations

General objects

These objects and functions are defined for all script types.

gb.log("I had %d birds and a %s dog", 42, "black");
// Logging to the console (use the "Open Log" button on the developer tab).
// The first parameter is a format string just like console.log() in Firebug:
//   %s: string
//   %o: dump the object in JSON-like format (no escape of keywords, supports NaN).
//   %d: decimal (no formatting yet)
//   %f: floating point (no formatting yet)

gb.dlog(...);
// same parameters as gb.log(), but logs only when the proxy server debug logging
// (gb.debug.enabled) is enabled.
// The parameters will still be evaluated, so this is only for simple logging.

var s = gb.versionString;
// contains the current GlimmerBlocker version, Read-only.
s = "1.3.5b20";

var i = gb.versionCompare(v);
// compares the version to v, and returns -1, 0 or 1. Use this for testing GB versions, e.g. 
if (gb.versionCompare("1.3.5b20") >= 0) fancyStuff();

var b = gb.debug.enabled;
var b = gb.debug.verbose;
var b = gb.debug.httpServer;
var b = gb.debug.httpClient;
var b = gb.debug.networkConfig;
var b = gb.debug.filters;
// flags which tells the state of the proxy server debug checkboxes.  Read-only booleans.

var s = gb.stringify(obj);
// converts the object into a JSON-like string using same format as %o in gb.log()

var html = gb.htmlEncode("Paul & Allan says '1 < 2'.");
// Encodes some text as html. The example returns
html = "Paul &amp; Allan says '1 &lt; 2'.";

var html = gb.attrEncode("Paul & \"Spooky\" says '1 < 2'.");
// Encodes some text as html attribute value, but without quotes.
// The example returns
html = 'Paul &amp; &#34;Spooky&#34; says &#39;1 &lt; 2&#39;.';

var a = "value=" + gb.attrQuote("simple");
var b = "value=" + gb.attrQuote("Paul & \"Spooky\" says '1 < 2'.");
// Encodes some text as html attribute value including quotes, if required.
// The example returns
a = 'value=simple';
b = 'value=\'Paul &amp; "Spooky" says &#39;1 &lt; 2&#39;.\'';
b = "value='Paul &amp; \"Spooky\" says &#39;1 &lt; 2&#39;.'"; // equivalent to the above

var ss = gb.urlEncode(s);
// encode a string with %-escapes.  Similar to escape() and encodeURIComponent() in browsers.
// gb.urlEncode("Hello, D'Angleterre") -> "Hello%2C%20D%27Angleterre"

var s = gb.urlDecode(ss);
// decodes a string with %-escapes: opposite of gb.urlEncode()
// gb.urlDecode("Hello%2C%20D%27Angleterre") -> "Hello, D'Angleterre"

var js = gb.jsEncode(s);
// encode a string to be a Javascript string token:
// gb. jsEncode(null) -> "null"
// gb. jsEncode("Hello, D'Angleterre") -> "'Hello, D\x27Angleterre'"
//           OBS: the result includes single quotes.

The gb.request object

Script types:

  • request-modification rules: defined and modifiable.
  • transformation rules: defined, but read-only as the request already has been executed.
  • keyword rules: defined, but read-only as the request is never forwarded to a web-server.
  • global proxy script: not defined.
var s = gb.request.url; // the full URL of the request
s = "http://www.google.com/search?q=apple";

var s = gb.request.urlHost;
// only the host part of the URL
s = "www.google.com";

var port = gb.request.urlPort;
// only the portnumber of the URL
port = 80;

var s = gb.request.urlHostPort;
// the host and port, separated by colon.
s = "www.google.com:80";

var s = gb.request.urlPath;
// only the path part of the URL, excl. query. Never empty, starts always with "/".
s = "/search";

var s = gb.request.urlQuery; // only the query path of the URL, excl. query. Never null.
s = "q=apple";

var s = gb.request.method; // Changing the method easily breaks everything.
s = "GET";

var s = gb.request.referer;
s = "http://ifixit.com"; // The referer header. Might be null.

var s = gb.request.contentType;  // The full content-type of the *request*, not the response.
s = "application/x-www-form-urlencoded"; // Typically null.

var s = gb.request.baseContentType;  // Content-type without any semicolon-options.
s = "application/x-www-form-urlencoded"; // Typically null.

var h = gb.request.headers;
// returns a Javascript object which contains all the request headers.
// The attribute name is the proper mixed-case name of the header (e.g. "User-Agent"),
//    and the value is an array of strings.
// If you assign to gb.request.headers["uSeR-aGeNt"],
//    it will still set the attribute "User-Agent".
// If you set an attribute to null or an empty string, the attribute will be deleted.
// Tip: use gb.log() to see the headers:
gb.log("h = %o", gb.request.headers);
// will log something similar to:
h = {
    Cookie:['BookCusCountry=DK'],
    'User-Agent':['Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6; en-us) ...'],
    'Accept-Encoding':['gzip'],
    'Accept-Language':['en-us'],
    Host:['glimmerblocker.org'],
    Accept:['*/*']
};

var s = gb.request.clientAddr;
// returns client ip address as dotted decimal in a Javascript string.
s = "10.1.2.3";

var s = gb.request.clientHostname;
// returns hostname for client ip address using reverse dns lookup
s = "dhcp42.internal.company.com";

Changing any of the gb.request attributes in a request-modification script makes GlimmerBlocker use the new values when getting the content from the server. So if you change gb.request.url, it will not result in GlimmerBlocker sending back a redirect response to Safari. Instead, the new url will be used when getting the content from the server, e.g. a completely different server. So you can make Safari think it fetches one URL, but in reality show content from a completely different URL. If you want to make a redirect, use gb.response.sendRedirect('...');

You cannot assign a new object to gb.request.headers, only change attributes of gb.request.headers: See the 'other consideration' section at bottom of this page.

The gb.response object

Script types:

  • request-modification rules: defined, but shallow.
  • transformation rules: defined.
  • keyword rules: defined, but shallow.
  • global proxy script: not defined.

If shallow, the object contains an empty dummy response with status = 200 and empty text/html content.

If the shallow response header is modified, and/or the global t object is set to a non-empty string, that will be used as a response and the web-server will not be contacted. You can use this as an advanced blocker which returns a "<script>window.close();</script>" response which closes pop-unders. This is how the gb.response.sendRedirect() method works: it just modifies the header, but doesn't do any "send this back to Safari" magic behind the scenes.

var i = gb.response.status;
// http status code, e.g. 200 or 404. Integer.

var s = gb.response.statusMessage;
// http status message, e.g. "OK" or "Not found".

var s = gb.response.contentType;  // The full content-type, including any charset option.
s = "text/html; charset=UTF-8";

var s = gb.response.baseContentType;  // The base content-type without any options.
s = "text/html";

var h = gb.response.headers;
// returns a Javascript object which contains all the response headers.
// The attribute name is the proper mixed-case name of the header (e.g. "Cache-Control"),
//    and the value is an array of strings.
// If you assign to gb.request.headers["cAchE-cOntRol"],
//    it will still set the attribute "Cache-Control".
// If you set an attribute to null or an empty string, the attribute will be deleted.
// Tip: use gb.log() to see the headers:
gb.log("h = %o", gb.response.headers);
// will log something similar to:
h = {
    'Cache-Control':['max-age=600'],
    Expires:['Sat, 13 Jun 2009 19:06:37 GMT'],
    'Accept-Ranges':['bytes'],
    Server:['Apache/2.2.9 (Unix)'],
    'Content-Type':['text/html; charset=UTF-8']
}

You cannot assign a new object to gb.response.headers, only change attributes of gb.response.headers: See the 'other consideration' section at bottom of this page.

gb.response.sendRedirect(url);
// Modifies the response so it becomes a simple redirect:
// gb.response.status  = 302,
// gb.response.statusMessage = "Redirected to...";
// gb.response.headers['Location']  = url;
// gb.response.headers['content-type'] = 'text/plain';
// t = "Redirected to...";
// All the other headers are kept as-is.

gb.response.sendHtml(html);
// Sets response to a simple text/html response:
// gb.response.status  = 200
// gb.response.statusMessage = "OK";
// gb.response.headers['Location']  = '';
// gb.response.headers['content-type'] = 'text/html';
// t = html;
// All the other headers are kept as-is.

gb.response.sendText(txt);
// Like sendHtml, but uses content-type = text/plain.

gb.response.sendUnknownHostErrorPage(host);
// Sets response to GlimmerBlocker's "host not found" error page.
// The host argument is used for the search entry.

gb.response.sendCantConnectErrorPage(host);
// Like sendUnknownHostErrorPage(), but message is
// "Can't connect to host".

Content modification

Because content modification often is performed using multiple Javascript statements, the text content is stored in the global variable t to avoid unwieldily long statements.

Global utility functions:

replace(/regexp/, "some text");
// is a shorthand for:
t = t.replace(/regexp/, "some text");

Utility functions in the gb object:

gb.zapScriptElements();
// removes all <script>..</script> elements from t.

gb.zapStyleElements();
// removes all <style>..</style> elements from t.

gb.zapIframeElements();
// removes all <iframe>..</iframe> elements from t.

gb.addScriptElement(contents);
// Adds a <script>contents</script> element in t just before the </body> tag
// (i.e. end of document).

gb.addStyleElement(contents);
// Adds a <style>contents</style> element in t just before the </head> tag
// (i.e. end of header so it overrides loaded stylesheets).

gb.setDocumentTitle(txt)
// Updates/creates the <title>...</title> element with the new text.
// The argument is automatically html-encoded,
// so you don't need to care about <, > and &.

gb.insertAtHeadStart(contents);
// Inserts the contents just after the <head> tag.
// Useful for adding <meta..> tags.

gb.insertAtHeadEnd(contents);
// Inserts the contents just before the </head> tag.
// Useful for adding external stylesheets, scripts, etc.

gb.insertAtBodyEnd(contents);
// Inserts the contents just before the </body> tag.
// Useful for adding external scripts, etc.

var hostPrefix = gb.attachmentDownloadHostPrefix();
// returns a "download as attachment" hostname prefix.
// The servlet takes two parameters:
//   1) url:  the absolute URL of the file to download.
//   2) filename: the filename which Safari should use.
// The servlet fetches the content at the URL and forwards it to Safari, but adds
//    a "content-disposition" header so the file always is downloaded as an attachment.
// The servlet checks the content-type header sent by the server
//    and changes the filename to match it.
// The reason for using a host prefix instead of a static domain such as
//    'glimmerblocker.test' is to get Safari send the cookies for the domain.
// See YouTube download filter for example.
a.href = "http://" + hostPrefix + ".example.com" +
  "?url=" + escape("http://example.com/thingy.flv") +
  "&filename=" + escape("weird-movie.suffix");
// The prefix is unique for each GlimmerBlocker installation.

Network state

The gb.network object is documented on the Proxies page. It tells the state of the network interfaces (e.g. ip-address and AirPort network name), and allows you to specify a nested http/socks proxy, and to use a different dns server than the Mac's default.

Other considerations

The gb.* objects are magic objects and not normal javascript objects. This is similar to special javascript objects in browsers, e.g. location.href = "http://ruc.dk" doesn't just assign a value, but makes the browser load a new page.

// This doesn't work in a browser:
var s = location.href;
s = "http://ruc.dk"; // only 's' gets a new value, location.href is untouched.

// This doesn't work in GlimmerBlocker
var s = gb.request.referer;
s = "http://ruc.dk"; // only changes 's', the referer is unchanged.

// This works:
location.href = "http://ruc.dk"; // in a browser
gb.request.referer = "http://ruc.dk"; // in GlimmerBlocker

//  OBS: you cannot replace full sub-objects in gb.*, e.g.
gb.response.headers = { "Location":"http://ruc.dk", "User-Agent":"Mine"};
// and you must change each attribute separately, like this:
gb.response.headers["Location"] = "http://ruc.dk";
gb.response.headers["User-Agent"] = "Mine";

Each script uses its own global scope in Javascript, so a script is not able to see nor modify variables used by other rules. GlimmerBlocker caches the last 25 executed scripts to optimize performance: the compiled version of the script and the its scope (i.e. global variables). There is no support for persistence whatsoever.

The request & response flow.

GlimmerBlocker uses the Rhino Javascript runtime with the language level set to 1.7

If you find any errors, omissions, or have any helpful comments to improve the documentation, please send email to: [feedback@glimmerblocker.org]

Last modified 15 months ago Last modified on 10/09/13 15:38:26