Opera Unite JavaScript API

Jul1509Jul 15, 09

I've been taking a close look at what's happening in the early stages of Opera Unite's adoption. People seem to like it, but nobody I have spoken with has committed to maintaining their Unite server presence. That said, I think the opportunity is on us for some really cool web apps powered by users' computers instead of our own servers and bandwidth. I've been extremely busy working on amoebaOS recently as things are being prepared for the initial public release, so for the sake of brevity I thought it would be useful to post the documentation for Opera Unite's JavaScript API here. This was pulled from the JavaScript example file as posted on opera.com - I wanted to re-post it, because their version does not render as an HTML document (it is contained within the JavaScript code).

Opera Unite Web server APIs

This API document describes the JavaScript bindings for the Opera Unite Web Server, available through Opera Unite services.

Unite services are packaged like Opera Widgets with a config.xml file.

Note that no methods in this API return actual arrays. Instead they return objects whose properties can be iterated over in an array style syntax, i.e.array[i]. Methods like push(), shift(), sort(), and so on are not available. [my note: you can still use these Array methods by calling Array.prototype.push.apply(apiResponse,[newItem]); ]

Enabling the Web server API

In order to make the file system and its methods available, you need to add a feature element to your config.xml file like this:

<feature name="http://xmlns.opera.com/webserver">
<param name="servicepath" value="chat" />

The servicepath parameter is required and defines the path the service will be accessed from. See the note on service URLs for more information.

The entry point to the API becomes available as a JavaScript object opera.io.webserver.

Opera Unite services and URLs

Opera Unite users may start a Web server on different devices running Opera, for example on a home and work computer, a living room media center and a mobile phone. The user may deploy a set of services on each Web server. A service is typically a single application, for example a file sharing service or a multiplayer chess service. Services can accessed on the following general URL:


For example:


The username is the user's My Opera username.

The device name is whatever the user has chosen when enabling the Web server. It's tied to one instance of Opera.

The proxy is a server run by Opera, proxying requests between servers and clients.

The service, or service path, is the IRI name of the service, as defined in config.xml.

The path represents a file or instruction the service will handle.

Note that only valid IRI characters can be used as part of the device name, username and service name.

Working with requests and responses

The function of a Web server is to listen to requests from clients, process them and issue a response, for example send a Web page or the result of a script. Requests occur when the user visits a particular service URL. The request may contain form data, send via GET and POST and uploaded files.

In the case of the Opera Unite Web Server you listen to requests from clients by adding event listeners to the opera.io.webserver object:


The path corresponds to the first path component in the URL after the service name, for example:


In this case, if the user visits the URL


The service will pick it up and call the supplied addHandler function.

Handler functions are passed a {@link WebServerRequestEvent} object as an argument. This event object gives access to the incoming connection ({@link WebServerConnection}), the incoming request ({@link WebServerRequest}), and the response ({@link WebServerResponse}) the author can write data to. The addhandler could look something like this:

function addHandler(e)
var req = e.connection.request;
var res = e.connection.response;

//Get article from POST data
var article = req.bodyItems['article'][0];

//...Store the article data

//Write a response back to the client
res.write('Article updated');


Data sent as GET are available in the queryItems property of the request. Data sent as POST are available in the bodyItems property. The body of the request is also available in the raw form in the body property. If files were attached, these are available in the files property of the request.

The response object has methods for sending different kinds of data, for example writeImage() and writeFile().

You may supply a custom protocol string, status code and headers, but these must be set before data is written to the response.

Note that requests may not begin with '_', as this is reserved for special, system generated events.

Special requests: _index, _request, _close

The Web server supports three special requests.

This request occurs when a user visits the root of the service, e.g. http://work.john.operaunite.com/share. If you do not listen for this request, the file public_html/index.html will be served when the user visits the root of the server.
This is a special request that catches all incoming requests, except for _close. Use this to gain fine grained control of the requests made to the server. You'll need to use {@link WebServerRequest#uri} to differentiate between different requests. This request also catches _index, but not _close.
This request occurs when a connection is closed. The connection property of the resulting event is a dummy object, while the id property contains the id of the closed connection.

If the developer adds event listeners for both _request and some specific path, the event handler for the specific path will be called before the _request handler. Handlers for _index are also fired before _request.

Redispatching requests

You can redispatch a request to a new URI by changing the {@link WebServerRequest#uri} property and calling the {@link WebServerResponse#closeAndRedispatch} method. This is useful for example for correcting commonly mistyped URLs, chaining requests and providing authentication across the entire service. For example:

if ( ! authenticated )
request.uri = opera.io.webserver.currentServicePath + 'loginform';

And headers, GET or POST data in the original request are sent along with the redispatched request.

Note that uri must be set to a relative URI path, starting with '/' and the name of the service (the {@link opera.io.webserver#currentServicePath} property), potentially followed by more path components, for example '/blog/add'.

If a request is redispatched, none of the special event handlers, like _request will be fired.

Requests and files

If an incoming request URI matches a shared file or a file in public_html, the file will be served.

However, if you listen for the _request event, even requests to files will be intercepted. In order to serve the file, you'll need to call {@link WebServerResponse#closeAndRedispatch} without changing the URI.

Sharing files

You can share files from a local disk through your Web server. Use the {@link opera.io.webserver#shareFile} and {@link opera.io.webserver#unshareFile} methods. The first takes two arguments - a File object retrieved using the File I/O API, and the name used to share it on the web.

Here's an example:

//mount a directory using File I/O, get a reference to it called 'dir'

Assuming the device is called 'work', the user is called 'john' and the service is called 'fileSharing', the directory will now be available on the URL http://work.john.operaunite.com/fileSharing/myShare.

Note that for security reasons the contents of a directory is not listed automatically. You'll need to listen for the name of the share as a request, and serve a listing to the client yourself. You may still access files under the shared directory, for example:


Uploading files

You can upload files using a normal file upload form. Once uploaded, the file will be available in the {@link WebServerRequest#files} property. This is a special File object that functions like a directory. You can iterate through it to locate your uploaded file.

The File object and its children will be deleted when the request object goes out of scope. You must make sure to read it or copy it before this happens.

for ( var i = 0, file; file = request.files[i]; i++ )
file.copyTo('/storage/' + file.name);

The value of the name property of the File object will be the same as the file name the uploaded file had on the user's disk.

Each uploaded file has a metaData property, which contains a dictionary of headers for that uploaded file.

Working with cookies

You can set cookies using the Set-Cookie header as you would for a normal Web page. Note that if you do not specify a path, the Web server will set it to the path of the current service. For security reasons, you are not allowed to set cookies for just the operaunite.com host itself. Cookies cannot be shared among services.

The unite:// URL protocol and WebServerRequest.isOwner

In order to allow administration of the service, the service developer will need to be able to positively identify a user as the owner of the service.

All links to pages generated by the service can be expressed as unite://[path] rather than http://[path]. Such a link will give the user a security error if it is not followed from a page in the same instance of Opera that is runing the service.

Such URLs can also be opened from the native UI, or from the root service page. In other cases, Opera will show a dialogue asking the user to confirm that he or she wants to log in and administrate the running service.

In cases where the service is accessed through unite://, the corresponding {@link WebServerConnection} object will have its isOwner property set to true. Service developers can check this property and provide an administration interface.

@author Hans S. Toemmerholt, Web Applications, Opera Software ASA

About Jason Miller:

I am a JavaScript developer from Waterloo, Ontario, Canada. When I am not typing green code onto a black screen, you might find me at the nearest coffee pub checking out the brew. I run a internet firm called developIT and maintain blogs and web apps when I can.
Leave a Comment

Post Comment