mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-11 16:50:42 +00:00
Merge branch 'master' of github.com:gnustep/libs-base
This commit is contained in:
commit
ccfb05525e
6 changed files with 195 additions and 87 deletions
|
@ -34,7 +34,7 @@
|
|||
also contain commas, most notably in the Expires field (which is not quoted
|
||||
and can contain spaces as well). The last key/value does not have to have a
|
||||
semi-colon, so this can be tricky to parse if another cookie occurs
|
||||
after this (See GSRangeOfCookie).
|
||||
after this (See GSCookieStrings).
|
||||
*/
|
||||
|
||||
#import "common.h"
|
||||
|
@ -114,7 +114,7 @@ static const unsigned char whitespace[32] = {
|
|||
#define GS_IS_WHITESPACE(X) IS_BIT_SET(whitespace[(X)/8], (X) % 8)
|
||||
|
||||
static id GSPropertyListFromCookieFormat(NSString *string, int version);
|
||||
static NSRange GSRangeOfCookie(NSString *string);
|
||||
static NSMutableArray *GSCookieStrings(NSString *string);
|
||||
|
||||
@implementation NSHTTPCookie
|
||||
|
||||
|
@ -141,36 +141,42 @@ static NSRange GSRangeOfCookie(NSString *string);
|
|||
forHeader: (NSString *)header
|
||||
andURL: (NSURL *)url
|
||||
{
|
||||
int version;
|
||||
NSString *defaultPath, *defaultDomain;
|
||||
NSMutableArray *a;
|
||||
int version;
|
||||
NSString *defaultPath;
|
||||
NSString *defaultDomain;
|
||||
NSMutableArray *cookies;
|
||||
NSUInteger count;
|
||||
|
||||
if ([header isEqual: @"Set-Cookie"])
|
||||
version = 0;
|
||||
{
|
||||
version = 0;
|
||||
}
|
||||
else if ([header isEqual: @"Set-Cookie2"])
|
||||
version = 1;
|
||||
{
|
||||
version = 1;
|
||||
}
|
||||
else
|
||||
return nil;
|
||||
|
||||
a = [NSMutableArray array];
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
defaultDomain = [url host];
|
||||
defaultPath = [url path];
|
||||
if ([[url absoluteString] hasSuffix: @"/"] == NO)
|
||||
defaultPath = [defaultPath stringByDeletingLastPathComponent];
|
||||
{
|
||||
defaultPath = [defaultPath stringByDeletingLastPathComponent];
|
||||
}
|
||||
|
||||
cookies = GSCookieStrings(field);
|
||||
count = [cookies count];
|
||||
/* We could use an NSScanner here, but this string could contain all
|
||||
sorts of odd stuff. It's not quite a property list either - it has
|
||||
dates and also could have tokens without values. */
|
||||
while (1)
|
||||
while (count-- > 0)
|
||||
{
|
||||
NSHTTPCookie *cookie;
|
||||
NSMutableDictionary *dict;
|
||||
NSString *onecookie;
|
||||
NSRange range = GSRangeOfCookie(field);
|
||||
NSHTTPCookie *cookie;
|
||||
NSMutableDictionary *dict;
|
||||
NSString *onecookie = [cookies objectAtIndex: count];
|
||||
|
||||
if (range.location == NSNotFound)
|
||||
break;
|
||||
onecookie = [field substringWithRange: range];
|
||||
NS_DURING
|
||||
dict = GSPropertyListFromCookieFormat(onecookie, version);
|
||||
NS_HANDLER
|
||||
|
@ -179,18 +185,25 @@ static NSRange GSRangeOfCookie(NSString *string);
|
|||
if ([dict count])
|
||||
{
|
||||
if ([dict objectForKey: NSHTTPCookiePath] == nil)
|
||||
[dict setObject: defaultPath forKey: NSHTTPCookiePath];
|
||||
{
|
||||
[dict setObject: defaultPath forKey: NSHTTPCookiePath];
|
||||
}
|
||||
if ([dict objectForKey: NSHTTPCookieDomain] == nil)
|
||||
[dict setObject: defaultDomain forKey: NSHTTPCookieDomain];
|
||||
{
|
||||
[dict setObject: defaultDomain forKey: NSHTTPCookieDomain];
|
||||
}
|
||||
cookie = [NSHTTPCookie cookieWithProperties: dict];
|
||||
if (cookie)
|
||||
[a addObject: cookie];
|
||||
{
|
||||
[cookies replaceObjectAtIndex: count withObject: cookie];
|
||||
}
|
||||
else
|
||||
{
|
||||
[cookies removeObjectAtIndex: count];
|
||||
}
|
||||
}
|
||||
if ([field length] <= NSMaxRange(range))
|
||||
break;
|
||||
field = [field substringFromIndex: NSMaxRange(range)+1];
|
||||
}
|
||||
return a;
|
||||
return cookies;
|
||||
}
|
||||
|
||||
+ (NSArray *) cookiesWithResponseHeaderFields: (NSDictionary *)headerFields
|
||||
|
@ -833,72 +846,139 @@ GSPropertyListFromCookieFormat(NSString *string, int version)
|
|||
return AUTORELEASE(dict);
|
||||
}
|
||||
|
||||
/* Look for the comma that separates cookies. Commas can also occur in
|
||||
date strings, like "expires", but perhaps it can occur other places.
|
||||
For instance, the key/value pair key=value1,value2 is not really
|
||||
valid, but should we handle it anyway? Definitely we should handle the
|
||||
perfectly normal case of:
|
||||
|
||||
Set-Cookie: domain=test.com; expires=Thu, 12-Sep-2109 14:58:04 GMT;
|
||||
session=foo
|
||||
Set-Cookie: bar=baz
|
||||
|
||||
which gets concatenated into something like:
|
||||
|
||||
Set-Cookie: domain=test.com; expires=Thu, 12-Sep-2109 14:58:04 GMT;
|
||||
session=foo,bar=baz
|
||||
|
||||
*/
|
||||
static NSRange
|
||||
GSRangeOfCookie(NSString *string)
|
||||
/* Split a string containing comma seprated cookeie settings into an array
|
||||
* of individual cookie specifications.
|
||||
* Look for the comma that separates cookies. Commas can also occur in
|
||||
* date strings, like "expires", but perhaps it can occur other places.
|
||||
* For instance, the key/value pair key=value1,value2 is not really
|
||||
* valid, but should we handle it anyway? Definitely we should handle the
|
||||
* perfectly normal case of:
|
||||
*
|
||||
* Set-Cookie: domain=test.com; expires=Thu, 12-Sep-2109 14:58:04 GMT;
|
||||
* session=foo
|
||||
* Set-Cookie: bar=baz
|
||||
*
|
||||
* which gets concatenated into something like:
|
||||
*
|
||||
* Set-Cookie: domain=test.com; expires=Thu, 12-Sep-2109 14:58:04 GMT;
|
||||
* session=foo,bar=baz
|
||||
*/
|
||||
static NSMutableArray*
|
||||
GSCookieStrings(NSString *string)
|
||||
{
|
||||
pldata _pld;
|
||||
pldata *pld = &_pld;
|
||||
unsigned char *ptr;
|
||||
unsigned pos;
|
||||
unsigned end;
|
||||
NSData *d;
|
||||
NSRange range;
|
||||
NSMutableArray *cookies;
|
||||
unsigned start = 0;
|
||||
unsigned saved = 0;
|
||||
|
||||
/*
|
||||
* An empty string is a nil property list.
|
||||
*/
|
||||
range = NSMakeRange(NSNotFound, NSNotFound);
|
||||
if ([string length] == 0)
|
||||
{
|
||||
return range;
|
||||
return nil;
|
||||
}
|
||||
|
||||
d = [string dataUsingEncoding: NSUTF8StringEncoding];
|
||||
NSCAssert(d, @"Couldn't get utf8 data from string.");
|
||||
_pld.ptr = (unsigned char*)[d bytes];
|
||||
_pld.pos = 0;
|
||||
_pld.end = [d length];
|
||||
_pld.err = nil;
|
||||
_pld.lin = 0;
|
||||
_pld.opt = 0;
|
||||
_pld.key = NO;
|
||||
_pld.old = YES; // OpenStep style
|
||||
ptr = (unsigned char*)[d bytes];
|
||||
pos = 0;
|
||||
end = [d length];
|
||||
|
||||
while (skipSpace(pld) == YES)
|
||||
cookies = [NSMutableArray arrayWithCapacity: 4];
|
||||
while (pos < end)
|
||||
{
|
||||
if (pld->ptr[pld->pos] == ',')
|
||||
while (pos < end && isspace(ptr[pos]))
|
||||
{
|
||||
/* Look ahead for something that will tell us if this is a
|
||||
separate cookie or not */
|
||||
unsigned saved_pos = pld->pos;
|
||||
while (pld->ptr[pld->pos] != '=' && pld->ptr[pld->pos] != ';'
|
||||
&& pld->ptr[pld->pos] != ',' && pld->pos < pld->end )
|
||||
pld->pos++;
|
||||
if (pld->ptr[pld->pos] == '=')
|
||||
{
|
||||
/* Separate comment */
|
||||
range = NSMakeRange(0, saved_pos-1);
|
||||
break;
|
||||
}
|
||||
pld->pos = saved_pos;
|
||||
pos++;
|
||||
}
|
||||
pld->pos++;
|
||||
}
|
||||
if (range.location == NSNotFound)
|
||||
range = NSMakeRange(0, [string length]);
|
||||
start = pos;
|
||||
|
||||
return range;
|
||||
while (pos < end)
|
||||
{
|
||||
if (ptr[pos] == ',')
|
||||
{
|
||||
/* Look ahead for something that will tell us if this is a
|
||||
* separate cookie or not. We look for something of the form
|
||||
* ' token =' where a space represents any optional whitespace.
|
||||
*/
|
||||
saved = pos++;
|
||||
while (pos < end && isspace(ptr[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
if (pos < end)
|
||||
{
|
||||
const char *bad = "()<>@,;:\\\"/[]?={}";
|
||||
int c = ptr[pos];
|
||||
|
||||
/* skip past token characters.
|
||||
*/
|
||||
while (c > 32 && c < 128 && strchr(bad, c) == 0)
|
||||
{
|
||||
pos++;
|
||||
if (pos < end)
|
||||
{
|
||||
c = ptr[pos];
|
||||
}
|
||||
}
|
||||
while (pos < end && isspace(ptr[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
if (pos < end && '=' == ptr[pos])
|
||||
{
|
||||
pos = saved + 1;
|
||||
/* We found a comma separator: so make the text before
|
||||
* the comma a cooke string as long as it is not empty.
|
||||
*/
|
||||
while (saved > start
|
||||
&& isspace(ptr[saved - 1]))
|
||||
{
|
||||
saved--;
|
||||
}
|
||||
if (saved > start)
|
||||
{
|
||||
NSString *str = [NSString alloc];
|
||||
|
||||
str = [str initWithBytes: ptr + start
|
||||
length: saved - start
|
||||
encoding: NSUTF8StringEncoding];
|
||||
[cookies addObject: str];
|
||||
RELEASE(str);
|
||||
}
|
||||
start = saved = pos;
|
||||
}
|
||||
}
|
||||
pos = saved;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
if (pos > start)
|
||||
{
|
||||
/* There was data after the last comma; make it into a cookie string
|
||||
* as long as it's not empty after removing spaces
|
||||
*/
|
||||
saved = pos;
|
||||
while (saved > start
|
||||
&& isspace(ptr[saved - 1]))
|
||||
{
|
||||
saved--;
|
||||
}
|
||||
if (saved > start)
|
||||
{
|
||||
NSString *str = [NSString alloc];
|
||||
|
||||
/* There may not be room to add a nul terminator, so we use an
|
||||
* initialiser which doesn't need one.
|
||||
*/
|
||||
str = [str initWithBytes: ptr + start
|
||||
length: saved - start
|
||||
encoding: NSUTF8StringEncoding];
|
||||
[cookies addObject: str];
|
||||
RELEASE(str);
|
||||
}
|
||||
}
|
||||
return cookies; // The individual cookies
|
||||
}
|
||||
|
|
|
@ -1100,9 +1100,18 @@ static NSOperationQueue *mainQueue = nil;
|
|||
|| (pending > 0 && internal->threadCount < POOL))
|
||||
{
|
||||
internal->threadCount++;
|
||||
[NSThread detachNewThreadSelector: @selector(_thread)
|
||||
toTarget: self
|
||||
withObject: nil];
|
||||
NS_DURING
|
||||
{
|
||||
[NSThread detachNewThreadSelector: @selector(_thread)
|
||||
toTarget: self
|
||||
withObject: nil];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
NSLog(@"Failed to create thread for %@: %@",
|
||||
self, localException);
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
/* Tell the thread pool that there is an operation to start.
|
||||
*/
|
||||
|
|
|
@ -114,12 +114,29 @@ typedef struct {
|
|||
{
|
||||
GSMimeHeader *h;
|
||||
|
||||
/* Remove existing headers matching the ones we are setting.
|
||||
*/
|
||||
e = [(NSArray*)headers objectEnumerator];
|
||||
while ((h = [e nextObject]) != nil)
|
||||
{
|
||||
NSString *n = [h namePreservingCase: YES];
|
||||
|
||||
[this->headers removeObjectForKey: n];
|
||||
}
|
||||
/* Set new headers, joining values where we have multiple headers
|
||||
* with the same name.
|
||||
*/
|
||||
e = [(NSArray*)headers objectEnumerator];
|
||||
while ((h = [e nextObject]) != nil)
|
||||
{
|
||||
NSString *n = [h namePreservingCase: YES];
|
||||
NSString *o = [this->headers objectForKey: n];
|
||||
NSString *v = [h fullValue];
|
||||
|
||||
if (nil != o)
|
||||
{
|
||||
n = [NSString stringWithFormat: @"%@, %@", o, n];
|
||||
}
|
||||
[self _setValue: v forHTTPHeaderField: n];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,14 +39,15 @@ int main()
|
|||
PASS(cookie == nil, "cookie without path returns nil");
|
||||
|
||||
dict = [NSDictionary dictionaryWithObject:
|
||||
@"S=calendar=R7tjDKqNB5L8YTZSvf29Bg;Expires=Wed, 09-Mar-2011 23:00:35 GMT"
|
||||
@"S=calendar=R7tjDKqNB5L8YTZSvf29Bg;Expires=Wed, 09-Mar-2011 23:00:35 GMT, "
|
||||
@"S=xxxxxxxx=R7tjDKqNB5L8YTZSvf29Bg;Expires=Thu, 10-Mar-2011 23:00:35 GMT"
|
||||
forKey: @"Set-Cookie"];
|
||||
|
||||
url = [NSURL URLWithString: @"http://www.google.com/calendar/feeds/default/"];
|
||||
cookies= [NSHTTPCookie cookiesWithResponseHeaderFields: dict forURL: url];
|
||||
TEST_FOR_CLASS(@"NSArray", cookies,
|
||||
"NSHTTPCookie +cookiesWithResponseHeaderFields: returns an NSArray");
|
||||
PASS([cookies count ] == 1, "cookies array contains a cookie");
|
||||
PASS([cookies count ] == 2, "cookies array contains two cookies");
|
||||
cookie = [cookies objectAtIndex: 0];
|
||||
PASS([[cookie name] isEqual: @"S"], "NSHTTPCookie returns proper name");
|
||||
PASS([[cookie value] isEqual: @"calendar=R7tjDKqNB5L8YTZSvf29Bg"],
|
||||
|
@ -56,6 +57,7 @@ int main()
|
|||
PASS(![cookie isSecure], "Cookie is not secure");
|
||||
PASS(![cookie isHTTPOnly], "Cookie is not http only");
|
||||
|
||||
cookies = [cookies subarrayWithRange: NSMakeRange(0, 1)];
|
||||
dict = [NSHTTPCookie requestHeaderFieldsWithCookies: cookies];
|
||||
PASS_EQUAL([dict objectForKey: @"Cookie"],
|
||||
@"S=calendar=R7tjDKqNB5L8YTZSvf29Bg",
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -2727,6 +2727,7 @@ fi
|
|||
if test -z "$LIBRARY_COMBO"; then
|
||||
LIBRARY_COMBO=`gnustep-config --variable=LIBRARY_COMBO 2>&5`
|
||||
fi
|
||||
OBJC_RUNTIME_LIB=`echo $LIBRARY_COMBO | tr '-' ' ' | awk '{print $1}'`
|
||||
|
||||
if test "$OBJC_RUNTIME_LIB" = "ng" -o "$OBJC_RUNTIME_LIB" = "apple"; then
|
||||
nonfragile=yes
|
||||
|
@ -6003,7 +6004,6 @@ esac
|
|||
#--------------------------------------------------------------------
|
||||
# Set Apple/Darwin/OSX/NeXT information for other tests
|
||||
#--------------------------------------------------------------------
|
||||
OBJC_RUNTIME_LIB=`echo $LIBRARY_COMBO | tr '-' ' ' | awk '{print $1}'`
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the Objective-C runtime" >&5
|
||||
$as_echo_n "checking the Objective-C runtime... " >&6; }
|
||||
if test "$OBJC_RUNTIME_LIB" = "nx" -o "$OBJC_RUNTIME_LIB" = "apple"; then
|
||||
|
|
|
@ -89,6 +89,7 @@ fi
|
|||
if test -z "$LIBRARY_COMBO"; then
|
||||
LIBRARY_COMBO=`gnustep-config --variable=LIBRARY_COMBO 2>&5`
|
||||
fi
|
||||
OBJC_RUNTIME_LIB=`echo $LIBRARY_COMBO | tr '-' ' ' | awk '{print $1}'`
|
||||
|
||||
if test "$OBJC_RUNTIME_LIB" = "ng" -o "$OBJC_RUNTIME_LIB" = "apple"; then
|
||||
nonfragile=yes
|
||||
|
@ -1254,7 +1255,6 @@ esac
|
|||
#--------------------------------------------------------------------
|
||||
# Set Apple/Darwin/OSX/NeXT information for other tests
|
||||
#--------------------------------------------------------------------
|
||||
OBJC_RUNTIME_LIB=`echo $LIBRARY_COMBO | tr '-' ' ' | awk '{print $1}'`
|
||||
AC_MSG_CHECKING(the Objective-C runtime)
|
||||
if test "$OBJC_RUNTIME_LIB" = "nx" -o "$OBJC_RUNTIME_LIB" = "apple"; then
|
||||
AC_MSG_RESULT(NeXT)
|
||||
|
|
Loading…
Reference in a new issue