The AUTOPROXY module implements a Netscape technology: "Automatic proxy configuration through JavaScript".
The general idea is that there exists a special script that the browser loads. Every time the browser tries to load a URL, the script is run and returns information about how to go about fetching the document at that URL: whether to connect directly to the host, or to connect through a proxy. In the latter case, the script also returns information about the proxy to use.
The technology is popular in large companies, which can use it to balance traffic among multiple proxies or to different proxies at different times of the day.
The proxy script is a JavaScript source file defining a global
function FindProxyForURL that takes some specific
arguments and returns some specific values; it is described in Netscape's documentation.
In the (Windows) preferences UI, go to the "Network" panel, click the "Proxy servers" button, and at the bottom of the dialog check the box for "Use automatic proxy configuration" and enter a URL to the proxy configuration script in the box below it. Then "OK" your way out.
Power users may edit the "[Proxy]" section of opera6.ini, like this:
[Proxy] Use Automatic Proxy Configuration=1 Automatic Proxy Configuration URL=file:///C:/mydir/myautoproxy.pacThe ".pac" extension is traditional, though other extensions are known (".jsc", for "JavaScript Configuration").
If Opera is compiled with
SUPPORT_AUTO_PROXY_CONFIGURATION (controlled by the feature FEATURE_AUTO_PROXY_CONFIG) then the
proxy-determining code in URL_DataStorage will consult
the autoproxy module about a configured proxy for some URLs. Exactly
which URLs is determined by clients of this code (ie, the URL
module).
The following policies are currently in effect, implemented partly by the autoproxy module and partly by the URL module:
If the autoproxy URL cannot be loaded, then autoproxy functionality is disabled until the autoproxy preferences are changed. (FIXME: It is a known bug that Opera reports that Proxy Configuration will be disabled for the rest of the session. This is the old behaviour)
If the autoproxy script contains a syntax error, then an error is posted to the JS console with information about the location of the error, autoproxy functionality is disabled until the autoproxy preferences are changed. (FIXME: It should also be reloaded if the script is changed)
If the autoproxy script throws an unhandled exception at run-time, then the exception is posted to the JS console, autoproxy functionality is disabled until the autoproxy preferences are changed.
If the autoproxy script accesses network functionality while it is being initialized, then autoproxy functionality is disabled until the autoproxy preferences are changed. (FIXME: It doesn't say why it was disabled; this sounds like a bug.)
Buggy scripts are handled by cutting them off after a fairly large number of computation steps (currently 10 million steps). A script that fails with an error will cause the URL not to be loaded at all.
Autoproxy bugs are flagged with the string [AUTOPROXY] in the Summary field and usually have the component "Proxy".
API documentation generated by Doxygen contains all necessary information.
Implementation documentation generated by Doxygen contains what you need to know.
The module is small and can be disabled completely.
Older versions of autoproxy stores the proxy configuration library as a unicode string (probably about 20KB) in the library itself. Newer versions store this library in compiled form, thus reducing footprint.
Since the autoproxy module runs as a client of the URL module, it generally uses the same OOM outward signalling mechanisms as the URL module.
An OOM result is generally signalled through a call on
MemoryManager::RaiseConditionUAPCL::Load()
Internally in the module OOM is usually handled by propagating OP_STATUS values.
Whoever created the load handler and called
UAPCL::Load() on it must be prepared to handle OOM,
signalled as described above. The autoproxy module only performs
local cleanup, making sure that things remain consistent and
leak-free. Generally the responsibility falls on the URL module.
All entry points to the module are through
UAPCL::Load()UAPCL::HandleCallback(); follow the flow from there, into
UAPCL::ExecuteScript(). It's straightforward.
Also see the general implementation description, above.
The module itself allocates very little: only a few small objects to hold data temporarily. But it does use the ECMAScript engine, which can allocate quite a lot. Autoproxy creates one global ES_Runtime, as well as one ES_Context per request, to run requests.
The autoproxy module caches an ES_Runtime, and this may prevent some memory from being freed even if all windows are closed. See "Caching and freeing memory" below.
The module itself uses no recursive calls and no stack-allocated arrays or large objects. It calls the ECMAScript engine and the URL layer; they may use more. Locally in the module I'd say that less than 50 words of stack memory are live in the worst case on a system with a dense processor stack (like x86).
The module currently has three global variables (total of three words of memory).
One ES_Runtime is cached by the module and may hold onto some usually not very large amount of memory (though there are no bounds on how much memory a runtime can reference.)
The caches can be cleaned out by calling the global function
ReleaseAutoProxyResources(). It is safe to call this
function at any time. If there are no pending autoproxy requests,
this will release all dynamic memory that is currently held by the
module. In order to actually free memory held by the ECMAScript
environment, it may be necessary to run a garbage collection; the
autoproxy module does not do that.
The function ReleaseAutoProxyResources() must be
called on exit before the ECMAScript environment is destroyed.
One of the methods in the autoproxy module is using the buffer
returned from MemoryManager::GetTempBuffer(). There is no
check on whether this buffer is used outside the module. (Reuse of
the buffer internally is not a problem: this is the only place in the
code that uses the temp buffer, and the code does not call any
interesting functions.) It would be trivial to allocate a temporary
string on the heap to serve the same purpose.
No known opportunities in the module proper.
There are no tests, since memory use is fairly trivial.
If the deallocation function is not called before Opera exits, one will get an assert in the ECMAScript engine when that is destroyed.
Running the selftests for the module (see comments in
testsuite/autoproxy.ot for detailed description; it is
more than running with -test) should exercise most of the
code.
One trade-off has been made: an ES_Runtime is cached, to avoid having to recreate it for every URL lookup. This means that RAM use is higher than the theoretical minimum. It is probably the case that it is not practical to avoid at least some kind of caching.
There are no other known tradeoffs.
There are no planned improvements. All known improvements would come as a result of the ECMAScript engine improving its memory use.
The performance of the module is largely dependent on the performance of the ECMAScript engine.
The important things that happen in the autoproxy module are:
Reading the autoproxy script from a URL, creating a runtime for it, and compiling it.
These operations are performed whenever the script changes.
Running a FindProxyForURL request. This consists of compiling a small script, creating a context, and running the script for a quantum. If the script finishes within its first quantum (most do) then it takes no penalty; otherwise, it is rescheduled to run in 50ms.
FIXME: Here the time may well be dominated by invoking the compiler. We can avoid running the compiler by instead looking up the function and calling it directly.
FIXME: The 50ms reschedule is usually too long; if we could use the standard scheduler we could do better.
Performing name lookups.
Name lookups are synchronous for the script that invokes them, but take no time per se except waiting for the lookup to complete.
Executing proxy library functions: shExpMatch and the like.
shExpMatch is written in C and is probably not a
bottleneck. The other library functions are written in
JavaScript, but they are generally simple and it is not clear they
should be a problem. With the new ECMAScript compiler they should
be faster still.
ECMAScript module
ECMAScript utilities module
Netscape's original documentation (local copy)
A revised version of Netscape's documentation that include some design choices (local copy)
Module repository page (Wiki)
ECMAScript 3rd edition (external)
$Id$