mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
New: added timeout and cache feature in CPURLRequest
This PR adds the possibility to set the timeout and the cache policy of a CPURLRequest. For that, there are new things in the framework : - CFHTTPRequest has now the functions setTimeout(), getTimeout() and isTimeoutRequest - CPURLRequest has now the methods +requestWithURL:cachePolicy:timeoutInterval: and -initWithURL:cachePolicy:timeoutInterval: - CPURLConnection does not call the delegate didReceiveData: when a request has timed out. I will call the delegate didFailWithError: - Cache is now possible for a CPURLRequest, only CPURLRequestReturnCacheDataElseLoad, CPURLRequestReturnCacheDataDontLoad and CPURLRequestReloadIgnoringLocalCacheData are supported. By default CPURLRequestReloadIgnoringLocalCacheData. - Default timeout has been set to 60sec as in cocoa. - A request is considered as timeout when there isn't any response (text/xml/type) and when the status of the response is 0.
This commit is contained in:
@@ -112,6 +112,7 @@ var CPURLConnectionDelegate = nil;
|
||||
try
|
||||
{
|
||||
var aCFHTTPRequest = new CFHTTPRequest();
|
||||
aCFHTTPRequest.setTimeout([aRequest timeoutInterval] * 1000);
|
||||
aCFHTTPRequest.setWithCredentials([aRequest withCredentials]);
|
||||
|
||||
aCFHTTPRequest.open([aRequest HTTPMethod], [[aRequest URL] absoluteString], NO);
|
||||
@@ -125,7 +126,7 @@ var CPURLConnectionDelegate = nil;
|
||||
|
||||
aCFHTTPRequest.send([aRequest HTTPBody]);
|
||||
|
||||
if (!aCFHTTPRequest.success())
|
||||
if (!aCFHTTPRequest.success() || aCFHTTPRequest.isTimeoutRequest())
|
||||
return nil;
|
||||
|
||||
return [CPData dataWithRawString:aCFHTTPRequest.responseText()];
|
||||
@@ -176,6 +177,7 @@ var CPURLConnectionDelegate = nil;
|
||||
(window.location.protocol === "file:" || window.location.protocol === "app:"));
|
||||
|
||||
_HTTPRequest = new CFHTTPRequest();
|
||||
_HTTPRequest.setTimeout([aRequest timeoutInterval] * 1000);
|
||||
_HTTPRequest.setWithCredentials([aRequest withCredentials]);
|
||||
|
||||
if (shouldStartImmediately)
|
||||
@@ -210,6 +212,7 @@ var CPURLConnectionDelegate = nil;
|
||||
_HTTPRequest.open([_request HTTPMethod], [[_request URL] absoluteString], YES);
|
||||
|
||||
_HTTPRequest.onreadystatechange = function() { [self _readyStateDidChange]; };
|
||||
_HTTPRequest.ontimeout = function() { [self _timeout]; };
|
||||
|
||||
var fields = [_request allHTTPHeaderFields],
|
||||
key = nil,
|
||||
@@ -222,11 +225,16 @@ var CPURLConnectionDelegate = nil;
|
||||
}
|
||||
catch (anException)
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(connection:didFailWithError:)])
|
||||
[_delegate connection:self didFailWithError:anException];
|
||||
[self _sendDelegateDidFailWithError:anException];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_sendDelegateDidFailWithError:(CPException)anException
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(connection:didFailWithError:)])
|
||||
[_delegate connection:self didFailWithError:anException];
|
||||
}
|
||||
|
||||
/*
|
||||
Cancels the current request.
|
||||
*/
|
||||
@@ -249,10 +257,24 @@ var CPURLConnectionDelegate = nil;
|
||||
return _isLocalFileConnection;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_timeout
|
||||
{
|
||||
var exception = [CPException exceptionWithName:@"Timeout exception"
|
||||
reason:"The request timed out."
|
||||
userInfo:@{}];
|
||||
|
||||
[self _sendDelegateDidFailWithError:exception];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_readyStateDidChange
|
||||
{
|
||||
if (_HTTPRequest.readyState() === CFHTTPRequest.CompleteState)
|
||||
var isTimeoutRequest = !_HTTPRequest.status() && !_HTTPRequest.responseText();
|
||||
|
||||
if (_HTTPRequest.readyState() === CFHTTPRequest.CompleteState && !_HTTPRequest.isTimeoutRequest())
|
||||
{
|
||||
var statusCode = _HTTPRequest.status(),
|
||||
URL = [_request URL];
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
@import "CPString.j"
|
||||
@import "CPURL.j"
|
||||
|
||||
@typedef CPURLRequestCachePolicy
|
||||
CPURLRequestUseProtocolCachePolicy = 0;
|
||||
CPURLRequestReloadIgnoringLocalCacheData = 1;
|
||||
CPURLRequestReturnCacheDataElseLoad = 2;
|
||||
CPURLRequestReturnCacheDataDontLoad = 3;
|
||||
|
||||
/*!
|
||||
@class CPURLRequest
|
||||
@ingroup foundation
|
||||
@@ -35,14 +41,16 @@
|
||||
*/
|
||||
@implementation CPURLRequest : CPObject
|
||||
{
|
||||
CPURL _URL @accessors(property=URL);
|
||||
CPURL _URL @accessors(property=URL);
|
||||
|
||||
// FIXME: this should be CPData
|
||||
CPString _HTTPBody @accessors(property=HTTPBody);
|
||||
CPString _HTTPMethod @accessors(property=HTTPMethod);
|
||||
BOOL _withCredentials @accessors(property=withCredentials);
|
||||
CPString _HTTPBody @accessors(property=HTTPBody);
|
||||
CPString _HTTPMethod @accessors(property=HTTPMethod);
|
||||
BOOL _withCredentials @accessors(property=withCredentials);
|
||||
|
||||
CPDictionary _HTTPHeaderFields @accessors(readonly, getter=allHTTPHeaderFields);
|
||||
CPDictionary _HTTPHeaderFields @accessors(readonly, getter=allHTTPHeaderFields);
|
||||
CPTimeInterval _timeoutInterval @accessors(readonly, getter=timeoutInterval);
|
||||
CPURLRequestCachePolicy _cachePolicy @accessors(readonly, getter=cachePolicy);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -55,6 +63,18 @@
|
||||
return [[CPURLRequest alloc] initWithURL:aURL];
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a request with a specified URL, cachePolicy and timeoutInterval
|
||||
@param aURL the URL of the request
|
||||
@param aCachePolicy the cache policy of the request
|
||||
@param aTimeoutInterval the timeoutInterval of the request
|
||||
@return a CPURLRequest
|
||||
*/
|
||||
+ (id)requestWithURL:(CPURL)anURL cachePolicy:(CPURLRequestCachePolicy)aCachePolicy timeoutInterval:(CPTimeInterval)aTimeoutInterval
|
||||
{
|
||||
return [[CPURLRequest alloc] initWithURL:anURL cachePolicy:aCachePolicy timeoutInterval:aTimeoutInterval];
|
||||
}
|
||||
|
||||
/*!
|
||||
Equal to `[receiver initWithURL:nil]`.
|
||||
*/
|
||||
@@ -63,6 +83,27 @@
|
||||
return [self initWithURL:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the request with a URL. This is the designated initializer.
|
||||
|
||||
@param aURL the url to set
|
||||
@param aCachePolicy the cache policy of the request
|
||||
@param aTimeoutInterval the timeoutInterval of the request
|
||||
@return the initialized CPURLRequest
|
||||
*/
|
||||
- (id)initWithURL:(CPURL)anURL cachePolicy:(CPURLRequestCachePolicy)aCachePolicy timeoutInterval:(CPTimeInterval)aTimeoutInterval
|
||||
{
|
||||
self = [self initWithURL:anURL];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_cachePolicy = aCachePolicy;
|
||||
_timeoutInterval = aTimeoutInterval;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the request with a URL. This is the designated initializer.
|
||||
|
||||
@@ -81,9 +122,34 @@
|
||||
_HTTPMethod = @"GET";
|
||||
_HTTPHeaderFields = @{};
|
||||
_withCredentials = NO;
|
||||
_timeoutInterval = 60.0;
|
||||
_cachePolicy = CPURLRequestUseProtocolCachePolicy;
|
||||
|
||||
[self setValue:"Thu, 01 Jan 1970 00:00:00 GMT" forHTTPHeaderField:"If-Modified-Since"];
|
||||
[self setValue:"no-cache" forHTTPHeaderField:"Cache-Control"];
|
||||
|
||||
switch (_cachePolicy)
|
||||
{
|
||||
case CPURLRequestUseProtocolCachePolicy:
|
||||
// TODO: implement everything about cache...
|
||||
[self setValue:"no-cache" forHTTPHeaderField:"Cache-Control"];
|
||||
break;
|
||||
|
||||
case CPURLRequestReturnCacheDataElseLoad:
|
||||
[self setValue:"max-stale=31536000" forHTTPHeaderField:"Cache-Control"];
|
||||
break;
|
||||
|
||||
case CPURLRequestReturnCacheDataDontLoad:
|
||||
[self setValue:"only-if-cached" forHTTPHeaderField:"Cache-Control"];
|
||||
break;
|
||||
|
||||
case CPURLRequestReloadIgnoringLocalCacheData:
|
||||
[self setValue:"no-cache" forHTTPHeaderField:"Cache-Control"];
|
||||
break;
|
||||
|
||||
default:
|
||||
[self setValue:"no-cache" forHTTPHeaderField:"Cache-Control"];
|
||||
}
|
||||
|
||||
[self setValue:"XMLHttpRequest" forHTTPHeaderField:"X-Requested-With"];
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ GLOBAL(CFHTTPRequest) = function()
|
||||
|
||||
// by default, all requests will assume that credentials should not be sent.
|
||||
this._nativeRequest.withCredentials = false;
|
||||
this._nativeRequest.timeout = 60000;
|
||||
|
||||
var self = this;
|
||||
this._stateChangeHandler = function()
|
||||
@@ -112,7 +113,13 @@ GLOBAL(CFHTTPRequest) = function()
|
||||
determineAndDispatchHTTPRequestEvents(self);
|
||||
};
|
||||
|
||||
this._timeoutHandler = function()
|
||||
{
|
||||
dispatchTimeoutHTTPRequestEvents(self);
|
||||
};
|
||||
|
||||
this._nativeRequest.onreadystatechange = this._stateChangeHandler;
|
||||
this._nativeRequest.ontimeout = this._timeoutHandler;
|
||||
|
||||
if (CFHTTPRequest.AuthenticationDelegate !== nil)
|
||||
this._eventDispatcher.addEventListener("HTTP403", function()
|
||||
@@ -209,6 +216,16 @@ CFHTTPRequest.prototype.getResponseHeader = function(/*String*/ aHeader)
|
||||
return this._nativeRequest.getResponseHeader(aHeader);
|
||||
};
|
||||
|
||||
CFHTTPRequest.prototype.setTimeout = function(/*int*/ aTimeout)
|
||||
{
|
||||
this._nativeRequest.timeout = aTimeout;
|
||||
};
|
||||
|
||||
CFHTTPRequest.prototype.getTimeout = function(/*int*/ aTimeout)
|
||||
{
|
||||
return this._nativeRequest.timeout
|
||||
};
|
||||
|
||||
CFHTTPRequest.prototype.getAllResponseHeaders = function()
|
||||
{
|
||||
return this._nativeRequest.getAllResponseHeaders();
|
||||
@@ -235,7 +252,10 @@ CFHTTPRequest.prototype.send = function(/*Object*/ aBody)
|
||||
if (!this._isOpen)
|
||||
{
|
||||
delete this._nativeRequest.onreadystatechange;
|
||||
delete this._nativeRequest.ontimeout;
|
||||
|
||||
this._nativeRequest.open(this._method, this._URL, this._async, this._user, this._password);
|
||||
this._nativeRequest.ontimeout = this._timeoutHandler;
|
||||
this._nativeRequest.onreadystatechange = this._stateChangeHandler;
|
||||
}
|
||||
|
||||
@@ -287,15 +307,25 @@ CFHTTPRequest.prototype.withCredentials = function()
|
||||
return this._nativeRequest.withCredentials;
|
||||
};
|
||||
|
||||
CFHTTPRequest.prototype.isTimeoutRequest = function()
|
||||
{
|
||||
// Can we consider that as a timeout ?
|
||||
return !this.success() && !this._nativeRequest.response && !this._nativeRequest.responseText && !this._nativeRequest.responseType && !this._nativeRequest.responseURL && !this._nativeRequest.responseXML;
|
||||
};
|
||||
|
||||
function dispatchTimeoutHTTPRequestEvents(/*CFHTTPRequest*/ aRequest)
|
||||
{
|
||||
aRequest._eventDispatcher.dispatchEvent({ type:"timeout", request:aRequest});
|
||||
}
|
||||
|
||||
function determineAndDispatchHTTPRequestEvents(/*CFHTTPRequest*/ aRequest)
|
||||
{
|
||||
var eventDispatcher = aRequest._eventDispatcher;
|
||||
var eventDispatcher = aRequest._eventDispatcher,
|
||||
nativeRequest = aRequest._nativeRequest,
|
||||
readyStates = ["uninitialized", "loading", "loaded", "interactive", "complete"];
|
||||
|
||||
eventDispatcher.dispatchEvent({ type:"readystatechange", request:aRequest});
|
||||
|
||||
var nativeRequest = aRequest._nativeRequest,
|
||||
readyStates = ["uninitialized", "loading", "loaded", "interactive", "complete"];
|
||||
|
||||
if (readyStates[aRequest.readyState()] === "complete")
|
||||
{
|
||||
var status = "HTTP" + aRequest.status();
|
||||
|
||||
Reference in New Issue
Block a user