1 /* ***** BEGIN LICENSE BLOCK ***** 2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 * 4 * The contents of this file are subject to the Mozilla Public License Version 5 * 1.1 (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * http://www.mozilla.org/MPL/ 8 * 9 * Software distributed under the License is distributed on an "AS IS" basis, 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 * for the specific language governing rights and limitations under the 12 * License. 13 * 14 * The Original Code is gContactSync. 15 * 16 * The Initial Developer of the Original Code is 17 * Josh Geenen <gcontactsync@pirules.org>. 18 * Portions created by the Initial Developer are Copyright (C) 2008-2009 19 * the Initial Developer. All Rights Reserved. 20 * 21 * Contributor(s): 22 * 23 * Alternatively, the contents of this file may be used under the terms of 24 * either the GNU General Public License Version 2 or later (the "GPL"), or 25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 26 * in which case the provisions of the GPL or the LGPL are applicable instead 27 * of those above. If you wish to allow use of your version of this file only 28 * under the terms of either the GPL or the LGPL, and not to allow others to 29 * use your version of this file under the terms of the MPL, indicate your 30 * decision by deleting the provisions above and replace them with the notice 31 * and other provisions required by the GPL or the LGPL. If you do not delete 32 * the provisions above, a recipient may use your version of this file under 33 * the terms of any one of the MPL, the GPL or the LGPL. 34 * 35 * ***** END LICENSE BLOCK ***** */ 36 37 if (!com) var com = {}; // A generic wrapper variable 38 // A wrapper for all GCS functions and variables 39 if (!com.gContactSync) com.gContactSync = {}; 40 41 /** 42 * Sets up an HTTP request.<br> 43 * The constructor is not all that useful so extend this class if you must 44 * make repetitive HTTP requests.<br><br> 45 * You may setup callbacks based on different HTTP status codes: 46 * <ul> 47 * <li>0 (offline): use <b>mOnError</b></li> 48 * <li>200 (OK): use <b>mOnSuccess</b></li> 49 * <li>201 (CREATED): use <b>mOnCreated</b></li> 50 * <li>401 (UNAUTHORIZED): use <b>mOn401</b></li> 51 * <li><anything else>: use <b>mOnError</b></li> 52 * </ul> 53 * <br>Sample usage: 54 * <pre> 55 * // Create and setup a new HttpRequest 56 * var myHttpRequest = new com.gContactSync.HttpRequest(); 57 * myHttpRequest.mUrl = "http://www.pirules.org"; 58 * myHttpRequest.mType = "GET"; 59 * myHttpRequest.addHeaderItem("Content-length", 0); 60 * // setup the callbacks 61 * myHttpRequest.mOnSuccess = function myRequestSuccess(aHttpReq) { 62 * com.gContactSync.alert("Request succeeded. Content:\n\n" + aHttpReq.statusText); 63 * }; 64 * myHttpRequest.mOnOffline = function myRequestOffline(aHttpReq) { 65 * com.gContactSync.alert("You are offline"); 66 * }; 67 * myHttpRequest.mOnError = function myRequestError(aHttpReq) { 68 * com.gContactSync.alert("Request failed...Status: " + aHttpReq.status); 69 * }; 70 * // send the request 71 * myHttpRequest.send(); 72 * </pre> 73 * @constructor 74 * @class 75 */ 76 com.gContactSync.HttpRequest = function gCS_HttpRequest() { 77 if (window.XMLHttpRequest) 78 this.mHttpRequest = new XMLHttpRequest(); 79 if (!this.mHttpRequest) 80 throw "Error - could not create an XMLHttpRequest" + 81 com.gContactSync.StringBundle.getStr("pleaseReport"); 82 }; 83 84 com.gContactSync.HttpRequest.prototype = { 85 /** Content types */ 86 CONTENT_TYPES: { 87 /** URL encoded */ 88 URL_ENC: "application/x-www-form-urlencoded", 89 /** ATOM/XML */ 90 ATOM: "application/atom+xml", 91 /** XML */ 92 XML: "application/xml" 93 }, 94 /** 95 * Adds a content override to the header in case a firewall blocks DELETE or 96 * PUT requests. 97 * @param aType {string} The type of override. Must be DELETE or PUT. 98 */ 99 addContentOverride: function HttpRequest_addContentOverride(aType) { 100 switch (aType) { 101 case "delete": 102 case "DELETE": 103 this.addHeaderItem("X-HTTP-Method-Override", "DELETE"); 104 break; 105 case "put": 106 case "PUT": 107 this.addHeaderItem("X-HTTP-Method-Override", "PUT"); 108 break; 109 default: 110 throw "Error - type sent to addContentOverride must be DELETE or PUT"; 111 } 112 }, 113 /** 114 * Adds a header label/value pair to the arrays of header information 115 * @param aLabel {string} The label for the header. 116 * @param aValue {string} The value for the header. 117 */ 118 addHeaderItem: function HttpRequest_addHeaderItem(aLabel, aValue) { 119 if (!this.mHeaderLabels) { 120 this.mHeaderLabels = []; 121 this.mHeaderValues = []; 122 } 123 this.mHeaderLabels.push(aLabel); 124 this.mHeaderValues.push(aValue); 125 }, 126 /** 127 * Sends the HTTP Request with the information stored in the object.<br> 128 * Note: Setup everything, including the callbacks for different statuses 129 * including mOnSuccess, mOnError, mOnFail, and mOnCreated first.<br> 130 * See the class documentation for a sample request. 131 */ 132 send: function HttpRequest_send() { 133 // log the basic info for debugging purposes 134 com.gContactSync.LOGGER.VERBOSE_LOG("HTTP Request being formed"); 135 com.gContactSync.LOGGER.VERBOSE_LOG(" * Caller is: " + this.send.caller.name); 136 com.gContactSync.LOGGER.VERBOSE_LOG(" * URL: " + this.mUrl); 137 com.gContactSync.LOGGER.VERBOSE_LOG(" * Type: " + this.mType); 138 com.gContactSync.LOGGER.VERBOSE_LOG(" * Content-Type: " + this.mContentType); 139 140 this.mHttpRequest.open(this.mType, this.mUrl, true); // open the request 141 142 // set the header 143 this.addHeaderItem("Content-Type", this.mContentType); 144 com.gContactSync.LOGGER.VERBOSE_LOG(" * Setting up the header: "); 145 146 for (var i = 0; i < this.mHeaderLabels.length; i++) { 147 com.gContactSync.LOGGER.VERBOSE_LOG(" o " + this.mHeaderLabels[i] + 148 " " + this.mHeaderValues[i]); 149 this.mHttpRequest.setRequestHeader(this.mHeaderLabels[i], 150 this.mHeaderValues[i]); 151 } 152 this.mHttpRequest.send(this.mBody); // send the request 153 com.gContactSync.LOGGER.VERBOSE_LOG(" * Request Sent"); 154 var httpReq = this.mHttpRequest, 155 onSuccess = this.mOnSuccess, 156 onOffline = this.mOnOffline, 157 onFail = this.mOnError, 158 onCreated = this.mOnCreated, 159 on401 = this.mOn401; 160 161 httpReq.onreadystatechange = function httpReq_readyState() { 162 var callback = [], 163 i; 164 // if the request is done then check the status 165 if (httpReq.readyState === 4) { 166 // this may be called after the address book window is closed 167 // if the window is closed there will be an exception thrown as 168 // explained here - https://www.mozdev.org/bugs/show_bug.cgi?id=20527 169 com.gContactSync.LOGGER.VERBOSE_LOG(" * The request has finished with status: " + 170 httpReq.status + "/" + 171 (httpReq.status ? httpReq.statusText : "offline")); 172 if (httpReq.status) { 173 com.gContactSync.LOGGER.VERBOSE_LOG(" * Headers:\n" + 174 httpReq.getAllResponseHeaders() + "\n"); 175 } 176 177 switch (httpReq.status) { 178 case 0: // the user is offline 179 callback = onOffline; 180 break; 181 case 201: // 201 CREATED 182 callback = onCreated; 183 break; 184 case 200: // 200 OK 185 callback = onSuccess; 186 break; 187 case 401: // 401 Unauthorized (Token Expired in Gmail) 188 callback = on401; 189 break; 190 default: // other status 191 callback = onFail; 192 } 193 if (callback) { 194 com.gContactSync.LOGGER.VERBOSE_LOG(" * Running the function callback"); 195 callback.call(this, httpReq); 196 } 197 } // end of readyState 198 }; 199 } 200 }; 201