1
1
/** GSHTTPURLHandle.m - Class GSHTTPURLHandle
2
2
Copyright (C) 2000 Free Software Foundation, Inc.
4
Written by: Mark Allison <mark@brainstorm.co.uk>
5
Integrated: Richard Frith-Macdonald <rfm@gnu.org>
4
Written by: Mark Allison <mark@brainstorm.co.uk>
5
Integrated by: Richard Frith-Macdonald <rfm@gnu.org>
8
8
This file is part of the GNUstep Library.
10
10
This library is free software; you can redistribute it and/or
11
11
modify it under the terms of the GNU Library General Public
12
12
License as published by the Free Software Foundation; either
13
13
version 2 of the License, or (at your option) any later version.
15
15
This library is distributed in the hope that it will be useful,
16
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
18
Library General Public License for more details.
20
20
You should have received a copy of the GNU Library General Public
21
21
License along with this library; if not, write to the Free
22
22
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
25
25
#include "config.h"
26
#include <Foundation/NSArray.h>
27
#include <Foundation/NSString.h>
28
#include <Foundation/NSException.h>
29
#include <Foundation/NSValue.h>
30
#include <Foundation/NSData.h>
31
#include <Foundation/NSURL.h>
32
#include <Foundation/NSURLHandle.h>
33
#include <Foundation/NSNotification.h>
34
#include <Foundation/NSRunLoop.h>
35
#include <Foundation/NSByteOrder.h>
36
#include <Foundation/NSLock.h>
37
#include <Foundation/NSFileHandle.h>
38
#include <Foundation/NSDebug.h>
39
#include <Foundation/GSMime.h>
26
#include "Foundation/NSArray.h"
27
#include "Foundation/NSString.h"
28
#include "Foundation/NSException.h"
29
#include "Foundation/NSValue.h"
30
#include "Foundation/NSData.h"
31
#include "Foundation/NSURL.h"
32
#include "Foundation/NSURLHandle.h"
33
#include "Foundation/NSNotification.h"
34
#include "Foundation/NSRunLoop.h"
35
#include "Foundation/NSByteOrder.h"
36
#include "Foundation/NSLock.h"
37
#include "Foundation/NSFileHandle.h"
38
#include "Foundation/NSDebug.h"
39
#include "Foundation/NSHost.h"
40
#include "Foundation/NSProcessInfo.h"
41
#include "Foundation/NSPathUtilities.h"
42
#include "GNUstepBase/GSMime.h"
43
#include "GNUstepBase/GSLock.h"
40
44
#include <string.h>
42
46
#include <unistd.h>
44
48
#include <sys/file.h>
50
54
static NSString *httpVersion = @"1.1";
53
'A','B','C','D','E','F','G','H','I','J','K','L','M',
54
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
55
'a','b','c','d','e','f','g','h','i','j','k','l','m',
56
'n','o','p','q','r','s','t','u','v','w','x','y','z',
57
'0','1','2','3','4','5','6','7','8','9','+','/'
60
56
@interface GSHTTPURLHandle : NSURLHandle
64
61
NSFileHandle *sock;
66
64
NSMutableData *dat;
67
65
GSMimeParser *parser;
68
66
GSMimeDocument *document;
81
- (NSString*) encodebase64: (NSString*) input;
82
80
- (void) setDebug: (BOOL)flag;
81
- (void) _tryLoadInBackground: (NSURL*)fromURL;
86
* This is a <em>PRIVATE</em> subclass of NSURLHandle.
87
* It is documented here in order to give you information about the
88
* default behavior of an NSURLHandle created to deal with a URL
89
* that has either the <code>http</code> or <code>https</code> scheme.
90
* The name and/or other implementation details of this class
91
* may be changed at any time.
94
* A GSHTTPURLHandle instance is used to manage connections to
95
* <code>http</code> and <code>https</code> URLs.
96
* Secure connections are handled automatically
97
* (using openSSL) for URLs with the scheme <code>https</code>.
98
* Connection via proxy server is supported, as is proxy tunneling
99
* for secure connections. Basic parsing of <code>http</code>
100
* headers is performed to extract <code>http</code> status
101
* information, cookies etc. Cookies are
102
* retained and automatically sent during subsequent requests where
103
* the cookie is valid.
106
* Header information from the current page may be obtained using
107
* -propertyForKey and -propertyForKeyIfAvailable. <code>HTTP</code>
108
* status information can be retrieved as by calling either of these
109
* methods specifying one of the following keys:
113
* NSHTTPPropertyStatusCodeKey - numeric status code
116
* NSHTTPPropertyStatusReasonKey - text describing status
119
* NSHTTPPropertyServerHTTPVersionKey - <code>http</code>
120
* version supported by remote server
124
* According to MacOS-X headers, the following should also
125
* be supported, but currently are not:
128
* <item>NSHTTPPropertyRedirectionHeadersKey</item>
129
* <item>NSHTTPPropertyErrorPageDataKey</item>
132
* The omission of these headers is not viewed as important at
133
* present, since the MacOS-X public beta implementation doesn't
137
* Other calls to -propertyForKey and -propertyForKeyIfAvailable may
138
* be made specifying a <code>http</code> header field name.
139
* For example specifying a key name of "Content-Length"
140
* would return the value of the "Content-Length" header
144
* [GSHTTPURLHandle-writeProperty:forKey:]
145
* can be used to specify the parameters
146
* for the <code>http</code> request. The default request uses the
147
* "GET" method when fetching a page, and the
148
* "POST" method when using -writeData:.
149
* This can be over-ridden by calling -writeProperty:forKey: with
150
* the key name "GSHTTPPropertyMethodKey" and specifying an
151
* alternative method (i.e "PUT").
154
* A Proxy may be specified by calling -writeProperty:forKey:
155
* with the keys "GSHTTPPropertyProxyHostKey" and
156
* "GSHTTPPropertyProxyPortKey" to set the host and port
157
* of the proxy server respectively. The GSHTTPPropertyProxyHostKey
158
* property can be set to either the IP address or the hostname of
159
* the proxy server. If an attempt is made to load a page via a
160
* secure connection when a proxy is specified, GSHTTPURLHandle will
161
* attempt to open an SSL Tunnel through the proxy.
164
* Requests to the remote server may be forced to be bound to a
165
* particular local IP address by using the key
166
* "GSHTTPPropertyLocalHostKey" which must contain the
167
* IP address of a network interface on the local host.
86
170
@implementation GSHTTPURLHandle
88
172
static NSMutableDictionary *urlCache = nil;
91
175
static Class sslClass = 0;
93
177
static NSLock *debugLock = nil;
94
static char debugFile[128];
178
static NSString *debugFile;
96
static void debugRead(NSData *data)
180
static void debugRead(GSHTTPURLHandle *handle, NSData *data)
101
185
[debugLock lock];
102
d = open(debugFile, O_WRONLY|O_CREAT|O_APPEND, 0644);
186
d = open([debugFile fileSystemRepresentation],
187
O_WRONLY|O_CREAT|O_APPEND, 0644);
105
s = [NSString stringWithFormat: @"\nRead %@ %u bytes - '",
106
[NSDate date], [data length]];
190
s = [NSString stringWithFormat: @"\nRead for %x at %@ %u bytes - '",
191
handle, [NSDate date], [data length]];
107
192
write(d, [s cString], [s cStringLength]);
108
193
write(d, [data bytes], [data length]);
109
194
write(d, "'", 1);
112
197
[debugLock unlock];
114
static void debugWrite(NSData *data)
199
static void debugWrite(GSHTTPURLHandle *handle, NSData *data)
119
204
[debugLock lock];
120
d = open(debugFile, O_WRONLY|O_CREAT|O_APPEND, 0644);
205
d = open([debugFile fileSystemRepresentation],
206
O_WRONLY|O_CREAT|O_APPEND, 0644);
123
s = [NSString stringWithFormat: @"\nWrite %@ %u bytes - '",
124
[NSDate date], [data length]];
209
s = [NSString stringWithFormat: @"\nWrite for %x at %@ %u bytes - '",
210
handle, [NSDate date], [data length]];
125
211
write(d, [s cString], [s cStringLength]);
126
212
write(d, [data bytes], [data length]);
127
213
write(d, "'", 1);
305
- (void) bgdApply: (NSString*)basic
307
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
308
NSEnumerator *wpEnumerator;
314
if (debug == YES) NSLog(@"%@", NSStringFromSelector(_cmd));
316
s = [basic mutableCopy];
317
if ([[u query] length] > 0)
319
[s appendFormat: @"?%@", [u query]];
322
version = [request objectForKey: NSHTTPPropertyServerHTTPVersionKey];
325
version = httpVersion;
327
[s appendFormat: @" HTTP/%@\r\n", version];
329
if ([wProperties objectForKey: @"host"] == nil)
331
[wProperties setObject: [u host] forKey: @"host"];
334
if ([wData length] > 0)
336
[wProperties setObject: [NSString stringWithFormat: @"%d", [wData length]]
337
forKey: @"content-length"];
339
* Assume content type if not specified.
341
if ([wProperties objectForKey: @"content-type"] == nil)
343
[wProperties setObject: @"application/x-www-form-urlencoded"
344
forKey: @"content-type"];
347
if ([wProperties objectForKey: @"authorization"] == nil)
353
if ([[u password] length] > 0)
355
auth = [NSString stringWithFormat: @"%@:%@",
356
[u user], [u password]];
360
auth = [NSString stringWithFormat: @"%@", [u user]];
362
auth = [NSString stringWithFormat: @"Basic %@",
363
[GSMimeDocument encodeBase64String: auth]];
364
[wProperties setObject: auth
365
forKey: @"authorization"];
369
wpEnumerator = [wProperties keyEnumerator];
370
while ((key = [wpEnumerator nextObject]))
372
[s appendFormat: @"%@: %@\r\n", key, [wProperties objectForKey: key]];
374
[wProperties removeAllObjects];
375
[s appendString: @"\r\n"];
376
buf = [[s dataUsingEncoding: NSASCIIStringEncoding] mutableCopy];
379
* Append any data to be sent
383
[buf appendData: wData];
387
* Watch for write completion.
389
[nc addObserver: self
390
selector: @selector(bgdWrite:)
391
name: GSFileHandleWriteCompletionNotification
393
connectionState = writing;
396
* Send request to server.
398
if (debug == YES) debugWrite(self, buf);
399
[sock writeInBackgroundAndNotify: buf];
214
404
- (void) bgdRead: (NSNotification*) not
216
406
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
217
407
NSDictionary *dict = [not userInfo];
220
411
d = [dict objectForKey: NSFileHandleNotificationDataItem];
221
if (debug == YES) debugRead(d);
412
if (debug == YES) debugRead(self, d);
224
if ([parser isComplete] == YES)
414
if ([parser parse: d] == NO)
229
connectionState = idle;
230
[nc removeObserver: self
231
name: NSFileHandleReadCompletionNotification
236
* Retrieve essential keys from document
238
info = [document headerNamed: @"http"];
239
val = [info objectForKey: NSHTTPPropertyServerHTTPVersionKey];
241
[pageInfo setObject: val forKey: NSHTTPPropertyServerHTTPVersionKey];
242
val = [info objectForKey: NSHTTPPropertyStatusCodeKey];
244
[pageInfo setObject: val forKey: NSHTTPPropertyStatusCodeKey];
245
val = [info objectForKey: NSHTTPPropertyStatusReasonKey];
247
[pageInfo setObject: val forKey: NSHTTPPropertyStatusReasonKey];
249
* Tell superclass that we have successfully loaded the data.
251
[self didLoadBytes: [parser data] loadComplete: YES];
418
NSLog(@"HTTP parse failure - %@", parser);
420
[self endLoadInBackground];
421
[self backgroundLoadDidFailWithReason: @"Response parse failed"];
255
[sock readInBackgroundAndNotify];
425
BOOL complete = [parser isComplete];
427
if (complete == NO && [parser isInHeaders] == NO)
435
info = [document headerNamed: @"http"];
436
ver = [[info value] floatValue];
437
status = [info objectForKey: NSHTTPPropertyStatusCodeKey];
438
len = [[document headerNamed: @"content-length"] value];
439
enc = [[document headerNamed: @"content-transfer-encoding"] value];
442
enc = [[document headerNamed: @"transfer-encoding"] value];
445
if ([status isEqual: @"204"] || [status isEqual: @"304"])
447
complete = YES; // No body expected.
449
else if ([enc isEqualToString: @"chunked"] == YES)
451
complete = NO; // Read chunked body data
464
connectionState = idle;
465
[nc removeObserver: self
466
name: NSFileHandleReadCompletionNotification
469
ver = [[[document headerNamed: @"http"] value] floatValue];
470
val = [[document headerNamed: @"connection"] value];
471
if (ver < 1.1 || (val != nil && [val isEqual: @"close"] == YES))
478
* Retrieve essential keys from document
480
info = [document headerNamed: @"http"];
481
val = [info objectForKey: NSHTTPPropertyServerHTTPVersionKey];
484
[pageInfo setObject: val
485
forKey: NSHTTPPropertyServerHTTPVersionKey];
487
val = [info objectForKey: NSHTTPPropertyStatusCodeKey];
490
[pageInfo setObject: val forKey: NSHTTPPropertyStatusCodeKey];
492
val = [info objectForKey: NSHTTPPropertyStatusReasonKey];
495
[pageInfo setObject: val forKey: NSHTTPPropertyStatusReasonKey];
498
* Tell superclass that we have successfully loaded the data.
501
r = NSMakeRange(bodyPos, [d length] - bodyPos);
504
[self didLoadBytes: [d subdataWithRange: r]
510
* Report partial data if possible.
512
if ([parser isInBody])
515
r = NSMakeRange(bodyPos, [d length] - bodyPos);
516
bodyPos = [d length];
517
[self didLoadBytes: [d subdataWithRange: r]
520
[sock readInBackgroundAndNotify];
303
569
- (void) loadInBackground
305
NSNotificationCenter *nc;
306
NSString *host = nil;
307
NSString *port = nil;
310
* Don't start a load if one is in progress.
312
if (connectionState != idle)
314
NSLog(@"Attempt to load an http handle which is not idle ... ignored");
321
parser = [GSMimeParser new];
322
document = RETAIN([parser document]);
323
[self beginLoadInBackground];
330
if ([[request objectForKey: GSHTTPPropertyProxyHostKey] length] == 0)
334
if ([[url scheme] isEqualToString: @"https"])
338
[self backgroundLoadDidFailWithReason:
339
@"https not supported ... needs SSL bundle"];
343
fileHandleAsClientInBackgroundAtAddress: host
350
fileHandleAsClientInBackgroundAtAddress: host
357
if ([[request objectForKey: GSHTTPPropertyProxyPortKey] length] == 0)
359
[request setObject: @"8080" forKey: GSHTTPPropertyProxyPortKey];
361
if ([[url scheme] isEqualToString: @"https"])
365
[self backgroundLoadDidFailWithReason:
366
@"https not supported ... needs SSL bundle"];
369
host = [request objectForKey: GSHTTPPropertyProxyHostKey];
370
port = [request objectForKey: GSHTTPPropertyProxyPortKey];
372
fileHandleAsClientInBackgroundAtAddress: host
378
host = [request objectForKey: GSHTTPPropertyProxyHostKey];
379
port = [request objectForKey: GSHTTPPropertyProxyPortKey];
381
fileHandleAsClientInBackgroundAtAddress: host
389
* Tell superclass that the load failed - let it do housekeeping.
391
[self backgroundLoadDidFailWithReason: [NSString stringWithFormat:
392
@"Unable to connect to %@:%@", host, port]];
396
nc = [NSNotificationCenter defaultCenter];
397
[nc addObserver: self
398
selector: @selector(bgdConnect:)
399
name: GSFileHandleConnectCompletionNotification
401
connectionState = connecting;
571
[self _tryLoadInBackground: nil];
404
574
- (void) endLoadInBackground
406
577
if (connectionState != idle)
408
579
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
556
740
if ([[request objectForKey: GSHTTPPropertyProxyHostKey] length] > 0
557
&& [[url scheme] isEqualToString: @"https"] == NO)
741
&& [[u scheme] isEqualToString: @"https"] == NO)
559
s = [[NSMutableString alloc] initWithFormat: @"%@ http://%@%@",
560
method, [url host], [url path]];
561
if ([[url query] length] > 0)
563
[s appendFormat: @"?%@", [url query]];
565
[s appendFormat: @" HTTP/%@\r\n", httpVersion];
745
s = [[NSMutableString alloc] initWithFormat: @"%@ http://%@%@",
746
method, [u host], path];
750
s = [[NSMutableString alloc] initWithFormat: @"%@ http://%@:%@%@",
751
method, [u host], [u port], path];
569
s = [[NSMutableString alloc] initWithFormat: @"%@ %@",
571
if ([[url query] length] > 0)
573
[s appendFormat: @"?%@", [url query]];
575
[s appendFormat: @" HTTP/%@\nHost: %@\r\n", httpVersion, [url host]];
578
if ([wData length] > 0)
580
[wProperties setObject: [NSString stringWithFormat: @"%d", [wData length]]
581
forKey: @"content-length"];
583
* Assume content type if not specified.
585
if ([wProperties objectForKey: @"content-type"] == nil)
587
[wProperties setObject: @"application/x-www-form-urlencoded"
588
forKey: @"content-type"];
591
if ([url user] != nil)
595
if ([[url password] length] > 0)
597
auth = [NSString stringWithFormat: @"%@:%@",
598
[url user], [url password]];
602
auth = [NSString stringWithFormat: @"%@", [url user]];
604
auth = [NSString stringWithFormat: @"Basic %@",
605
[self encodebase64: auth]];
606
[wProperties setObject: auth
607
forKey: @"Authorization"];
609
wpEnumerator = [wProperties keyEnumerator];
610
while ((key = [wpEnumerator nextObject]))
612
[s appendFormat: @"%@: %@\r\n", key, [wProperties objectForKey: key]];
614
[wProperties removeAllObjects];
615
[s appendString: @"\n"];
616
buf = [[s dataUsingEncoding: NSASCIIStringEncoding] mutableCopy];
619
* Append any data to be sent
623
[buf appendData: wData];
628
* Send request to server.
630
[sock writeInBackgroundAndNotify: buf];
631
if (debug == YES) debugWrite(buf);
756
s = [[NSMutableString alloc] initWithFormat: @"%@ %@",
636
* Watch for write completion.
638
[nc addObserver: self
639
selector: @selector(bgdWrite:)
640
name: GSFileHandleWriteCompletionNotification
642
connectionState = writing;
645
764
- (void) bgdWrite: (NSNotification*)notification
766
NSNotificationCenter *nc;
647
767
NSDictionary *userInfo = [notification userInfo];
770
if (debug == YES) NSLog(@"%@", NSStringFromSelector(_cmd));
650
771
e = [userInfo objectForKey: GSFileHandleNotificationError];
775
if (keepalive == YES)
778
* The write failed ... connection dropped ... and we
779
* are re-using an existing connection (keepalive = YES)
780
* then we may try again with a new connection.
782
nc = [NSNotificationCenter defaultCenter];
783
[nc removeObserver: self
784
name: GSFileHandleWriteCompletionNotification
788
connectionState = idle;
789
[self _tryLoadInBackground: u];
654
792
NSLog(@"Failed to write command to socket - %@", e);
656
794
* Tell superclass that the load failed - let it do housekeeping.
903
- (void) _tryLoadInBackground: (NSURL*)fromURL
905
NSNotificationCenter *nc;
906
NSString *host = nil;
907
NSString *port = nil;
911
* Don't start a load if one is in progress.
913
if (connectionState != idle)
915
NSLog(@"Attempt to load an http handle which is not idle ... ignored");
922
parser = [GSMimeParser new];
923
document = RETAIN([parser mimeDocument]);
926
* First time round, fromURL is nil, so we use the url ivar and
927
* we notify that the load is begining. On retries we get a real
928
* value in fromURL to use.
934
[self beginLoadInBackground];
945
port = [NSString stringWithFormat: @"%u", [port intValue]];
951
if ([port isEqualToString: @"https"])
955
else if ([port isEqualToString: @"http"])
962
keepalive = NO; // New connection
964
* If we have a local address specified,
965
* tell the file handle to bind to it.
967
s = [request objectForKey: GSHTTPPropertyLocalHostKey];
970
s = [NSString stringWithFormat: @"bind-%@", s];
974
s = @"tcp"; // Bind to any.
977
if ([[request objectForKey: GSHTTPPropertyProxyHostKey] length] == 0)
979
if ([[u scheme] isEqualToString: @"https"])
985
[self backgroundLoadDidFailWithReason:
986
@"https not supported ... needs SSL bundle"];
989
sock = [sslClass fileHandleAsClientInBackgroundAtAddress: host
992
cert = [request objectForKey: GSHTTPPropertyCertificateFileKey];
993
if ([cert length] > 0)
998
key = [request objectForKey: GSHTTPPropertyKeyFileKey];
999
pwd = [request objectForKey: GSHTTPPropertyPasswordKey];
1000
[sock sslSetCertificate: cert privateKey: key PEMpasswd: pwd];
1005
sock = [NSFileHandle fileHandleAsClientInBackgroundAtAddress: host
1012
if ([[request objectForKey: GSHTTPPropertyProxyPortKey] length] == 0)
1014
[request setObject: @"8080" forKey: GSHTTPPropertyProxyPortKey];
1016
if ([[u scheme] isEqualToString: @"https"])
1020
[self backgroundLoadDidFailWithReason:
1021
@"https not supported ... needs SSL bundle"];
1024
host = [request objectForKey: GSHTTPPropertyProxyHostKey];
1025
port = [request objectForKey: GSHTTPPropertyProxyPortKey];
1026
sock = [sslClass fileHandleAsClientInBackgroundAtAddress: host
1032
host = [request objectForKey: GSHTTPPropertyProxyHostKey];
1033
port = [request objectForKey: GSHTTPPropertyProxyPortKey];
1034
sock = [NSFileHandle
1035
fileHandleAsClientInBackgroundAtAddress: host
1045
* Tell superclass that the load failed - let it do housekeeping.
1047
[self backgroundLoadDidFailWithReason: [NSString stringWithFormat:
1048
@"Unable to connect to %@:%@ ... %s",
1049
host, port, GSLastErrorStr(errno)]];
1053
nc = [NSNotificationCenter defaultCenter];
1054
[nc addObserver: self
1055
selector: @selector(bgdConnect:)
1056
name: GSFileHandleConnectCompletionNotification
1058
connectionState = connecting;
1066
keepalive = YES; // Reusing a connection.
1067
method = [request objectForKey: GSHTTPPropertyMethodKey];
1070
if ([wData length] > 0)
1079
path = [[u path] stringByTrimmingSpaces];
1080
if ([path length] == 0)
1084
basic = [NSString stringWithFormat: @"%@ %@", method, path];
1085
[self bgdApply: basic];
1090
* Writes the specified data as the body of an <code>http</code>
1091
* or <code>https</code> request to the web server.
1092
* Returns YES on success,
1093
* NO on failure. By default, this method performs a POST operation.
1094
* On completion, the resource data for this handle is set to the
1095
* page returned by the request.
740
1097
- (BOOL) writeData: (NSData*)d
742
1099
ASSIGN(wData, d);
1104
* Sets a property to be used in the next request made by this handle.
1105
* The property is set as a header in the next request, unless it is
1106
* one of the following -
1109
* GSHTTPPropertyBodyKey - set an NSData item to be sent to
1110
* the server as the body of the request.
1113
* GSHTTPPropertyMethodKey - override the default method of
1114
* the request (eg. "PUT").
1117
* GSHTTPPropertyProxyHostKey - specify the name or IP address
1118
* of a host to proxy through.
1121
* GSHTTPPropertyProxyPortKey - specify the port number to
1122
* connect to on the proxy host. If not give, this defaults
1123
* to 8080 for <code>http</code> and 4430 for <code>https</code>.
1126
* Any NSHTTPProperty... key
746
1130
- (BOOL) writeProperty: (id) property forKey: (NSString*) propertyKey
748
if (propertyKey == nil || [propertyKey isKindOfClass: [NSString class]] == NO)
1132
if (propertyKey == nil
1133
|| [propertyKey isKindOfClass: [NSString class]] == NO)
750
1135
[NSException raise: NSInvalidArgumentException
751
1136
format: @"%@ with invalid key", NSStringFromSelector(_cmd)];
753
if ([propertyKey hasPrefix: @"GSHTTPProperty"])
1138
if ([propertyKey hasPrefix: @"GSHTTPProperty"]
1139
|| [propertyKey hasPrefix: @"NSHTTPProperty"])
755
1141
if (property == nil)
779
- (NSString*) encodebase64: (NSString*) input
781
char *str = calloc([input length], sizeof(char));
783
NSMutableString *nstr = [NSMutableString string];
786
strcpy(str, [input cString]);
788
for (i=0; i < [input length]; i += 3)
790
[nstr appendFormat: @"%c", emp[*sptr >> 2]];
791
[nstr appendFormat: @"%c",
792
emp[((*sptr << 4) & 060) | ((sptr[1] >> 4) & 017)]];
793
[nstr appendFormat: @"%c",
794
emp[((sptr[1] << 2) & 074) | ((sptr[2] >> 6) & 03)]];
795
[nstr appendFormat: @"%c", emp[sptr[2] & 077]];
799
/* If len was not a multiple of 3, then we have encoded too
800
* many characters. Adjust appropriately.
802
if (i == [input length] + 1)
804
/* There were only 2 bytes in that last group */
805
[nstr deleteCharactersInRange: NSMakeRange([nstr length] - 1, 1)];
807
else if (i == [input length] + 2)
809
/* There was only 1 byte in that last group */
810
[nstr deleteCharactersInRange: NSMakeRange([nstr length] - 2, 2)];