HTTPPost.js

Summary

This module is used to save documents via HTTP POST.

Version: 0.7.0

Author: James A. Overton


/* ***** BEGIN LICENSE BLOCK *****
 * Licensed under Version: MPL 1.1/GPL 2.0/LGPL 2.1
 * Full Terms at http://mozile.mozdev.org/license.html
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code was written by Max d'Ayala (www.dAyala.co.uk).
 *
 * The Initial Developer of the Original Code is Max d'Ayala
 * Portions created by the Initial Developer are Copyright (C) 2002-2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *	Max d'Ayala (www.dAyala.co.uk)
 *	Tobias Minich
 *	James A. Overton <james@overton.ca>
 *
 * ***** END LICENSE BLOCK ***** */
 

/** HTTP POST
 * @fileoverview This module is used to save documents via HTTP POST.
 * 
 * @link http://mozile.mozdev.org 
 * @author James A. Overton <james@overton.ca>
 * @version 0.7.0
 */

// Define a new Mozile.saveList entry.
mozile.saveList["HTTPPost"] = new Array();
mozile.saveList["HTTPPost"]["value"] ="HTTPPost";
mozile.saveList["HTTPPost"]["label"] ="Save via HTTP POST";
mozile.saveList["HTTPPost"]["function"] = "mozileSaveViaPOST";
mozile.saveList["HTTPPost"]["url"] = "";

// If the configuration of this modules gives a URL, then set it
if(mozile.moduleList["HTTPPost"]["url"]) {
	mozile.saveList["HTTPPost"]["url"] = mozile.moduleList["HTTPPost"]["url"];
}

// If the configuration of this modules says it's the default, then set it as the default.
if(mozile.moduleList["HTTPPost"]["default"] && mozile.moduleList["HTTPPost"]["default"] == "true") {
	mozile.saveList["default"] = mozile.saveList["HTTPPost"];
}

/*
var save = mozile.commandList["Mozile-SaveToDialog"];
save.command = function(event) {
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "save.command";
	
	mozile.status(f,1,"Starting to save document.");
	PostOnload();
}
*/








var fileObj = new Object();
var content;

function mozileSaveViaPOST() {
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "mozileSaveViaPOST()";
	mozile.status(f,1,"Saving via POST...");
	
	fileObj.httpSavePath = mozile.saveConfig["url"];
	fileObj.documentHref =  mozile.saveConfig["url"];
	fileObj.charset = document.characterSet;
	fileObj.characterSet = document.characterSet;
	fileObj.contentType = "text/plain";
	
	var content = mozile.content();
	content = CR + LF + content + CR + LF;
	
	POST_HttpRequest(fileObj, content);
}




const CR = '\x0D';
const LF = '\x0A';

var reqObj = new Object();


/* === Global variables === */
var XHR = new Object();
var POSTinfo = new Object();
POSTinfo.isError=true;
POSTinfo.isAbort=false;
POSTinfo.status="0";
POSTinfo.statusText="Undefined";
POSTinfo.msgText="Undefined";
POSTinfo.display=null;
POSTinfo.document=null;
POSTinfo.documentText=null;
POSTinfo.location=null;
POSTinfo.replace=null;





/* === WINDOW Events === */

/** POST - On Load  -
 * Starts the HTTPRequest, and focuses the abort button.
 *
 * @return True if successful.
 */
function PostOnload() {
	var content = mozile.documentToXML();
	POST_HttpRequest( fileObj, content );
	//document.getElementById("abortButton").focus();
	return true;
}

/** POST - Stop  -
 * This function is called by the abort button, and it tyried to gracefully shut down the HTTPRequest.
 *
 * @return True if successful.
 */
function PostStop() {
	var f = ["savepost.js","PostStop"];

	if ( XHR.readyState != 4 ) {
		XHR.abort();
	}
	/* Possibility of locking window open if this try block fails */
	try {
		var n = document.getElementById("saveText2").firstChild;
		n.data = "Save aborted.";
		n = document.getElementById("acceptButton");
		n.setAttribute( "hidden", "false" );
		n.focus();
		document.getElementById("abortButton").setAttribute( "hidden", "true" );
		document.getElementById("saveMeter").setAttribute( "mode", "determined" );
		document.getElementById("saveMeter").setAttribute( "value", "65" );
	}
	catch(e) {
		mozile.debug(f,3,"Exception: "+e);
	}
	reqObj.isAbort = true;
	mozile.debug(f,1,"XMLHttpRequest aborted");
	return true;
}


/** POST - Accept  -
 * This function performs the final cleanup after a successful save.
 *
 * @return True if successful.
 */
function PostAccept() {
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "save.command";
	mozile.status(f,1,"Save complete!");
	return true;
}



/* === XMLHttpRequest Events === */

/** POST - Complete  -
 * If the HTTPRequest is successful, then this function completes the save operation.
 *
 * @return True if successful.
 */
function PostComplete()
{
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "PostComplete";

	//mozile.insertString(XHR.responseText);

	if ( XHR.readyState == 4 ) {
		try {
			//document.getElementById("abortButton").setAttribute( "disabled", "true" );
		} catch (e) {
			mozile.debug(f,3,"Exception: "+e);
		}
		POST_Response();
	}

	/*Set up info to be returned to opener.*/
	reqObj.isError = POSTinfo.isError;
	reqObj.status = POSTinfo.status;
	reqObj.statusText = POSTinfo.statusText;
	reqObj.msgText = POSTinfo.msgText;
	reqObj.display = POSTinfo.display;
	if (POSTinfo.document) {
		reqObj.document = POSTinfo.document;
	}
	if (POSTinfo.documentText) {
		reqObj.documentText = POSTinfo.documentText;
	}
	if (POSTinfo.location != null) {
		reqObj.location = POSTinfo.location;
		if (POSTinfo.replace === true)
			reqObj.replace = POSTinfo.replace;
	}
	mozile.debug(f,1,"POST completed");

	

	if ( "status" in reqObj ) {mozile.debug(f,1,"status: "+reqObj.status);}
	if ( "statusText" in reqObj ) {mozile.debug(f,1,"statusText: "+reqObj.statusText);}
	if ( "msgText" in reqObj ) {mozile.debug(f,2,"msgText: "+reqObj.msgText);}
	if ( "originalStatus" in reqObj ) {mozile.debug(f,1,"originalStatus: "+reqObj.originalStatus);}
	if ( "originalStatusText" in reqObj ) {mozile.debug(f,1,"originalStatusText: "+reqObj.originalStatusText);}

	if ( ("isAbort" in reqObj) && reqObj.isAbort ) {
		mozile.debug(f,3,"Save aborted");
	}
	else if ( ("isError" in reqObj) ) {
		if ( !reqObj.isError ) {
			mozileTarget.document.MOZILE_CURRENT_CONFIG.saved = 'true';
			mozile.debug(f,3,"Save successful");
		}
		else {
			mozile.debug(f,3,"Save error.");
			if ( !("msgText" in reqObj) ) {
				/*This is the old error function*/
			  alert ("Couldn't save document \n" + reqObj.statusText);
			}
		}
	}
	
	// Currently message display only implemented for POST method.
	// if ( ( ("display" in reqObj) && reqObj.display == "yes" ) 
	//   || ( ("isError" in reqObj) && reqObj.isError===true && ("display" in reqObj) && reqObj.display != "no" ) ) {
	// 	try {
	// 		var SaveMsgWindow = window.open(
	// 			"savemsg.xml",
	// 			"savemsg",
	// 			"modal,dialog,centerscreen,chrome,resizable=yes");
	// 	}catch (e){
	// 		mozile.debug(f,3,"Save message window open exception: "+e);
	// 	}
	// }
	mozile.status(f,2, "Document saved.", 100, "window.open(mozile.moduleList['HTTPPost']['path']+'savemsg.xml', 'savemsg', 'centerscreen,chrome,resizable=yes')");

	/*Close window. window.close() doesn't work directly from here.*/
	/*Don't like this but can't get dispatchEvent() to work.*/
	try {
		//var b = document.getElementById("acceptButton");
		//b.doCommand( PostAccept );
		/*problem handling errors here because window has closed.*/
	} catch (e) {
		mozile.debug(f,3,"Exception2: "+e);
	}
	
	return true;
}



/** POST - Change  -
 * This function is called when the HTTPRequest status changes. It sets the message for the statusbar. 
 * 0 (initial text), 1 and 4 probably won't show, 2 may be too quick as well!
 *
 * @return True if successful.
 */
function PostChange() {
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "PostChange";
	
	try {
		switch ( XHR.readyState )
		{
		case 1 :
			mozile.status(f,3,"1 : Initialising...", 10);
			break;
		case 2 :
			mozile.status(f,3,"2 : Sending...", 50);
			break;
		case 3 :
			mozile.status(f,3,"3 : Receiving acknowledgement...", 90);
			break;
		case 4 :
			mozile.status(f,3,"4 : Completed", 100);
			break;
		}
	}
	catch(e) {
		mozile.debug(f,4,"Exception: "+e);
	}
	return true;
}


/** POST - On Error  -
 * This function is called when the HTTPRequest signals an error.
 *
 * @return True if successful.
 */
function PostOnerror()
{
	/*What to do here??? Will the onload event still fire to terminate the process???*/
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "PostOnerror";
	
	mozile.debug(f,3,"POST XMLHttpRequest Error");
	mozile.status(f,3,"Save Failed! There was some kind of error in the HTTP POST.");
	return true;
}



/* === FUNCTIONS === */

/** POST - HTTP Request  -
 * This function starts and HTTP Request.
 *
 * @param id The id object for this request.
 * @param content The content string to be saved.
 * @return True if successful.
 */
function POST_HttpRequest(id, content)
{
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "POST_HttpRequest";
	var contentLength;
	
	//alert(id.httpSavePath +" "+ id.documentHref);

	//Length doesn't include CRs and LFs, data only.
	contentLength = content.length;

	//alert(contentLength);
	
	try {
		XHR = new XMLHttpRequest();
		XHR.open("POST", id.httpSavePath, true, null, null);
		XHR.setRequestHeader( 'Content-Type', id.contentType + "; " + id.characterSet );
		XHR.setRequestHeader( 'Content-Length',  contentLength );
		XHR.setRequestHeader( 'Content-Location', id.documentHref );
		XHR.onerror = PostOnerror;
		XHR.onreadystatechange = PostChange;
		XHR.onload = PostComplete;
		XHR.send(content);
		mozile.debug(f,1,"POST sent");
	}catch (e){
		mozile.debug(f,4,"Exception: "+e);
		mozile.status(f,3,"Save Failed! Permission denied to save to URL \"" + mozile.saveConfig["url"] +"\"");
	}
}



/** POST - Prepare Data  -
 * Prepares the data by formatting it into an input stream? Requires privileges.
 *
 * @param data The data to be prepared.
 * @return True if successful.
 */
function POST_PrepareData( data )
{
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "POST_PrepareData";
	var SP;
	
	const CR = '\x0D';
	const LF = '\x0A';
	
	var postData = new String();
	postData = CR + LF + data + CR + LF;
	try {
		SP = Components.classes["@mozilla.org/io/string-input-stream;1"].createInstance();
		if (SP) {
			SP.QueryInterface(Components.interfaces.nsIStringInputStream);
			SP.setData( postData, postData.length ); 
		}
		else {
			SP = null;
			mozile.debug(f,3,"Problem creating Stream!!!");
		}
	} catch(e) {
		SP = null;
		mozile.debug(f,3,"Exception: "+e);
	}
	return SP;
}


/** POST - Response  -
 * This function is called when there is a response to the HTTPRequest. It is really just a switch that calls another function as appropriate.
 *
 * @return True if successful.
 */
function POST_Response()
{
  switch ( XHR.status ) {
	case 200 :
		POST_200();
		break;
	case 204 :
		POST_204();
		break;
	case 201 :
		POST_201();
		break;
	default :
		POST_Error( "Unexpected server response" );
	}
	return true;
}


/** POST - 204  -
 * This function handles the 204: No Content response to the HTTPRequest.
 *
 * @return True if successful.
 */
function POST_204() {
	POSTinfo.isError = false;
	POSTinfo.status = "204";
	POSTinfo.statusText = XHR.statusText;
}

/** POST - 201  -
 * This function handles the 201: Created response to the HTTPRequest.
 *
 * @return True if successful.
 */
function POST_201() {
	POSTinfo.isError = false;
	POSTinfo.status = "201";
	POSTinfo.statusText = XHR.statusText;
}

/** POST - 200  -
 * This function handles the 200: Ok response to the HTTPRequest.
 *
 * @return True if successful.
 */
function POST_200() {
	if ( XHR.responseXML ) {
		POST_200XML();
	}
	else {
		POST_Error( "XML response not received from server." );
	}
}

/** POST - 200 XML  -
 * This function handles the 200: Ok response to the HTTPRequest, and parses the XML which is returned.
 *
 * @return True if successful.
 */
function POST_200XML() {
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "POST_200XML";
	var postNode, psNode, ptNode, pdNode, plNode, postStatus="", postStatusText="";
	var postLocation=null, postReplace=false, postDisplay=null;

	try {
		postNode = XHR.responseXML.getElementsByTagNameNS("http://www.mozile.mozdev.org/ns/save/", "post");
		if (postNode.length > 0) {
			psNode = postNode[0].getElementsByTagName("status");
			if ( (psNode.length > 0) && psNode[0].hasChildNodes() && (psNode[0].firstChild.nodeType == Node.TEXT_NODE) ) {
				postStatus = psNode[0].firstChild.data;
			}
			ptNode = postNode[0].getElementsByTagName("statustext");
			if ( (ptNode.length > 0) && ptNode[0].hasChildNodes() && (ptNode[0].firstChild.nodeType == Node.TEXT_NODE) ) {
				postStatusText = ptNode[0].firstChild.data;
			}
			pdNode = postNode[0].getElementsByTagName("display");
			if ( (pdNode.length > 0) && pdNode[0].hasChildNodes() && (pdNode[0].firstChild.nodeType == Node.TEXT_NODE) ) {
				postDisplay = pdNode[0].firstChild.data.toLowerCase();
			}
			plNode = postNode[0].getElementsByTagName("location");
			if (plNode.length > 0) {
				if ( plNode[0].hasChildNodes() && (plNode[0].firstChild.nodeType == Node.TEXT_NODE) ) {
					postLocation = plNode[0].firstChild.data;
				}
				else {
					postLocation = "";
				}
				if ( plNode[0].hasAttributes() ) {
					var plAttr = plNode[0].attributes.getNamedItem("replace");
					if ( plAttr && plAttr.value.toLowerCase() == "true" )
						postReplace = true;
				}
			}
		}
		if ( (postStatus == "") || (postStatusText == "") ) {
			var s = "Something is wrong with the XML response."
			if (postNode.length == 0) {s+="\n<post> tag is missing or namespace is incorrect.\n  Namespace should be;\nhttp://www.mozile.mozdev.org/ns/save/";}
			else if (psNode.length == 0) {s+="\n<status> tag is missing.";}
			else if (postStatus == "") {s+="\nEmpty <status></status> tags.";}
			else if (ptNode.length == 0) {s+="\n<statustext> tag is missing.";}
			else if (postStatusText == "") {s+="\nEmpty <statustext></statustext> tags.";}
			POST_Error( s );
		} else {
			POSTinfo.status = "200";
			POSTinfo.statusText = XHR.statusText;
			POSTinfo.msgText = "[" + postStatus + "] " + postStatusText;
			if ( postStatus == "1" ) {
				POSTinfo.isError = false;
			}
			else {
				POSTinfo.isError = true;
			}
			switch (postDisplay) {
			case "yes" :
			case "no" :
				POSTinfo.display = postDisplay;
				break;
			default :
				POSTinfo.display = null;
			}
			if ( postLocation !== null ) {
				POSTinfo.location = postLocation;
				if ( postReplace )
					POSTinfo.replace = true;
			}
			if ( XHR.responseText )
				POSTinfo.documentText = XHR.responseText;
			if ( XHR.responseXML )
				POSTinfo.document = XHR.responseXML;
		}
	}
	catch(e) {
		mozile.debug(f,2,"Exception: "+e);
		POST_Error( "Exception" );
	}
}

/** POST - Error  -
 * General error handling function.	Optional first argument is a short string describing the error.
 *
 * @param message Optional A descriptive error message.
 * @return True if successful.
 */
/*
  
*/
function POST_Error() {
	var m = "Error";
	if ( arguments[0] ) {
		m += ": " + arguments[0] + "\n";
	}
	if (XHR.status && XHR.responseXML) {
		POSTinfo.status = XHR.status;
		POSTinfo.statusText = XHR.statusText;
		POSTinfo.document = XHR.responseXML;
		var x = parseXMLerror(XHR.responseXML);
		if ( x ) {
			m += "\n" + x;
		}
		POSTinfo.msgText = m;
		if ( XHR.responseText ) {
			POSTinfo.documentText = XHR.responseText;
		}
	}
	else if ( XHR.status && XHR.responseText ) {
		POSTinfo.status = XHR.status;
		POSTinfo.statusText = XHR.statusText;
		POSTinfo.msgText = m;
		POSTinfo.documentText = XHR.responseText;
	}
	else if ( XHR.status ) {
		POSTinfo.status = XHR.status;
		POSTinfo.statusText = XHR.statusText;
		POSTinfo.msgText = m;
	}
	else {
		POSTinfo.status = 999;
		POSTinfo.statusText = "Undefined";
		POSTinfo.msgText = m;
	}
	POSTinfo.isError = true;
}


/** POST - Parse XML Error  -
 * Checks for parsing errors in the XML response.
 *
 * @param responseXML The XML provided by the 200XML response to the HTTPRequest.
 * @return True if successful.
 */
function parseXMLerror( responseXML ) {
	var f = new Array();
	f["File"] = "HTTPPost/HTTPPost.js";
	f["Function"] = "parseXMLerror";
	var errtext="";
  
	try {
		// look to see if there is a parse error
		var parserErrorNode = responseXML.getElementsByTagNameNS("http://www.mozilla.org/newlayout/xml/parsererror.xml","parsererror")[0];

		if (parserErrorNode) {
			errtext += parserErrorNode.firstChild.data;
			var sourceNode = parserErrorNode.getElementsByTagName("sourcetext")[0];
			if (sourceNode) {
				errtext += "\n" + sourceNode.firstChild.data;
			}
		}
	} catch (e) {
		  mozile.debug(f,2,"Exception: "+e);
	}
	return errtext;
}



















mozile.registerModule("HTTPPost","1.0.0");


Documentation generated by JSDoc on Wed Oct 19 19:25:33 2005