diff --git a/ChangeLog b/ChangeLog index acd7022ab..aab5df006 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2010-10-01 Richard Frith-Macdonald + + * Source/NSURL.m: Fix for bug #31153 ... allow hash in path when + initialising. + * Source/NSURLProtocol.m: Fix thread related crash with deallocation + of placeholder object. + 2010-09-30 Richard Frith-Macdonald * Source/GSFileHandle.m: diff --git a/Source/NSURL.m b/Source/NSURL.m index b7374b121..36c25937b 100644 --- a/Source/NSURL.m +++ b/Source/NSURL.m @@ -670,8 +670,11 @@ static unsigned urlAlign; { /* RFC 2396 'reserved' characters ... * as modified by RFC2732 + * static const char *reserved = ";/?:@&=+$,[]"; */ - static const char *reserved = ";/?:@&=+$,[]"; + /* Same as reserved set but allow the hash character in a path too. + */ + static const char *filepath = ";/?:@&=+$,[]#"; if ([aUrlString isKindOfClass: [NSString class]] == NO) { @@ -990,7 +993,7 @@ static unsigned urlAlign; if (buf->fragment == 0 && base != 0) { buf->fragment = base->fragment; - if (legal(buf->fragment, reserved) == NO) + if (legal(buf->fragment, filepath) == NO) { [NSException raise: NSInvalidArgumentException format: @"[%@ %@](%@, %@) " @@ -1019,7 +1022,7 @@ static unsigned urlAlign; if (buf->query == 0 && base != 0) { buf->query = base->query; - if (legal(buf->query, reserved) == NO) + if (legal(buf->query, filepath) == NO) { [NSException raise: NSInvalidArgumentException format: @"[%@ %@](%@, %@) " @@ -1048,7 +1051,7 @@ static unsigned urlAlign; if (buf->parameters == 0 && base != 0) { buf->parameters = base->parameters; - if (legal(buf->parameters, reserved) == NO) + if (legal(buf->parameters, filepath) == NO) { [NSException raise: NSInvalidArgumentException format: @"[%@ %@](%@, %@) " @@ -1086,7 +1089,7 @@ static unsigned urlAlign; { buf->hasNoPath = YES; } - if (legal(buf->path, reserved) == NO) + if (legal(buf->path, filepath) == NO) { [NSException raise: NSInvalidArgumentException format: @"[%@ %@](%@, %@) " diff --git a/Source/NSURLProtocol.m b/Source/NSURLProtocol.m index cd713c38c..c98fe46b3 100644 --- a/Source/NSURLProtocol.m +++ b/Source/NSURLProtocol.m @@ -284,8 +284,34 @@ typedef struct { static NSMutableArray *registered = nil; static NSLock *regLock = nil; static Class abstractClass = nil; +static Class placeholderClass = nil; static NSURLProtocol *placeholder = nil; +@interface NSURLProtocolPlaceholder : NSURLProtocol +@end +@implementation NSURLProtocolPlaceholder +- (void) dealloc +{ + if (self == placeholder) + { + [self retain]; + return; + } + [super dealloc]; +} +- (void) release +{ + /* In a multi-threaded environment we could have two threads release the + * class at the same time ... causing -dealloc to be called twice at the + * same time, so that we can get an exception as we try to decrement the + * retain count beyond zero. To avoid this we make the placeholder be a + * subclass whose -retain method prevents us even calling -dealoc in any + * normal circumstances. + */ + return; +} +@end + @implementation NSURLProtocol + (id) allocWithZone: (NSZone*)z @@ -313,7 +339,8 @@ static NSURLProtocol *placeholder = nil; if (registered == nil) { abstractClass = [NSURLProtocol class]; - placeholder = (NSURLProtocol*)NSAllocateObject(abstractClass, 0, + placeholderClass = [NSURLProtocolPlaceholder class]; + placeholder = (NSURLProtocol*)NSAllocateObject(placeholderClass, 0, NSDefaultMallocZone()); registered = [NSMutableArray new]; regLock = [NSLock new]; @@ -342,7 +369,7 @@ static NSURLProtocol *placeholder = nil; return NO; } -+(Class) _classToHandleRequest:(NSURLRequest *)request ++ (Class) _classToHandleRequest:(NSURLRequest *)request { Class protoClass = nil; int count; @@ -390,11 +417,6 @@ static NSURLProtocol *placeholder = nil; - (void) dealloc { - if (self == placeholder) - { - [self retain]; - return; - } if (this != 0) { [self stopLoading]; @@ -440,7 +462,7 @@ static NSURLProtocol *placeholder = nil; { if ((self = [super init]) != nil) { - if (isa != abstractClass) + if (isa != abstractClass && isa != placeholderClass) { _NSURLProtocolInternal = NSZoneCalloc([self zone], 1, sizeof(Internal)); @@ -453,7 +475,7 @@ static NSURLProtocol *placeholder = nil; cachedResponse: (NSCachedURLResponse *)cachedResponse client: (id )client { - if (isa == abstractClass) + if (isa == abstractClass || isa == placeholderClass) { unsigned count;