HTTP-Gateway

From CommonJS Spec Wiki
Jump to: navigation, search

This is an interface used by any http gateway handler. A handler's job is to talk with a webserver (or act as one) in some way (mod_ handler, CGI handler, FastCGI handler, built-in http server, Servlet handler, etc...) and provide an api conforming to this spec which it makes a call to the gateway using app with to handle the http request and response.

The API used in this spec was designed arround an inverted XMLHttpRequest object, with some high-level things removed, static content properties and events converted to streaming, and some server functionality patterns from the JSGI/Rack/WSGI group of protocols. Middleware is NOT a target of this spec, middleware is a semi-high level funcationality, this spec's target is low-level functionality only. Middleware can be implemented inside of a gateway interface built on top of this gateway interface written in pure-js (ie: You can write JSGI entirely using this http-gateway, heck you could write a node compatible API port using this http-gateway).

This API is independent of sync or async code. It works purely on a streaming basis. The implementation is expected to:

  1. read the status line and the headers (or grab them from whatever api)
  2. look for a content-length header and use it to wrap the input stream (or make the input stream return EOF right away if no content-length is present)
  3. wrap the output stream in this api
  4. then pass it to the gateway app

Once the api leaves the gateway handler control over the response is completely up to the gateway app. It is the gateway app's responsibility to end the request by calling .close(); The function returning signifies nothing to the handler other than the gateway being ready to accept another request. So it doesn't matter to the handler whether the gateway app is streaming or doing some other action asynchronously.

Quick Overview

exports.(app|gateway?) = function(r) {
	r.gateway.version = [1, 0];
	r.gateway.multithread;
	r.gateway.multiprocess;
	r.gateway.runonce;
	r.env; // An object containing various pieces of data from the server;
	       // Env variables for CGI, passed faux env for FastCGI, handler dependant on other types of handlers.
	r.connected; // boolean true, will change to boolean false if the client has disconnected
 
	// Request (all keys must be present and of the correct type)
	r.method === "GET"; // must be uppercase string
	r.scheme === "http"; // must be lowercase string
	r.serverName; // string; ip, static hostname, etc... (NOT the value of the Host: header)
	r.serverPort; // 80, etc...
	r.scriptName; // String coresponding to the application location. "" if at site root, string starting with / otherwise. (decoded)
	r.pathInfo; // ... (decoded)
	r.queryString; // string
	r.getRequestHeader('Content-Type');
	r.read(#);
	r.read();
 
	// Response
	r.status = 200;
	r.statusText = "OK"; // optional status text. Some handlers may ignore this,
	                     // handlers should understand the relation of basic http status codes
	                     // to their status text in some way (even if that is allowing apache or something else handle that)
	r.addResponseHeader('Content-Type', 'text/html'); // Should throw an error if .flush() has already been called.
	r.write(data); // First call implies a call to .flush()
	r.flush(); // Flushes buffered data if buffering is used and flushing is possible;
	           // First call sends status and headers through handler and signifies finalization of them, rejection of headers after that is enforced.
	r.close();
};

API

connected
A boolean indicating if the client is still connected. Checking this periodically is useful to understand if you should abort what you are doing.
method
The method of request used as an uppercase string.
scheme
The protocol used in the request as a lowercase string. This is normally only ever "http" or "https".
serverName
serverPort
scriptName
(decoded)
pathInfo
(decoded)
queryString
The query string from the response.
getRequestHeader(headerName);
read(max);
status
The numeric http status code to return. This is the only necessary interface for defining the return status. The handler must map the standard HTTP numeric status codes to their default status text.
statusText
An optional extra interface to the status text. You may set this to override the status text printed beside the status code. This interface is not necessary for use for the standard http headers, the handler must know how to map status codes to status text when overrides are not specified.
Note that some handlers may ignore this property if the system they connect does not provide a way to set the status text.
addResponseHeader(headerName, headerValue);
Adds a response header to the headers in the response. Multiple headers of the same kind can be written with separate calls. New calls will not overwrite old headers.
flush();
Ensures current buffered data is flushed to the output stream.
On first call this method forces the status line and headers to be sent, and terminates headers (the blank line indicating the start of the body). After this is called all calls to addResponseHeader will throw.
write(data);
Writes a chunk of data to the output stream.
Data must be a object that returns a Blob on valueOf("blob");
On first call this implies a call to .flush();
close();
This closes the connection with the browser ending the response.

ToFix

  • getRequestHeader is implemented for the most flexibility, however to implement JSGI's env/req object with HTTP-Gateway we'll need a method that allows the list of all sent headers to be obtained so that the .headers object can be created.
  • Should we note that calls to addResponseHeader with newlines in the headerValue should write out the header in extended header format (ie: A single header where it is extended to multiple lines by prepending each line with leading whitespace):
X-Example: asdf
 asdf