termlib-Socket Sample
This page demos the termlib.js socket extension for client-server communication via asynchronous XMLHttpRequests (commonly known as AJAX).
The socket extension provides a tight integration for all XMLHttpRequest tasks that would commonly occur in a real world application.
All you have to do, is call the send( <options> ) method and return. The request (might it succeed or fail) will come back to your callback-handler with your Terminal instance set as the this object.
example:
// assume we are inside a handler
// ("this" refers to an instance of Terminal)
this.send(
{
url: "my_service.cgi",
method: "post",
data: myDataObject,
callback: mySocketCallback
}
);
return;
function mySocketCallback() {
if (this.socket.succes) {
// status 200 OK
this.write("Server said:\n" + this.socket.responseText);
}
else if (this.socket.errno) {
// connection failed
this.write("Connection error: " + this.socket.errstring);
}
else {
// connection succeeded, but server returned other status than 2xx
this.write("Server returned: " +
this.socket.status + " " + this.socket.statusText);
}
this.prompt()
}
The send() API:
As send( <options> ) is called the socket library creates a XMLHttpRequest, collects and escapes the provided data, executes any initial tasks, and sends the request.
All settings are transfered via a single options-object containing one ore more of the following options:
url |
the request url, must be on the same host (default "") |
method |
request method (GET or POST; default GET) |
data |
request data (default ""), may be of any type, preferably an object with key-value pairs.
the data is serialized and escaped for you by the library. (Please note that there might be unexpected results with nested objects or arrays. By the way: arrays are serialized as comma separated lists.) For complex data structures use a XML-object (true AJAX, see below).
The resulting string will be either appended to the request url (GET) or used as post-body.
|
callback |
the callback-function to handled the response |
advanced settings: |
postbody |
Use this for true AJAX (e.g. sending a XML-object to the server)
If a postbody option is supplied, this will change the behavior as follows:
1) the request method is forced to "POST"
2) the postbody will be used instead of any supplied data object
3) the postbody will be transmitted as is (no serializing or escaping) |
|
(Note: The creation and parsing of XML-objects is out of the scope of this document and termlib.js and is therefor left entirely up to you.)
|
userid |
optional user-id for implicit login (transfered without encryption!) |
password |
optional password for implicit login (transfered without encryption!) |
mimetype |
optional MIME-type to override the response's default MIME |
headers |
optional object (key-value pairs) of HTTP-headers to be included in the request |
getHeaders |
optional array (or object with labels as keys) of HTTP-headers to be extracted from the response |
timeout |
optional individual timeout in msecs for this request (default: 10000) |
send() will add a parameter "_termlib_reqid" with a unique id to every GET request that doesn't target the local file system (sent from pages with the "file:" schemes). This additional parameter ensures that MSIE (MS Internet Explorer) will truly fetch the requested document instead of serving it from its cache.
A word on local requests:
Please note that local requests (from and to the local file system) won't work with MSIE 7. (Sorry, ask Bill.) This MSIE 7 error will be captured as connection error with errno 2 ("Could not open XMLHttpRequest.").
If a browser requests a local document that does not exist, a 404 (Not Found) status code will be generated by the library and the errno property will be set to 5 ("The requested local document was not found.").
Global Config Settings:
There are a few global settings in Terminal.prototype._HttpSocket.prototype (the prototype of the internal socket object used by the library), which define some default values:
useXMLEncoding |
Boolean flag (default: false) for parameter delimiters
if false, parameters will be delimited by "&".
if true, parameters will be delimited using ";" (new XML compatible syntax).
|
defaulTimeout |
Number of ticks (milliseconds, default: 10000 = 10 sec) for request timeout, if not specified else. |
defaultMethod |
String (default: "GET"); request method to use, if not specified else. |
forceNewline |
Boolean flag (default: true): translate line breaks in the responseText to newlines (\n). |
The Callback (Response Handling):
Any request issued by send() will trigger the handler specified by the callback option (or a basic default-handler). The callback will be called in any case, should the request succeed, timeout or fail otherwise.
All response data (and some of the request data) is provided in a temporary "socket object for your convenience. (This temporary object will be discarded just after the callback returns.) As the this object points to your instance of Terminal, this object will be available as "this.socket" inside your callback-handler.
Properties of the socket object:
status |
the HTTP status code (e.g.: 200, 404) or 0 (zero) on timeout and network errors |
statusText |
the HTTP status text (e.g.: "OK", "Not Found") |
responseText |
the transmitted text (response body) line breaks will be normalized to newlines (\n) if _HttpSocket.prototype.forceNewline == true (default behavior) |
responseXML |
the response body as XML object (if applicable) |
success |
a simple boolean flag for a 2xx OK response |
headers |
object containing any HTTP headers (as key-value pairs) of the response,
which where requested by the "getHeaders"-option of the send().
the header-labels are unified to "camelCase"
e.g.: "Content-Length" will be in headers.contentLength |
stored request data: |
url |
the request url as specified in the send() options. |
data |
the data you called send() with |
query |
the composed query-string or postbody as transmitted to the host |
method |
the request method |
errno |
the internal error number (0: no error) |
errstring |
the internal error message ("": no error) |
Some of the response specific data (as status codes, or headers) might not be present with local connections.
Connection errors are classified with the following errno and errstring values:
errno |
errstring |
|
label |
0 |
"" |
|
OK |
1 |
"XMLHttpRequest not implemented." |
|
NOTIMPLEMENTED |
2 |
"Could not open XMLHttpRequest." |
|
FATALERROR |
3 |
"The connection timed out." |
|
TIMEOUT |
4 |
"Network error." |
|
NETWORKERROR |
5 |
"The requested local document was not found." |
|
LOCALFILEERROR |
The labels are implemented as key-value pairs in Terminal.prototype._HttpSocket.prototype.errno (type "object").
Error codes (errno) are also accessible as this.socket.ErrorCodes at run-time.
example:
// assume we are inside a handler
if (this.socket.errno == this.socket.ErrorCodes.TIMEOUT) {
this.write("Oops, the request encountered a timeout.");
}
Inside an interactive terminal session you'll usually want to return just after send() and call prompt() at the end of your callback-handler.
This way the terminal will keep blocked until the callback is finished.
Aside from this, the socket extension provides also the means for background tasks (e.g. storing temporary status on a server etc.) that do not need visual feedback or user interaction. Since the requests are performed and handled asynchronous and object oriented, both will go side by side.
Norbert Landsteiner Vienna, 2007/03 Updated 2010/01
|