// Both AJAX and XMLHttpRequest are misnomers. 'HTTPConnection' is much more // accurate. //////////////////////////////////////////////////////////////////////////////// // Constants //////////////////////////////////////////////////////////////////////////////// var __CFHTTP_ERROR_DIALOG_BOX_ID = "invalid CFHTTPDialogBox id"; var __CFHTTP_ERROR_IN_PROGRESS = "a request is already in progress"; var __CFHTTP_ERROR_RESPONSE = "no response loaded"; var __CFHTTP_WARNING_ACTIVEX_EXCEPTION = "can't test for ActiveX XMLHTTP support without exception support"; var __CFHTTP_WARNING_ACTIVEX_INTERFACES = "couldn't find ActiveX XMLHTTP interface"; var __CFHTTP_WARNING_TRANSPORT_UNAVAILABLE = "couldn't find HTTP transport"; var __CFHTTP_DEFAULT_HEADERS = {}; __CFHTTP_DEFAULT_HEADERS["connection"] = "close"; __CFHTTP_DEFAULT_HEADERS["content-encoding"] = "UTF-8"; var __CFHTTP_REQUEST_METHOD = "POST"; var __CFHTTP_SUPPORTS_CONNECTIONS = true; var CFHTTP_STATE_IDLE = 0; var CFHTTP_STATE_OPEN = 1; var CFHTTP_STATE_SENT = 2; var CFHTTP_STATE_RECEIVING = 3; var CFHTTP_STATE_LOADED = 4; //////////////////////////////////////////////////////////////////////////////// // Static variables //////////////////////////////////////////////////////////////////////////////// var __cfHTTPDialogBoxMap = {}; //////////////////////////////////////////////////////////////////////////////// // Classes //////////////////////////////////////////////////////////////////////////////// // __CFHTTPResponse function __CFHTTPResponse(transport) { this.__transport = transport; } __CFHTTPResponse.prototype.getBody = function() { return this.__transport.responseText; } __CFHTTPResponse.prototype.getCode = function() { var code = this.__transport.status; // IE stupidity if (code == 1223) { code = 204; } return code; } __CFHTTPResponse.prototype.getDocument = function() { return this.__transport.responseXML; } __CFHTTPResponse.prototype.getHeader = function(key) { return this.__transport.getResponseHeader(key); } __CFHTTPResponse.prototype.getMessage = function() { var transport = this.__transport; var message = undefined; // IE stupidity if (transport.status == 1223) { message = "No Content"; } else { message = transport.statusText; } return message; } __CFHTTPResponse.prototype.isError = function() { var code = this.getCode(); return ! ((code >= 200) && (code < 300)) } // CFHTTPConnection function CFHTTPConnection() { this.__handlers = new CFEventHandlerExpandedSet(); this.__stateChangeEvent = this.__handleStateChange.bind(this); this.__resetTransport(); } CFHTTPConnection.prototype.__handleStateChange = function() { var transport = this.__transport; var state = transport.readyState; if (state == CFHTTP_STATE_LOADED) { this.__response = new __CFHTTPResponse(transport); } this.__handlers.execute(state); if (state == CFHTTP_STATE_LOADED) { this.__resetTransport(); } } CFHTTPConnection.prototype.__resetTransport = function() { var transport = __cfHTTPCreateTransport(); this.__response = undefined; this.__transport = transport; transport.onreadystatechange = this.__stateChangeEvent; } CFHTTPConnection.prototype.abort = function() { this.__transport.abort(); this.__resetTransport(); } CFHTTPConnection.prototype.addEventHandler = function() { var handlers = this.__handlers; handlers.add.apply(handlers, arguments); } CFHTTPConnection.prototype.executeFormRequest = function(url, headers, params) { var combinedHeaders = {}; for (var key in headers) { combinedHeaders[key] = headers[key]; } combinedHeaders["content-type"] = "application/x-www-form-urlencoded"; var body = cfURLCreateQueryString(params); return this.executeRequest(url, combinedHeaders, body); } CFHTTPConnection.prototype.executeRequest = function(url, headers, body) { if (this.getState() != CFHTTP_STATE_IDLE) { return cfErrorTrigger("CFHTTPConnection::executeRequest: " + __CFHTTP_ERROR_IN_PROGRESS); } var transport = this.__transport; transport.open(__CFHTTP_REQUEST_METHOD, url, true); var combinedHeaders = {}; var key; if (typeof(headers) != "undefined") { for (key in headers) { combinedHeaders[key] = headers[key]; } } for (key in __CFHTTP_DEFAULT_HEADERS) { combinedHeaders[key] = __CFHTTP_DEFAULT_HEADERS[key]; } for (key in combinedHeaders) { transport.setRequestHeader(key, combinedHeaders[key]); } if (typeof(body) != "undefined") { transport.send(body); } else { transport.send(); } } CFHTTPConnection.prototype.getResponse = function() { var response = this.__response; if (typeof(response) == "undefined") { return cfErrorTrigger("CFHTTPConnection::getResponse: " + __CFHTTP_ERROR_RESPONSE); } return response; } CFHTTPConnection.prototype.getState = function() { return this.__transport.readyState; } // CFHTTPDialogBox function CFHTTPDialogBox(id, titleBoxId, contentPaneId, closeButtonId, idleMessage, openMessage, sendMessage, receivingMessage, loadedMessage) { CFDialogBox.call(id, titleBoxId, contentPaneId, closeButtonId); this.__idleMessage = idleMessage; this.__loadedMessage = loadedMessage; this.__openMessage = openMessage; this.__receivingMessage = receivingMessage; this.__sendMessage = sendMessage; __cfHTTPDialogBoxMap[id] = this; } //////////////////////////////////////////////////////////////////////////////// // Private functions //////////////////////////////////////////////////////////////////////////////// function __cfHTTPCreateTransportActiveXObjectMicrosoftXMLHTTP() { return new ActiveXObject("Microsoft.XMLHTTP"); } function __cfHTTPCreateTransportActiveXObjectMsxml2XMLHTTP() { return new ActiveXObject("Msxml2.XMLHTTP"); } function __cfHTTPCreateTransportCreateRequest() { // XX: Is this _really_ a viable transport option? return window.createRequest(); } function __cfHTTPCreateTransportUndefined() { return cfErrorTrigger("__cfHTTPCreateTransportUndefined: " + __CFHTTP_ERROR_SUPPORT); } function __cfHTTPCreateTransportXMLHttpRequest() { return new XMLHttpRequest(); } function __cfHTTPDisableConnections(warning) { cfWarningTrigger("[http]: " + warning); __cfHTTPCreateTransport = __cfHTTPCreateTransportUndefined; __CFHTTP_SUPPORTS_CONNECTIONS = false; } //////////////////////////////////////////////////////////////////////////////// // Public API //////////////////////////////////////////////////////////////////////////////// function cfHTTPDialogBoxCreate(arg) { return new CFHTTPDialogBox(arg.id, arg.titleBoxId, arg.contentBoxId, arg.closeButtonId, arg.idleMessage, arg.openMessage, arg.sendMessage, arg.receivingMessage, arg.loadedMessage); } function cfHTTPDialogBoxGet(id) { var box = __cfHTTPDialogBoxMap[id]; if (typeof(box) == "undefined") { return cfErrorTrigger("'" + id + "': " + __CFHTTP_ERROR_DIALOG_BOX_ID); } return box; } function cfHTTPHasConnectionSupport() { return __CFHTTP_SUPPORTS_CONNECTIONS; } //////////////////////////////////////////////////////////////////////////////// // Initialization //////////////////////////////////////////////////////////////////////////////// if (window.XMLHttpRequest) { __cfHTTPCreateTransport = __cfHTTPCreateTransportXMLHttpRequest; } else if (window.ActiveXObject) { // XXX: I wish there was a way to figure out which ActiveX objects are // available to us without blindly passing class ids to the ActiveXObject // constructor. With such a mechanism, we could ignore situations where // exception support is disabled, and avoid creating useless objects for // that purpose. if (! cfErrorHasExceptionSupport()) { __cfHTTPDisableConnections(__CFHTTP_WARNING_ACTIVEX_EXCEPTION); } else { var f = __cfHTTPCreateTransportActiveXObjectMsxml2XMLHTTP; var obj = cfErrorWatch(undefined, f, [], true); if (obj) { __cfHTTPCreateTransport = f; obj = undefined; } else { f = __cfHTTPCreateTransportActiveXObjectMicrosoftXMLHTTP; obj = cfErrorWatch(undefined, f, [], true); if (obj) { __cfHTTPCreateTransport = f; obj = undefined; } else { __cfHTTPDisableConnections(__CFHTTP_WARNING_ACTIVEX_INTERFACES); } } } } else if (window.createRequest) { __cfHTTPCreateTransport = __cfHTTPCreateTransportCreateRequest; } else { __cfHTTPDisableConnections(__CFHTTP_WARNING_TRANSPORT_UNAVAILABLE); }