2001-12-17 14:31:42 +00:00
|
|
|
/** NSURLHandle.m - Class NSURLHandle
|
1999-02-13 00:50:41 +00:00
|
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
Written by: Manuel Guesdon <mguesdon@sbuilders.com>
|
2000-09-21 12:31:29 +00:00
|
|
|
Date: Jan 1999
|
2002-06-16 15:03:56 +00:00
|
|
|
Rewrite by: Richard Frith-Macdonald <rfm@gnu.org>
|
2002-06-06 14:02:59 +00:00
|
|
|
Date: Sep 2000, June 2002
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
|
|
This file is part of the GNUstep Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; if not, write to the Free
|
1999-09-09 02:56:20 +00:00
|
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
<title>NSURLHandle class reference</title>
|
|
|
|
$Date$ $Revision$
|
1999-02-13 00:50:41 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <Foundation/NSArray.h>
|
2000-09-21 12:31:29 +00:00
|
|
|
#include <Foundation/NSData.h>
|
|
|
|
#include <Foundation/NSEnumerator.h>
|
1999-02-13 00:50:41 +00:00
|
|
|
#include <Foundation/NSString.h>
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <Foundation/NSConcreteNumber.h>
|
2000-10-27 15:58:11 +00:00
|
|
|
#include <Foundation/NSLock.h>
|
1999-02-13 00:50:41 +00:00
|
|
|
#include <Foundation/NSURLHandle.h>
|
|
|
|
#include <Foundation/NSURL.h>
|
2000-10-27 21:17:09 +00:00
|
|
|
#include <Foundation/NSRunLoop.h>
|
2000-11-18 06:40:23 +00:00
|
|
|
#include <Foundation/NSFileManager.h>
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2000-09-21 12:31:29 +00:00
|
|
|
@class GSFileURLHandle;
|
2002-06-16 11:52:53 +00:00
|
|
|
@class GSFTPURLHandle;
|
2000-11-17 16:19:56 +00:00
|
|
|
@class GSHTTPURLHandle;
|
2000-09-21 12:31:29 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/*
|
|
|
|
* Keys for NSURLHandle
|
|
|
|
*/
|
|
|
|
NSString * const NSHTTPPropertyStatusCodeKey
|
2002-06-12 15:00:02 +00:00
|
|
|
= @"NSHTTPPropertyStatusCodeKey";
|
2002-06-06 14:02:59 +00:00
|
|
|
|
|
|
|
NSString * const NSHTTPPropertyStatusReasonKey
|
|
|
|
= @"NSHTTPPropertyStatusReasonKey";
|
|
|
|
|
|
|
|
NSString * const NSHTTPPropertyServerHTTPVersionKey
|
|
|
|
= @"NSHTTPPropertyServerHTTPVersionKey";
|
|
|
|
|
|
|
|
NSString * const NSHTTPPropertyRedirectionHeadersKey
|
|
|
|
= @"NSHTTPPropertyRedirectionHeadersKey";
|
|
|
|
|
|
|
|
NSString * const NSHTTPPropertyErrorPageDataKey
|
|
|
|
= @"NSHTTPPropertyErrorPageDataKey";
|
|
|
|
|
|
|
|
/* These are GNUstep extras */
|
|
|
|
NSString * const GSHTTPPropertyMethodKey
|
|
|
|
= @"GSHTTPPropertyMethodKey";
|
|
|
|
|
|
|
|
NSString * const GSHTTPPropertyProxyHostKey
|
|
|
|
= @"GSHTTPPropertyProxyHostKey";
|
|
|
|
|
|
|
|
NSString * const GSHTTPPropertyProxyPortKey
|
|
|
|
= @"GSHTTPPropertyProxyPortKey";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>
|
|
|
|
* An NSURLHandle instance is used to manage the resource data
|
|
|
|
* corresponding to an NSURL object. A single NSURLHandle can
|
|
|
|
* be used to manage multiple NSURL objects as long as those
|
|
|
|
* objects all refer to the same resource.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* Different NSURLHandle subclasses are used to manage different
|
|
|
|
* types of URL (usually based on the scheme of the URL), and you
|
|
|
|
* can register new subclasses to extend (or replace) the
|
|
|
|
* standard ones.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* GNUstep comes with private subclasses to handle the common
|
|
|
|
* URL schemes -
|
|
|
|
* </p>
|
|
|
|
* <list>
|
|
|
|
* <item>
|
|
|
|
* <code>file:</code> (local file I/O)
|
|
|
|
* </item>
|
|
|
|
* <item>
|
|
|
|
* <code>http:</code> and <code>shttp:</code> (webserver) access.
|
|
|
|
* </item>
|
2002-06-16 15:03:56 +00:00
|
|
|
* <item>
|
|
|
|
* <code>ftp:</code> (FTP server) access.
|
|
|
|
* </item>
|
2002-06-06 14:02:59 +00:00
|
|
|
* </list>
|
|
|
|
*/
|
1999-02-13 00:50:41 +00:00
|
|
|
@implementation NSURLHandle
|
|
|
|
|
2000-10-27 15:58:11 +00:00
|
|
|
static NSLock *registryLock = nil;
|
2000-09-19 08:31:40 +00:00
|
|
|
static NSMutableArray *registry = nil;
|
2000-10-27 15:58:11 +00:00
|
|
|
static Class NSURLHandleClass = 0;
|
2000-09-19 08:31:40 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Return a handle for the specified URL from the cache if possible.
|
|
|
|
* If the cache does not contain a matching handle, returns nil.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
+ (NSURLHandle*) cachedHandleForURL: (NSURL*)url
|
2000-09-19 08:31:40 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
/*
|
|
|
|
* Each subclass is supposed to do its own caching, so we must
|
|
|
|
* find the correct subclass and ask it for its cached handle.
|
|
|
|
*/
|
2000-10-27 15:58:11 +00:00
|
|
|
if (self == NSURLHandleClass)
|
2000-09-19 08:31:40 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
Class c = [self URLHandleClassForURL: url];
|
|
|
|
|
2000-10-27 15:58:11 +00:00
|
|
|
if (c == self || c == 0)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return [c cachedHandleForURL: url];
|
|
|
|
}
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
return nil;
|
2000-09-19 08:31:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/** <override-subclass />
|
|
|
|
* Implemented by subclasses to say which URLs they can handle.
|
|
|
|
* This method is used to determine which subclasses can be used
|
|
|
|
* to handle a particular URL.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
+ (BOOL) canInitWithURL: (NSURL*)url
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
/*
|
|
|
|
* The semi-abstract base class can't handle ANY scheme
|
|
|
|
*/
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
if (self == [NSURLHandle class])
|
2000-09-19 08:31:40 +00:00
|
|
|
{
|
2000-10-27 15:58:11 +00:00
|
|
|
NSURLHandleClass = self;
|
2000-09-21 12:31:29 +00:00
|
|
|
registry = [NSMutableArray new];
|
2000-10-27 15:58:11 +00:00
|
|
|
registryLock = [NSLock new];
|
2000-09-21 12:31:29 +00:00
|
|
|
[self registerURLHandleClass: [GSFileURLHandle class]];
|
2002-06-16 11:52:53 +00:00
|
|
|
[self registerURLHandleClass: [GSFTPURLHandle class]];
|
2000-11-17 16:19:56 +00:00
|
|
|
[self registerURLHandleClass: [GSHTTPURLHandle class]];
|
2000-09-19 08:31:40 +00:00
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Used to register a subclass as being available to handle URLs.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
+ (void) registerURLHandleClass: (Class)urlHandleSubclass
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Maintain a registry of classes that handle various schemes
|
|
|
|
* Re-adding a class moves it to the end of the registry - so it will
|
|
|
|
* be used in preference to any class added earlier.
|
|
|
|
*/
|
2000-10-27 15:58:11 +00:00
|
|
|
[registryLock lock];
|
2000-10-30 20:43:09 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
[registry removeObjectIdenticalTo: urlHandleSubclass];
|
|
|
|
[registry addObject: urlHandleSubclass];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
[registryLock unlock];
|
|
|
|
[localException raise];
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2000-10-27 15:58:11 +00:00
|
|
|
[registryLock unlock];
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Returns the most recently registered NSURLHandle subclass that
|
2002-11-04 15:39:43 +00:00
|
|
|
* responds to +canInitWithURL: with YES.
|
2002-06-06 14:02:59 +00:00
|
|
|
* If there is no such subclass, returns nil.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
+ (Class) URLHandleClassForURL: (NSURL*)url
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-10-27 15:58:11 +00:00
|
|
|
unsigned count;
|
2000-10-30 20:43:09 +00:00
|
|
|
Class c = 0;
|
2000-10-27 15:58:11 +00:00
|
|
|
|
|
|
|
[registryLock lock];
|
2000-10-30 20:43:09 +00:00
|
|
|
NS_DURING
|
2000-09-19 08:31:40 +00:00
|
|
|
{
|
2000-10-30 20:43:09 +00:00
|
|
|
count = [registry count];
|
2000-09-19 08:31:40 +00:00
|
|
|
|
2000-10-30 20:43:09 +00:00
|
|
|
/*
|
|
|
|
* Find a class to handle the URL, try most recently registered first.
|
|
|
|
*/
|
|
|
|
while (count-- > 0)
|
2000-09-19 08:31:40 +00:00
|
|
|
{
|
2000-10-30 20:43:09 +00:00
|
|
|
id found = [registry objectAtIndex: count];
|
|
|
|
|
|
|
|
if ([found canInitWithURL: url] == YES)
|
|
|
|
{
|
|
|
|
c = (Class)found;
|
2002-05-01 16:39:50 +00:00
|
|
|
break; // Found it.
|
2000-10-30 20:43:09 +00:00
|
|
|
}
|
2000-09-19 08:31:40 +00:00
|
|
|
}
|
|
|
|
}
|
2000-10-30 20:43:09 +00:00
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
[registryLock unlock];
|
|
|
|
[localException raise];
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2000-10-27 15:58:11 +00:00
|
|
|
[registryLock unlock];
|
2000-10-31 12:32:00 +00:00
|
|
|
return c;
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Add a client object, making sure that it doesn't occur more than once.<br />
|
|
|
|
* The client object will receive messages notifying it of events on the handle.
|
2000-09-25 06:06:28 +00:00
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (void) addClient: (id <NSURLHandleClient>)client
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2002-08-27 15:46:15 +00:00
|
|
|
id o = client;
|
|
|
|
|
|
|
|
RETAIN(o);
|
|
|
|
[_clients removeObjectIdenticalTo: o];
|
|
|
|
[_clients addObject: o];
|
|
|
|
RELEASE(o);
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
2000-09-19 08:31:40 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Returns the resource data that is currently available for the
|
|
|
|
* handle. This may be a partially loaded resource or may be
|
|
|
|
* empty of no data has been loaded yet.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (NSData*) availableResourceData
|
|
|
|
{
|
2000-10-27 21:17:09 +00:00
|
|
|
if (_status == NSURLHandleLoadInProgress)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
return _data;
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* This method should be called when a background load fails.<br />
|
|
|
|
* The method passes the failure notification to the clients of
|
|
|
|
* the handle - so subclasses should call super's implementation
|
|
|
|
* at the end of their implementation of this method.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (void) backgroundLoadDidFailWithReason: (NSString*)reason
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator = [_clients objectEnumerator];
|
|
|
|
id <NSURLHandleClient> client;
|
|
|
|
|
|
|
|
_status = NSURLHandleLoadFailed;
|
2000-10-27 21:17:09 +00:00
|
|
|
DESTROY(_data);
|
2000-09-21 12:31:29 +00:00
|
|
|
ASSIGNCOPY(_failure, reason);
|
|
|
|
|
|
|
|
while ((client = [enumerator nextObject]) != nil)
|
2000-09-19 18:49:43 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
[client URLHandle: self resourceDidFailLoadingWithReason: _failure];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* This method is called by when a background load begins.
|
|
|
|
* Subclasses should call super's implementation at
|
|
|
|
* the end of their implementation of this method.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (void) beginLoadInBackground
|
|
|
|
{
|
|
|
|
_status = NSURLHandleLoadInProgress;
|
2000-10-27 21:17:09 +00:00
|
|
|
DESTROY(_data);
|
|
|
|
_data = [NSMutableData new];
|
2000-09-21 12:31:29 +00:00
|
|
|
[_clients makeObjectsPerformSelector:
|
|
|
|
@selector(URLHandleResourceDidBeginLoading:)
|
|
|
|
withObject: self];
|
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* This method should be called to cancel a load currently in
|
|
|
|
* progress. The method calls -endLoadInBackground
|
|
|
|
* Subclasses should call super's implementation at
|
|
|
|
* the end of their implementation of this method.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (void) cancelLoadInBackground
|
|
|
|
{
|
|
|
|
[_clients makeObjectsPerformSelector:
|
|
|
|
@selector(URLHandleResourceDidCancelLoading:)
|
|
|
|
withObject: self];
|
|
|
|
[self endLoadInBackground];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
RELEASE(_data);
|
|
|
|
RELEASE(_failure);
|
|
|
|
RELEASE(_clients);
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Method called by subclasses during process of loading a resource.
|
2000-09-21 12:31:29 +00:00
|
|
|
* The base class maintains a copy of the data being read in and
|
|
|
|
* accumulates separate parts of the data.
|
|
|
|
*/
|
|
|
|
- (void) didLoadBytes: (NSData*)newData
|
|
|
|
loadComplete: (BOOL)loadComplete
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
id <NSURLHandleClient> client;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let clients know we are starting loading (unless this has already been
|
|
|
|
* done).
|
|
|
|
*/
|
|
|
|
if (_status != NSURLHandleLoadInProgress)
|
|
|
|
{
|
|
|
|
_status = NSURLHandleLoadInProgress;
|
2000-10-27 21:17:09 +00:00
|
|
|
DESTROY(_data);
|
|
|
|
_data = [NSMutableData new];
|
2000-09-21 12:31:29 +00:00
|
|
|
[_clients makeObjectsPerformSelector:
|
|
|
|
@selector(URLHandleResourceDidBeginLoading:)
|
|
|
|
withObject: self];
|
2000-09-19 18:49:43 +00:00
|
|
|
}
|
2000-09-21 12:31:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have been given nil data, there must have been a failure!
|
|
|
|
*/
|
|
|
|
if (newData == nil)
|
2000-09-19 08:31:40 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
[self backgroundLoadDidFailWithReason: @"nil data"];
|
|
|
|
return;
|
2000-09-19 08:31:40 +00:00
|
|
|
}
|
2000-09-21 12:31:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Let clients know we have read some data.
|
|
|
|
*/
|
|
|
|
enumerator = [_clients objectEnumerator];
|
|
|
|
while ((client = [enumerator nextObject]) != nil)
|
2000-09-19 18:49:43 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
[client URLHandle: self resourceDataDidBecomeAvailable: newData];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Accumulate data in cache.
|
|
|
|
*/
|
|
|
|
[_data appendData: newData];
|
|
|
|
|
|
|
|
if (loadComplete == YES)
|
|
|
|
{
|
2000-12-05 18:34:06 +00:00
|
|
|
id tmp = _data;
|
|
|
|
|
|
|
|
_data = [tmp copy];
|
|
|
|
RELEASE(tmp);
|
2000-09-21 12:31:29 +00:00
|
|
|
/*
|
|
|
|
* Let clients know we have finished loading.
|
|
|
|
*/
|
|
|
|
_status = NSURLHandleLoadSucceeded;
|
|
|
|
[_clients makeObjectsPerformSelector:
|
|
|
|
@selector(URLHandleResourceDidFinishLoading:)
|
|
|
|
withObject: self];
|
2000-09-19 18:49:43 +00:00
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* This method is called to stop any background loading process.
|
|
|
|
* -cancelLoadInBackground uses this method to cancel loading.
|
|
|
|
* Subclasses should call super's implementation at
|
|
|
|
* the end of their implementation of this method.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (void) endLoadInBackground
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
_status = NSURLHandleNotLoaded;
|
2000-12-05 18:34:06 +00:00
|
|
|
DESTROY(_data);
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Returns the failure reason for the last failure to load
|
|
|
|
* the resource data.
|
|
|
|
*/
|
1999-06-24 19:30:29 +00:00
|
|
|
- (NSString*) failureReason
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
if (_status == NSURLHandleLoadFailed)
|
|
|
|
return _failure;
|
|
|
|
else
|
|
|
|
return nil;
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Flushes any cached resource data.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (void) flushCachedData
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-10-27 21:17:09 +00:00
|
|
|
DESTROY(_data);
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2000-09-21 12:31:29 +00:00
|
|
|
- (id) init
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-10-27 15:58:11 +00:00
|
|
|
return [self initWithURL: nil cached: NO];
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/** <init />
|
|
|
|
* Initialises a handle with the specified URL.<br />
|
|
|
|
* The flag determines whether the handle will cache resource data
|
|
|
|
* and respond to requests from equivalent URLs for the cached data.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (id) initWithURL: (NSURL*)url
|
|
|
|
cached: (BOOL)cached
|
|
|
|
{
|
2000-10-27 15:58:11 +00:00
|
|
|
_status = NSURLHandleNotLoaded;
|
|
|
|
_clients = [NSMutableArray new];
|
|
|
|
return self;
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Starts (or queues) loading of the handle's resource data
|
|
|
|
* in the background (asynchronously).<br />
|
|
|
|
* The default implementation uses loadInForeground -
|
2000-10-27 21:17:09 +00:00
|
|
|
* if this method is not overridden, loadInForeground MUST be.
|
|
|
|
*/
|
1999-06-24 19:30:29 +00:00
|
|
|
- (void) loadInBackground
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-10-27 21:17:09 +00:00
|
|
|
NSData *d;
|
|
|
|
|
|
|
|
[self beginLoadInBackground];
|
|
|
|
d = [self loadInForeground];
|
|
|
|
if (d == nil)
|
|
|
|
{
|
|
|
|
[self backgroundLoadDidFailWithReason: @"foreground load returned nil"];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self didLoadBytes: d loadComplete: YES];
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Loads the handle's resource data in the foreground (synchronously).<br />
|
|
|
|
* The default implementation starts a background load and waits for
|
|
|
|
* it to complete -
|
2000-10-27 21:17:09 +00:00
|
|
|
* if this method is not overridden, loadInBackground MUST be.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (NSData*) loadInForeground
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-10-27 21:17:09 +00:00
|
|
|
NSRunLoop *loop = [NSRunLoop currentRunLoop];
|
|
|
|
|
|
|
|
[self loadInBackground];
|
|
|
|
while ([self status] == NSURLHandleLoadInProgress)
|
|
|
|
{
|
|
|
|
NSDate *limit;
|
|
|
|
|
|
|
|
limit = [[NSDate alloc] initWithTimeIntervalSinceNow: 1.0];
|
|
|
|
[loop runUntilDate: limit];
|
|
|
|
RELEASE(limit);
|
|
|
|
}
|
|
|
|
return _data;
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/** <override-subclass />
|
|
|
|
* Returns the property for the specified key, or nil if the
|
|
|
|
* key does not exist.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (id) propertyForKey: (NSString*)propertyKey
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1999-06-24 19:30:29 +00:00
|
|
|
return nil;
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/** <override-subclass />
|
|
|
|
* Returns the property for the specified key, but only if the
|
|
|
|
* handle does not need to do any work to retrieve it.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (id) propertyForKeyIfAvailable: (NSString*)propertyKey
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1999-06-24 19:30:29 +00:00
|
|
|
return nil;
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Removes an object from them list of clients notified of
|
|
|
|
* resource loading events by the URL handle.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (void) removeClient: (id <NSURLHandleClient>)client
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
[_clients removeObjectIdenticalTo: client];
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
2002-06-16 15:03:56 +00:00
|
|
|
* Returns the resource data belonging to the handle.
|
2002-06-06 14:02:59 +00:00
|
|
|
* Calls -loadInForeground if necessary.
|
2002-06-16 15:03:56 +00:00
|
|
|
* <p>
|
|
|
|
* The GNUstep implementation treats an <em>ftp:</em> request for a
|
|
|
|
* directory as a request to list the names of the directory contents.
|
|
|
|
* </p>
|
2002-06-06 14:02:59 +00:00
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (NSData*) resourceData
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
if (_status == NSURLHandleLoadSucceeded)
|
|
|
|
{
|
|
|
|
return [self availableResourceData];
|
|
|
|
}
|
2000-12-05 18:34:06 +00:00
|
|
|
else if (_status == NSURLHandleLoadInProgress)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2000-09-21 12:31:29 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
NSData *d = [self loadInForeground];
|
|
|
|
|
|
|
|
if (d != nil)
|
|
|
|
{
|
2000-10-27 21:17:09 +00:00
|
|
|
ASSIGNCOPY(_data, d);
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
2000-10-27 21:17:09 +00:00
|
|
|
return _data;
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Returns the current status of the handle.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (NSURLHandleStatus) status
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
return _status;
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* <p>
|
|
|
|
* Writes resource data to the handle. Returns YES on success,
|
|
|
|
* NO on failure.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
2002-06-16 15:03:56 +00:00
|
|
|
* The GNUstep implementation for <em>file:</em> writes the data
|
|
|
|
* directly to the local filesystem, and the return status reflects
|
|
|
|
* the result of that write operation.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* The GNUstep implementation for <em>http:</em> and <em>https:</em>
|
|
|
|
* sets the specified data as information to be POSTed to the URL next
|
|
|
|
* time it is loaded - so the method always returns YES.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* The GNUstep implementation for <em>ftp:</em> sets the specified data
|
|
|
|
* as information to be weitten to the URL next time it is loaded - so
|
|
|
|
* the method always returns YES.
|
2002-06-06 14:02:59 +00:00
|
|
|
* </p>
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (BOOL) writeData: (NSData*)data
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1999-06-24 19:30:29 +00:00
|
|
|
return NO;
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* <p>
|
|
|
|
* Sets a property for handle.
|
|
|
|
* Returns YES on success, NO on failure.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* The GNUstep implementation sets the property as a header
|
|
|
|
* to be sent the next time the URL is loaded, and recognizes
|
|
|
|
* some special property keys which control the behavior of
|
|
|
|
* the next load.
|
|
|
|
* </p>
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (BOOL) writeProperty: (id)propertyValue
|
|
|
|
forKey: (NSString*)propertyKey
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
return NO;
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2000-09-21 12:31:29 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@interface GSFileURLHandle : NSURLHandle
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-11-18 06:40:23 +00:00
|
|
|
NSString *_path;
|
|
|
|
NSMutableDictionary *_attributes;
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
2000-09-21 12:31:29 +00:00
|
|
|
@end
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* <p>
|
|
|
|
* This is a <em>PRIVATE</em> subclass of NSURLHandle.
|
|
|
|
* It is documented here in order to give you information about the
|
|
|
|
* default behavior of an NSURLHandle created to deal with a URL
|
|
|
|
* that has the FILE scheme. The name and/or other
|
|
|
|
* implementation details of this class may be changed at any time.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* A GSFileURLHandle instance is used to manage files on the local
|
|
|
|
* file-system of your machine.
|
|
|
|
* </p>
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
@implementation GSFileURLHandle
|
|
|
|
|
|
|
|
static NSMutableDictionary *fileCache = nil;
|
2000-10-27 21:17:09 +00:00
|
|
|
static NSLock *fileLock = nil;
|
2000-09-21 12:31:29 +00:00
|
|
|
|
|
|
|
+ (NSURLHandle*) cachedHandleForURL: (NSURL*)url
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
NSURLHandle *obj = nil;
|
|
|
|
|
|
|
|
if ([url isFileURL] == YES)
|
|
|
|
{
|
|
|
|
NSString *path = [url path];
|
|
|
|
|
|
|
|
path = [path stringByStandardizingPath];
|
2000-10-27 21:17:09 +00:00
|
|
|
[fileLock lock];
|
2000-10-30 20:43:09 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
obj = [fileCache objectForKey: path];
|
|
|
|
AUTORELEASE(RETAIN(obj));
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
[fileLock unlock];
|
|
|
|
[localException raise];
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2000-10-27 21:17:09 +00:00
|
|
|
[fileLock unlock];
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
|
|
|
return obj;
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2000-09-21 12:31:29 +00:00
|
|
|
+ (BOOL) canInitWithURL: (NSURL*)url
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
if ([url isFileURL] == YES)
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
return NO;
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2000-09-21 12:31:29 +00:00
|
|
|
+ (void) initialize
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
fileCache = [NSMutableDictionary new];
|
2000-10-27 21:17:09 +00:00
|
|
|
fileLock = [NSLock new];
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
RELEASE(_path);
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithURL: (NSURL*)url
|
|
|
|
cached: (BOOL)cached
|
|
|
|
{
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
if ([url isFileURL] == NO)
|
|
|
|
{
|
|
|
|
NSLog(@"Attempt to init GSFileURLHandle with bad URL");
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
path = [url path];
|
|
|
|
path = [path stringByStandardizingPath];
|
|
|
|
|
|
|
|
if (cached == YES)
|
|
|
|
{
|
|
|
|
id obj;
|
|
|
|
|
2000-10-27 21:17:09 +00:00
|
|
|
[fileLock lock];
|
2000-10-30 20:43:09 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
obj = [fileCache objectForKey: path];
|
|
|
|
if (obj != nil)
|
|
|
|
{
|
|
|
|
DESTROY(self);
|
|
|
|
RETAIN(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
2000-09-21 12:31:29 +00:00
|
|
|
{
|
2001-03-03 14:49:11 +00:00
|
|
|
obj = nil;
|
2000-10-27 21:17:09 +00:00
|
|
|
[fileLock unlock];
|
2000-10-30 20:43:09 +00:00
|
|
|
[localException raise];
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
2000-10-30 20:43:09 +00:00
|
|
|
NS_ENDHANDLER
|
2000-10-27 21:17:09 +00:00
|
|
|
[fileLock unlock];
|
2000-10-30 20:43:09 +00:00
|
|
|
if (obj != nil)
|
|
|
|
{
|
|
|
|
return obj;
|
|
|
|
}
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
2000-10-27 15:58:11 +00:00
|
|
|
|
|
|
|
if ((self = [super initWithURL: url cached: cached]) != nil)
|
2000-09-21 12:31:29 +00:00
|
|
|
{
|
|
|
|
_path = [path copy];
|
|
|
|
if (cached == YES)
|
|
|
|
{
|
2000-10-27 21:17:09 +00:00
|
|
|
[fileLock lock];
|
2000-10-30 20:43:09 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
[fileCache setObject: self forKey: _path];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
[fileLock unlock];
|
|
|
|
[localException raise];
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2000-10-27 21:17:09 +00:00
|
|
|
[fileLock unlock];
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
- (NSData*) loadInForeground
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-09-21 12:31:29 +00:00
|
|
|
NSData *d = [NSData dataWithContentsOfFile: _path];
|
|
|
|
|
|
|
|
[self didLoadBytes: d loadComplete: YES];
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Gets file attribute information for the file represented by
|
|
|
|
* the handle, using the same dictionary keys as the
|
|
|
|
* <ref class="NSFileManager">NSFileManager</ref> class.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (id) propertyForKey: (NSString*)propertyKey
|
|
|
|
{
|
2000-11-18 06:40:23 +00:00
|
|
|
NSDictionary *dict;
|
|
|
|
|
|
|
|
dict = [[NSFileManager defaultManager] fileAttributesAtPath: _path
|
|
|
|
traverseLink: YES];
|
|
|
|
RELEASE(_attributes);
|
|
|
|
_attributes = [dict mutableCopy];
|
|
|
|
return [_attributes objectForKey: propertyKey];
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2000-09-21 12:31:29 +00:00
|
|
|
- (id) propertyForKeyIfAvailable: (NSString*)propertyKey
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-11-18 06:40:23 +00:00
|
|
|
return [_attributes objectForKey: propertyKey];
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Writes the specified data as the contents of the file
|
|
|
|
* represented by the handle.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (BOOL) writeData: (NSData*)data
|
1999-02-13 00:50:41 +00:00
|
|
|
{
|
2000-11-18 06:40:23 +00:00
|
|
|
if ([data writeToFile: _path atomically: YES] == YES)
|
|
|
|
{
|
|
|
|
ASSIGNCOPY(_data, data);
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
return NO;
|
2000-09-21 12:31:29 +00:00
|
|
|
}
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
/**
|
|
|
|
* Changes the attributes of the file represented by this handle.
|
|
|
|
* This method uses the same dictionary keys as the
|
|
|
|
* <ref class="NSFileManager">NSFileManger</ref> class.
|
|
|
|
*/
|
2000-09-21 12:31:29 +00:00
|
|
|
- (BOOL) writeProperty: (id)propertyValue
|
|
|
|
forKey: (NSString*)propertyKey
|
|
|
|
{
|
2000-11-18 06:40:23 +00:00
|
|
|
if ([self propertyForKey: propertyKey] == nil)
|
|
|
|
{
|
|
|
|
return NO; /* Not a valid file property key. */
|
|
|
|
}
|
|
|
|
[_attributes setObject: propertyValue forKey: propertyKey];
|
|
|
|
return [[NSFileManager defaultManager] changeFileAttributes: _attributes
|
|
|
|
atPath: _path];
|
1999-06-24 19:30:29 +00:00
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
|
|
@end
|
2000-09-21 12:31:29 +00:00
|
|
|
|