![]() |
API 0.9.5
|
00001 /* 00002 * CPURLConnection.j 00003 * Foundation 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 var CPURLConnectionDelegate = nil; 00025 00070 @implementation CPURLConnection : CPObject 00071 { 00072 CPURLRequest _request; 00073 id _delegate; 00074 BOOL _isCanceled; 00075 BOOL _isLocalFileConnection; 00076 00077 HTTPRequest _HTTPRequest; 00078 } 00079 00080 + (void)setClassDelegate:(id)delegate 00081 { 00082 CPURLConnectionDelegate = delegate; 00083 } 00084 00085 /* 00086 Sends a request for the data from a URL. This is the easiest way to obtain data from a URL. 00087 @param aRequest contains the URL to request the data from 00088 @param aURLResponse not used 00089 @param anError not used 00090 @return the data at the URL or \c nil if there was an error 00091 */ 00092 + (CPData)sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:({CPURLResponse})aURLResponse 00093 { 00094 try 00095 { 00096 var request = new CFHTTPRequest(); 00097 00098 request.open([aRequest HTTPMethod], [[aRequest URL] absoluteString], NO); 00099 00100 var fields = [aRequest allHTTPHeaderFields], 00101 key = nil, 00102 keys = [fields keyEnumerator]; 00103 00104 while (key = [keys nextObject]) 00105 request.setRequestHeader(key, [fields objectForKey:key]); 00106 00107 request.send([aRequest HTTPBody]); 00108 00109 return [CPData dataWithRawString:request.responseText()]; 00110 } 00111 catch (anException) 00112 { 00113 } 00114 00115 return nil; 00116 } 00117 00118 /* 00119 Creates a url connection with a delegate to monitor the request progress. 00120 @param aRequest contains the URL to obtain data from 00121 @param aDelegate will be sent messages related to the request progress 00122 @return a connection that can be \c started to initiate the request 00123 */ 00124 + (CPURLConnection)connectionWithRequest:(CPURLRequest)aRequest delegate:(id)aDelegate 00125 { 00126 return [[self alloc] initWithRequest:aRequest delegate:aDelegate]; 00127 } 00128 00129 /* 00130 Default class initializer. Use one of the class methods instead. 00131 @param aRequest contains the URL to contact 00132 @param aDelegate will receive progress messages 00133 @param shouldStartImmediately whether the \c -start method should be called from here 00134 @return the initialized url connection 00135 */ 00136 - (id)initWithRequest:(CPURLRequest)aRequest delegate:(id)aDelegate startImmediately:(BOOL)shouldStartImmediately 00137 { 00138 self = [super init]; 00139 00140 if (self) 00141 { 00142 _request = aRequest; 00143 _delegate = aDelegate; 00144 _isCanceled = NO; 00145 00146 var URL = [_request URL], 00147 scheme = [URL scheme]; 00148 00149 // Browsers use "file:", Titanium uses "app:" 00150 _isLocalFileConnection = scheme === "file" || 00151 ((scheme === "http" || scheme === "https:") && 00152 window.location && 00153 (window.location.protocol === "file:" || window.location.protocol === "app:")); 00154 00155 _HTTPRequest = new CFHTTPRequest(); 00156 00157 if (shouldStartImmediately) 00158 [self start]; 00159 } 00160 00161 return self; 00162 } 00163 00164 - (id)initWithRequest:(CPURLRequest)aRequest delegate:(id)aDelegate 00165 { 00166 return [self initWithRequest:aRequest delegate:aDelegate startImmediately:YES]; 00167 } 00168 00169 /* 00170 return the delegate 00171 */ 00172 - (id)delegate 00173 { 00174 return _delegate; 00175 } 00176 00177 /* 00178 Start the connection. Not needed if you used the class method +connectionWithRequest:delegate: 00179 */ 00180 - (void)start 00181 { 00182 _isCanceled = NO; 00183 00184 try 00185 { 00186 _HTTPRequest.open([_request HTTPMethod], [[_request URL] absoluteString], YES); 00187 00188 _HTTPRequest.onreadystatechange = function() { [self _readyStateDidChange]; } 00189 00190 var fields = [_request allHTTPHeaderFields], 00191 key = nil, 00192 keys = [fields keyEnumerator]; 00193 00194 while (key = [keys nextObject]) 00195 _HTTPRequest.setRequestHeader(key, [fields objectForKey:key]); 00196 00197 _HTTPRequest.send([_request HTTPBody]); 00198 } 00199 catch (anException) 00200 { 00201 if ([_delegate respondsToSelector:@selector(connection:didFailWithError:)]) 00202 [_delegate connection:self didFailWithError:anException]; 00203 } 00204 } 00205 00206 /* 00207 Cancels the current request. 00208 */ 00209 - (void)cancel 00210 { 00211 _isCanceled = YES; 00212 00213 try 00214 { 00215 _HTTPRequest.abort(); 00216 } 00217 // We expect an exception in some browsers like FireFox. 00218 catch (anException) 00219 { 00220 } 00221 } 00222 00223 - (BOOL)isLocalFileConnection 00224 { 00225 return _isLocalFileConnection; 00226 } 00227 00228 /* @ignore */ 00229 - (void)_readyStateDidChange 00230 { 00231 if (_HTTPRequest.readyState() === CFHTTPRequest.CompleteState) 00232 { 00233 var statusCode = _HTTPRequest.status(), 00234 URL = [_request URL]; 00235 00236 if (statusCode === 401 && [CPURLConnectionDelegate respondsToSelector:@selector(connectionDidReceiveAuthenticationChallenge:)]) 00237 [CPURLConnectionDelegate connectionDidReceiveAuthenticationChallenge:self]; 00238 else 00239 { 00240 if ([_delegate respondsToSelector:@selector(connection:didReceiveResponse:)]) 00241 { 00242 if (_isLocalFileConnection) 00243 [_delegate connection:self didReceiveResponse:[[CPURLResponse alloc] initWithURL:URL]]; 00244 else 00245 { 00246 var response = [[CPHTTPURLResponse alloc] initWithURL:URL]; 00247 [response _setStatusCode:statusCode]; 00248 [_delegate connection:self didReceiveResponse:response]; 00249 } 00250 } 00251 if (!_isCanceled) 00252 { 00253 if ([_delegate respondsToSelector:@selector(connection:didReceiveData:)]) 00254 [_delegate connection:self didReceiveData:_HTTPRequest.responseText()]; 00255 if ([_delegate respondsToSelector:@selector(connectionDidFinishLoading:)]) 00256 [_delegate connectionDidFinishLoading:self]; 00257 } 00258 } 00259 } 00260 00261 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; 00262 } 00263 00264 /* @ignore */ 00265 - (HTTPRequest)_HTTPRequest 00266 { 00267 return _HTTPRequest; 00268 } 00269 00270 @end 00271 00272 @implementation CPURLConnection (Deprecated) 00273 00274 + (CPData)sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:({CPURLResponse})aURLResponse error:(id)anError 00275 { 00276 _CPReportLenientDeprecation(self, _cmd, @selector(sendSynchronousRequest:returningResponse:)); 00277 00278 return [self sendSynchronousRequest:aRequest returningResponse:aURLResponse]; 00279 } 00280 00281 - (HTTPRequest)_XMLHTTPRequest 00282 { 00283 _CPReportLenientDeprecation(self, _cmd, @selector(_HTTPRequest)); 00284 00285 return [self _HTTPRequest]; 00286 } 00287 00288 @end