~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/network/mac/ResourceHandleMac.mm

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 
24
 */
 
25
 
 
26
#import "config.h"
 
27
#import "ResourceHandleInternal.h"
 
28
 
 
29
#if !USE(CFNETWORK)
 
30
 
 
31
#import "AuthenticationChallenge.h"
 
32
#import "AuthenticationMac.h"
 
33
#import "BlobRegistry.h"
 
34
#import "BlockExceptions.h"
 
35
#import "CookieStorage.h"
 
36
#import "CookieStorageCFNet.h"
 
37
#import "CredentialStorage.h"
 
38
#import "CachedResourceLoader.h"
 
39
#import "EmptyProtocolDefinitions.h"
 
40
#import "FormDataStreamMac.h"
 
41
#import "Frame.h"
 
42
#import "FrameLoader.h"
 
43
#import "Logging.h"
 
44
#import "MIMETypeRegistry.h"
 
45
#import "Page.h"
 
46
#import "ResourceError.h"
 
47
#import "ResourceResponse.h"
 
48
#import "SchedulePair.h"
 
49
#import "Settings.h"
 
50
#import "SharedBuffer.h"
 
51
#import "SubresourceLoader.h"
 
52
#import "WebCoreSystemInterface.h"
 
53
#import "WebCoreURLResponse.h"
 
54
#import <wtf/UnusedParam.h>
 
55
#import <wtf/text/Base64.h>
 
56
#import <wtf/text/CString.h>
 
57
 
 
58
using namespace WebCore;
 
59
 
 
60
@interface WebCoreResourceHandleAsDelegate : NSObject <NSURLConnectionDelegate> {
 
61
    ResourceHandle* m_handle;
 
62
}
 
63
- (id)initWithHandle:(ResourceHandle*)handle;
 
64
- (void)detachHandle;
 
65
@end
 
66
 
 
67
// WebCoreNSURLConnectionDelegateProxy exists so that we can cast m_proxy to it in order
 
68
// to disambiguate the argument type in the -setDelegate: call.  This avoids a spurious
 
69
// warning that the compiler would otherwise emit.
 
70
@interface WebCoreNSURLConnectionDelegateProxy : NSObject <NSURLConnectionDelegate>
 
71
- (void)setDelegate:(id<NSURLConnectionDelegate>)delegate;
 
72
@end
 
73
 
 
74
@interface NSURLConnection (Details)
 
75
-(id)_initWithRequest:(NSURLRequest *)request delegate:(id)delegate usesCache:(BOOL)usesCacheFlag maxContentLength:(long long)maxContentLength startImmediately:(BOOL)startImmediately connectionProperties:(NSDictionary *)connectionProperties;
 
76
@end
 
77
 
 
78
@interface NSURLRequest (Details)
 
79
- (id)_propertyForKey:(NSString *)key;
 
80
@end
 
81
 
 
82
class WebCoreSynchronousLoaderClient : public ResourceHandleClient {
 
83
public:
 
84
    static PassOwnPtr<WebCoreSynchronousLoaderClient> create()
 
85
    {
 
86
        return adoptPtr(new WebCoreSynchronousLoaderClient);
 
87
    }
 
88
 
 
89
    virtual ~WebCoreSynchronousLoaderClient();
 
90
 
 
91
    void setAllowStoredCredentials(bool allow) { m_allowStoredCredentials = allow; }
 
92
    NSURLResponse *response() { return m_response; }
 
93
    NSMutableData *data() { return m_data; }
 
94
    NSError *error() { return m_error; }
 
95
    bool isDone() { return m_isDone; }
 
96
 
 
97
private:
 
98
    WebCoreSynchronousLoaderClient()
 
99
        : m_allowStoredCredentials(false)
 
100
        , m_response(0)
 
101
        , m_data(0)
 
102
        , m_error(0)
 
103
        , m_isDone(false)
 
104
    {
 
105
    }
 
106
 
 
107
    virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& /*redirectResponse*/);
 
108
    virtual bool shouldUseCredentialStorage(ResourceHandle*);
 
109
    virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&);
 
110
    virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
 
111
    virtual void didReceiveData(ResourceHandle*, const char*, int, int /*encodedDataLength*/);
 
112
    virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
 
113
    virtual void didFail(ResourceHandle*, const ResourceError&);
 
114
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
 
115
    virtual bool canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&);
 
116
#endif
 
117
 
 
118
    bool m_allowStoredCredentials;
 
119
    NSURLResponse *m_response;
 
120
    NSMutableData *m_data;
 
121
    NSError *m_error;
 
122
    bool m_isDone;
 
123
};
 
124
 
 
125
namespace WebCore {
 
126
 
 
127
static void applyBasicAuthorizationHeader(ResourceRequest& request, const Credential& credential)
 
128
{
 
129
    String authenticationHeader = "Basic " + base64Encode(String(credential.user() + ":" + credential.password()).utf8());
 
130
    request.clearHTTPAuthorization(); // FIXME: Should addHTTPHeaderField be smart enough to not build comma-separated lists in headers like Authorization?
 
131
    request.addHTTPHeaderField("Authorization", authenticationHeader);
 
132
}
 
133
 
 
134
ResourceHandleInternal::~ResourceHandleInternal()
 
135
{
 
136
}
 
137
 
 
138
ResourceHandle::~ResourceHandle()
 
139
{
 
140
    releaseDelegate();
 
141
    d->m_currentWebChallenge.setAuthenticationClient(0);
 
142
 
 
143
    LOG(Network, "Handle %p destroyed", this);
 
144
}
 
145
 
 
146
static bool shouldRelaxThirdPartyCookiePolicy(NetworkingContext* context, const KURL& url)
 
147
{
 
148
    // If a URL already has cookies, then we'll relax the 3rd party cookie policy and accept new cookies.
 
149
 
 
150
    RetainPtr<CFHTTPCookieStorageRef> cfCookieStorage = currentCFHTTPCookieStorage(context);
 
151
    NSHTTPCookieAcceptPolicy cookieAcceptPolicy = static_cast<NSHTTPCookieAcceptPolicy>(wkGetHTTPCookieAcceptPolicy(cfCookieStorage.get()));
 
152
 
 
153
    if (cookieAcceptPolicy != NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain)
 
154
        return false;
 
155
 
 
156
    NSArray *cookies = wkHTTPCookiesForURL(cfCookieStorage.get(), url);
 
157
 
 
158
    return [cookies count];
 
159
}
 
160
 
 
161
void ResourceHandle::createNSURLConnection(id delegate, bool shouldUseCredentialStorage, bool shouldRelaxThirdPartyCookiePolicy, bool shouldContentSniff)
 
162
{
 
163
    // Credentials for ftp can only be passed in URL, the connection:didReceiveAuthenticationChallenge: delegate call won't be made.
 
164
    if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty()) && !firstRequest().url().protocolIsInHTTPFamily()) {
 
165
        KURL urlWithCredentials(firstRequest().url());
 
166
        urlWithCredentials.setUser(d->m_user);
 
167
        urlWithCredentials.setPass(d->m_pass);
 
168
        firstRequest().setURL(urlWithCredentials);
 
169
    }
 
170
 
 
171
    if (shouldRelaxThirdPartyCookiePolicy)
 
172
        firstRequest().setFirstPartyForCookies(firstRequest().url());
 
173
 
 
174
    if (shouldUseCredentialStorage && firstRequest().url().protocolIsInHTTPFamily()) {
 
175
        if (d->m_user.isEmpty() && d->m_pass.isEmpty()) {
 
176
            // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, 
 
177
            // try and reuse the credential preemptively, as allowed by RFC 2617.
 
178
            d->m_initialCredential = CredentialStorage::get(firstRequest().url());
 
179
        } else {
 
180
            // If there is already a protection space known for the URL, update stored credentials before sending a request.
 
181
            // This makes it possible to implement logout by sending an XMLHttpRequest with known incorrect credentials, and aborting it immediately
 
182
            // (so that an authentication dialog doesn't pop up).
 
183
            CredentialStorage::set(Credential(d->m_user, d->m_pass, CredentialPersistenceNone), firstRequest().url());
 
184
        }
 
185
    }
 
186
        
 
187
    if (!d->m_initialCredential.isEmpty()) {
 
188
        // FIXME: Support Digest authentication, and Proxy-Authorization.
 
189
        applyBasicAuthorizationHeader(firstRequest(), d->m_initialCredential);
 
190
    }
 
191
 
 
192
    NSURLRequest *nsRequest = firstRequest().nsURLRequest();
 
193
    if (!shouldContentSniff) {
 
194
        NSMutableURLRequest *mutableRequest = [[nsRequest mutableCopy] autorelease];
 
195
        wkSetNSURLRequestShouldContentSniff(mutableRequest, NO);
 
196
        nsRequest = mutableRequest;
 
197
    }
 
198
 
 
199
#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
 
200
    ASSERT([NSURLConnection instancesRespondToSelector:@selector(_initWithRequest:delegate:usesCache:maxContentLength:startImmediately:connectionProperties:)]);
 
201
    static bool supportsSettingConnectionProperties = true;
 
202
#else
 
203
    static bool supportsSettingConnectionProperties = [NSURLConnection instancesRespondToSelector:@selector(_initWithRequest:delegate:usesCache:maxContentLength:startImmediately:connectionProperties:)];
 
204
#endif
 
205
 
 
206
    if (d->m_storageSession)
 
207
        nsRequest = [wkCopyRequestWithStorageSession(d->m_storageSession.get(), nsRequest) autorelease];
 
208
 
 
209
    if (supportsSettingConnectionProperties) {
 
210
        NSDictionary *sessionID = shouldUseCredentialStorage ? [NSDictionary dictionary] : [NSDictionary dictionaryWithObject:@"WebKitPrivateSession" forKey:@"_kCFURLConnectionSessionID"];
 
211
        NSDictionary *propertyDictionary = [NSDictionary dictionaryWithObject:sessionID forKey:@"kCFURLConnectionSocketStreamProperties"];
 
212
        d->m_connection.adoptNS([[NSURLConnection alloc] _initWithRequest:nsRequest delegate:delegate usesCache:YES maxContentLength:0 startImmediately:NO connectionProperties:propertyDictionary]);
 
213
        return;
 
214
    }
 
215
 
 
216
    d->m_connection.adoptNS([[NSURLConnection alloc] initWithRequest:nsRequest delegate:delegate startImmediately:NO]);
 
217
    return;
 
218
 
 
219
}
 
220
 
 
221
bool ResourceHandle::start(NetworkingContext* context)
 
222
{
 
223
    if (!context)
 
224
        return false;
 
225
 
 
226
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
227
 
 
228
    // If NetworkingContext is invalid then we are no longer attached to a Page,
 
229
    // this must be an attempted load from an unload event handler, so let's just block it.
 
230
    if (!context->isValid())
 
231
        return false;
 
232
 
 
233
    d->m_storageSession = context->storageSession();
 
234
 
 
235
    ASSERT(!d->m_proxy);
 
236
    d->m_proxy.adoptNS(wkCreateNSURLConnectionDelegateProxy());
 
237
    [static_cast<WebCoreNSURLConnectionDelegateProxy*>(d->m_proxy.get()) setDelegate:ResourceHandle::delegate()];
 
238
 
 
239
    bool shouldUseCredentialStorage = !client() || client()->shouldUseCredentialStorage(this);
 
240
 
 
241
    d->m_needsSiteSpecificQuirks = context->needsSiteSpecificQuirks();
 
242
 
 
243
    createNSURLConnection(
 
244
        d->m_proxy.get(),
 
245
        shouldUseCredentialStorage,
 
246
        shouldRelaxThirdPartyCookiePolicy(context, firstRequest().url()),
 
247
        d->m_shouldContentSniff || context->localFileContentSniffingEnabled());
 
248
 
 
249
    bool scheduled = false;
 
250
    if (SchedulePairHashSet* scheduledPairs = context->scheduledRunLoopPairs()) {
 
251
        SchedulePairHashSet::iterator end = scheduledPairs->end();
 
252
        for (SchedulePairHashSet::iterator it = scheduledPairs->begin(); it != end; ++it) {
 
253
            if (NSRunLoop *runLoop = (*it)->nsRunLoop()) {
 
254
                [connection() scheduleInRunLoop:runLoop forMode:(NSString *)(*it)->mode()];
 
255
                scheduled = true;
 
256
            }
 
257
        }
 
258
    }
 
259
 
 
260
    if (NSOperationQueue *operationQueue = context->scheduledOperationQueue()) {
 
261
        ASSERT(!scheduled);
 
262
        [connection() setDelegateQueue:operationQueue];
 
263
        scheduled = true;
 
264
    }
 
265
 
 
266
    // Start the connection if we did schedule with at least one runloop.
 
267
    // We can't start the connection until we have one runloop scheduled.
 
268
    if (scheduled)
 
269
        [connection() start];
 
270
    else
 
271
        d->m_startWhenScheduled = true;
 
272
 
 
273
    LOG(Network, "Handle %p starting connection %p for %@", this, connection(), firstRequest().nsURLRequest());
 
274
    
 
275
    if (d->m_connection) {
 
276
        if (d->m_defersLoading)
 
277
            wkSetNSURLConnectionDefersCallbacks(connection(), YES);
 
278
 
 
279
        return true;
 
280
    }
 
281
 
 
282
    END_BLOCK_OBJC_EXCEPTIONS;
 
283
 
 
284
    return false;
 
285
}
 
286
 
 
287
void ResourceHandle::cancel()
 
288
{
 
289
    LOG(Network, "Handle %p cancel connection %p", this, d->m_connection.get());
 
290
 
 
291
    // Leaks were seen on HTTP tests without this; can be removed once <rdar://problem/6886937> is fixed.
 
292
    if (d->m_currentMacChallenge)
 
293
        [[d->m_currentMacChallenge sender] cancelAuthenticationChallenge:d->m_currentMacChallenge];
 
294
 
 
295
    [d->m_connection.get() cancel];
 
296
}
 
297
 
 
298
void ResourceHandle::platformSetDefersLoading(bool defers)
 
299
{
 
300
    if (d->m_connection)
 
301
        wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), defers);
 
302
}
 
303
 
 
304
void ResourceHandle::schedule(SchedulePair* pair)
 
305
{
 
306
    NSRunLoop *runLoop = pair->nsRunLoop();
 
307
    if (!runLoop)
 
308
        return;
 
309
    [d->m_connection.get() scheduleInRunLoop:runLoop forMode:(NSString *)pair->mode()];
 
310
    if (d->m_startWhenScheduled) {
 
311
        [d->m_connection.get() start];
 
312
        d->m_startWhenScheduled = false;
 
313
    }
 
314
}
 
315
 
 
316
void ResourceHandle::unschedule(SchedulePair* pair)
 
317
{
 
318
    if (NSRunLoop *runLoop = pair->nsRunLoop())
 
319
        [d->m_connection.get() unscheduleFromRunLoop:runLoop forMode:(NSString *)pair->mode()];
 
320
}
 
321
 
 
322
WebCoreResourceHandleAsDelegate *ResourceHandle::delegate()
 
323
{
 
324
    if (!d->m_delegate) {
 
325
        WebCoreResourceHandleAsDelegate *delegate = [[WebCoreResourceHandleAsDelegate alloc] initWithHandle:this];
 
326
        d->m_delegate = delegate;
 
327
        [delegate release];
 
328
    }
 
329
    return d->m_delegate.get();
 
330
}
 
331
 
 
332
void ResourceHandle::releaseDelegate()
 
333
{
 
334
    if (!d->m_delegate)
 
335
        return;
 
336
    if (d->m_proxy)
 
337
        [d->m_proxy.get() setDelegate:nil];
 
338
    [d->m_delegate.get() detachHandle];
 
339
    d->m_delegate = nil;
 
340
}
 
341
 
 
342
id ResourceHandle::releaseProxy()
 
343
{
 
344
    id proxy = [[d->m_proxy.get() retain] autorelease];
 
345
    d->m_proxy = nil;
 
346
    [proxy setDelegate:nil];
 
347
    return proxy;
 
348
}
 
349
 
 
350
NSURLConnection *ResourceHandle::connection() const
 
351
{
 
352
    return d->m_connection.get();
 
353
}
 
354
 
 
355
bool ResourceHandle::loadsBlocked()
 
356
{
 
357
    return false;
 
358
}
 
359
 
 
360
bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame*)
 
361
{
 
362
    request.setCachePolicy(ReturnCacheDataDontLoad);
 
363
    NSURLResponse *nsURLResponse = nil;
 
364
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
365
 
 
366
    [NSURLConnection sendSynchronousRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:nil];
 
367
    
 
368
    END_BLOCK_OBJC_EXCEPTIONS;
 
369
    
 
370
    return nsURLResponse;
 
371
}
 
372
 
 
373
CFStringRef ResourceHandle::synchronousLoadRunLoopMode()
 
374
{
 
375
    return CFSTR("WebCoreSynchronousLoaderRunLoopMode");
 
376
}
 
377
 
 
378
void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
 
379
{
 
380
    LOG(Network, "ResourceHandle::loadResourceSynchronously:%@ allowStoredCredentials:%u", request.nsURLRequest(), storedCredentials);
 
381
 
 
382
#if ENABLE(BLOB)
 
383
    if (request.url().protocolIs("blob"))
 
384
        if (blobRegistry().loadResourceSynchronously(request, error, response, data))
 
385
            return;
 
386
#endif
 
387
 
 
388
    NSError *nsError = nil;
 
389
    NSURLResponse *nsURLResponse = nil;
 
390
    NSData *result = nil;
 
391
 
 
392
    ASSERT(!request.isEmpty());
 
393
    
 
394
    OwnPtr<WebCoreSynchronousLoaderClient> client = WebCoreSynchronousLoaderClient::create();
 
395
    client->setAllowStoredCredentials(storedCredentials == AllowStoredCredentials);
 
396
 
 
397
    RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(request, client.get(), false /*defersLoading*/, true /*shouldContentSniff*/));
 
398
 
 
399
    handle->d->m_storageSession = context->storageSession();
 
400
 
 
401
    if (context && handle->d->m_scheduledFailureType != NoFailure) {
 
402
        error = context->blockedError(request);
 
403
        return;
 
404
    }
 
405
 
 
406
    handle->createNSURLConnection(
 
407
        handle->delegate(), // A synchronous request cannot turn into a download, so there is no need to proxy the delegate.
 
408
        storedCredentials == AllowStoredCredentials,
 
409
        shouldRelaxThirdPartyCookiePolicy(context, request.url()),
 
410
        handle->shouldContentSniff() || context->localFileContentSniffingEnabled());
 
411
 
 
412
    [handle->connection() scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:(NSString *)synchronousLoadRunLoopMode()];
 
413
    [handle->connection() start];
 
414
    
 
415
    while (!client->isDone())
 
416
        [[NSRunLoop currentRunLoop] runMode:(NSString *)synchronousLoadRunLoopMode() beforeDate:[NSDate distantFuture]];
 
417
 
 
418
    result = client->data();
 
419
    nsURLResponse = client->response();
 
420
    nsError = client->error();
 
421
    
 
422
    [handle->connection() cancel];
 
423
 
 
424
 
 
425
    if (!nsError)
 
426
        response = nsURLResponse;
 
427
    else {
 
428
        response = ResourceResponse(request.url(), String(), 0, String(), String());
 
429
        if ([nsError domain] == NSURLErrorDomain)
 
430
            switch ([nsError code]) {
 
431
                case NSURLErrorUserCancelledAuthentication:
 
432
                    // FIXME: we should really return the actual HTTP response, but sendSynchronousRequest doesn't provide us with one.
 
433
                    response.setHTTPStatusCode(401);
 
434
                    break;
 
435
                default:
 
436
                    response.setHTTPStatusCode([nsError code]);
 
437
            }
 
438
        else
 
439
            response.setHTTPStatusCode(404);
 
440
    }
 
441
    
 
442
    data.resize([result length]);
 
443
    memcpy(data.data(), [result bytes], [result length]);
 
444
    
 
445
    error = nsError;
 
446
}
 
447
 
 
448
void ResourceHandle::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
 
449
{
 
450
    const KURL& url = request.url();
 
451
    d->m_user = url.user();
 
452
    d->m_pass = url.pass();
 
453
    d->m_lastHTTPMethod = request.httpMethod();
 
454
    request.removeCredentials();
 
455
 
 
456
    if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) {
 
457
        // If the network layer carries over authentication headers from the original request
 
458
        // in a cross-origin redirect, we want to clear those headers here.
 
459
        // As of Lion, CFNetwork no longer does this.
 
460
        request.clearHTTPAuthorization();
 
461
    } else {
 
462
        // Only consider applying authentication credentials if this is actually a redirect and the redirect
 
463
        // URL didn't include credentials of its own.
 
464
        if (d->m_user.isEmpty() && d->m_pass.isEmpty() && !redirectResponse.isNull()) {
 
465
            Credential credential = CredentialStorage::get(request.url());
 
466
            if (!credential.isEmpty()) {
 
467
                d->m_initialCredential = credential;
 
468
                
 
469
                // FIXME: Support Digest authentication, and Proxy-Authorization.
 
470
                applyBasicAuthorizationHeader(request, d->m_initialCredential);
 
471
            }
 
472
        }
 
473
    }
 
474
 
 
475
    if (d->m_storageSession)
 
476
        request.setStorageSession(d->m_storageSession.get());
 
477
 
 
478
    client()->willSendRequest(this, request, redirectResponse);
 
479
}
 
480
 
 
481
bool ResourceHandle::shouldUseCredentialStorage()
 
482
{
 
483
    if (client())
 
484
        return client()->shouldUseCredentialStorage(this);
 
485
 
 
486
    return false;
 
487
}
 
488
 
 
489
void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
 
490
{
 
491
    ASSERT(!d->m_currentMacChallenge);
 
492
    ASSERT(d->m_currentWebChallenge.isNull());
 
493
    // Since NSURLConnection networking relies on keeping a reference to the original NSURLAuthenticationChallenge,
 
494
    // we make sure that is actually present
 
495
    ASSERT(challenge.nsURLAuthenticationChallenge());
 
496
 
 
497
#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
 
498
    // Proxy authentication is handled by CFNetwork internally. We can get here if the user cancels
 
499
    // CFNetwork authentication dialog, and we shouldn't ask the client to display another one in that case.
 
500
    if (challenge.protectionSpace().isProxy()) {
 
501
        // Cannot use receivedRequestToContinueWithoutCredential(), because current challenge is not yet set.
 
502
        [challenge.sender() continueWithoutCredentialForAuthenticationChallenge:challenge.nsURLAuthenticationChallenge()];
 
503
        return;
 
504
    }
 
505
#endif
 
506
 
 
507
    if (!d->m_user.isNull() && !d->m_pass.isNull()) {
 
508
        NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:d->m_user
 
509
                                                                   password:d->m_pass
 
510
                                                                persistence:NSURLCredentialPersistenceForSession];
 
511
        d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge();
 
512
        d->m_currentWebChallenge = challenge;
 
513
        receivedCredential(challenge, core(credential));
 
514
        [credential release];
 
515
        // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly.
 
516
        d->m_user = String();
 
517
        d->m_pass = String();
 
518
        return;
 
519
    }
 
520
 
 
521
    if (!client() || client()->shouldUseCredentialStorage(this)) {
 
522
        if (!d->m_initialCredential.isEmpty() || challenge.previousFailureCount()) {
 
523
            // The stored credential wasn't accepted, stop using it.
 
524
            // There is a race condition here, since a different credential might have already been stored by another ResourceHandle,
 
525
            // but the observable effect should be very minor, if any.
 
526
            CredentialStorage::remove(challenge.protectionSpace());
 
527
        }
 
528
 
 
529
        if (!challenge.previousFailureCount()) {
 
530
            Credential credential = CredentialStorage::get(challenge.protectionSpace());
 
531
            if (!credential.isEmpty() && credential != d->m_initialCredential) {
 
532
                ASSERT(credential.persistence() == CredentialPersistenceNone);
 
533
                if (challenge.failureResponse().httpStatusCode() == 401) {
 
534
                    // Store the credential back, possibly adding it as a default for this directory.
 
535
                    CredentialStorage::set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
 
536
                }
 
537
                [challenge.sender() useCredential:mac(credential) forAuthenticationChallenge:mac(challenge)];
 
538
                return;
 
539
            }
 
540
        }
 
541
    }
 
542
 
 
543
    d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge();
 
544
    d->m_currentWebChallenge = core(d->m_currentMacChallenge);
 
545
    d->m_currentWebChallenge.setAuthenticationClient(this);
 
546
 
 
547
    // FIXME: Several concurrent requests can return with the an authentication challenge for the same protection space.
 
548
    // We should avoid making additional client calls for the same protection space when already waiting for the user,
 
549
    // because typing the same credentials several times is annoying.
 
550
    if (client())
 
551
        client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge);
 
552
}
 
553
 
 
554
void ResourceHandle::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge)
 
555
{
 
556
    ASSERT(d->m_currentMacChallenge);
 
557
    ASSERT(d->m_currentMacChallenge == challenge.nsURLAuthenticationChallenge());
 
558
    ASSERT(!d->m_currentWebChallenge.isNull());
 
559
 
 
560
    if (client())
 
561
        client()->didCancelAuthenticationChallenge(this, challenge);
 
562
}
 
563
 
 
564
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
 
565
bool ResourceHandle::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
 
566
{
 
567
    if (client())
 
568
        return client()->canAuthenticateAgainstProtectionSpace(this, protectionSpace);
 
569
        
 
570
    return false;
 
571
}
 
572
#endif
 
573
 
 
574
void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential)
 
575
{
 
576
    ASSERT(!challenge.isNull());
 
577
    if (challenge != d->m_currentWebChallenge)
 
578
        return;
 
579
 
 
580
    // FIXME: Support empty credentials. Currently, an empty credential cannot be stored in WebCore credential storage, as that's empty value for its map.
 
581
    if (credential.isEmpty()) {
 
582
        receivedRequestToContinueWithoutCredential(challenge);
 
583
        return;
 
584
    }
 
585
 
 
586
    if (credential.persistence() == CredentialPersistenceForSession && (!d->m_needsSiteSpecificQuirks || ![[[mac(challenge) protectionSpace] host] isEqualToString:@"gallery.me.com"])) {
 
587
        // Manage per-session credentials internally, because once NSURLCredentialPersistenceForSession is used, there is no way
 
588
        // to ignore it for a particular request (short of removing it altogether).
 
589
        // <rdar://problem/6867598> gallery.me.com is temporarily whitelisted, so that QuickTime plug-in could see the credentials.
 
590
        Credential webCredential(credential, CredentialPersistenceNone);
 
591
        KURL urlToStore;
 
592
        if (challenge.failureResponse().httpStatusCode() == 401)
 
593
            urlToStore = challenge.failureResponse().url();
 
594
        CredentialStorage::set(webCredential, core([d->m_currentMacChallenge protectionSpace]), urlToStore);
 
595
        [[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge];
 
596
    } else
 
597
        [[d->m_currentMacChallenge sender] useCredential:mac(credential) forAuthenticationChallenge:d->m_currentMacChallenge];
 
598
 
 
599
    clearAuthentication();
 
600
}
 
601
 
 
602
void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& challenge)
 
603
{
 
604
    ASSERT(!challenge.isNull());
 
605
    if (challenge != d->m_currentWebChallenge)
 
606
        return;
 
607
 
 
608
    [[d->m_currentMacChallenge sender] continueWithoutCredentialForAuthenticationChallenge:d->m_currentMacChallenge];
 
609
 
 
610
    clearAuthentication();
 
611
}
 
612
 
 
613
void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challenge)
 
614
{
 
615
    if (challenge != d->m_currentWebChallenge)
 
616
        return;
 
617
 
 
618
    if (client())
 
619
        client()->receivedCancellation(this, challenge);
 
620
}
 
621
 
 
622
} // namespace WebCore
 
623
 
 
624
@implementation WebCoreResourceHandleAsDelegate
 
625
 
 
626
- (id)initWithHandle:(ResourceHandle*)handle
 
627
{
 
628
    self = [self init];
 
629
    if (!self)
 
630
        return nil;
 
631
    m_handle = handle;
 
632
    return self;
 
633
}
 
634
 
 
635
- (void)detachHandle
 
636
{
 
637
    m_handle = 0;
 
638
}
 
639
 
 
640
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
 
641
{
 
642
    UNUSED_PARAM(connection);
 
643
 
 
644
    // the willSendRequest call may cancel this load, in which case self could be deallocated
 
645
    RetainPtr<WebCoreResourceHandleAsDelegate> protect(self);
 
646
 
 
647
    if (!m_handle || !m_handle->client())
 
648
        return nil;
 
649
    
 
650
    // See <rdar://problem/5380697> .  This is a workaround for a behavior change in CFNetwork where willSendRequest gets called more often.
 
651
    if (!redirectResponse)
 
652
        return newRequest;
 
653
 
 
654
#if !LOG_DISABLED
 
655
    if ([redirectResponse isKindOfClass:[NSHTTPURLResponse class]])
 
656
        LOG(Network, "Handle %p delegate connection:%p willSendRequest:%@ redirectResponse:%d, Location:<%@>", m_handle, connection, [newRequest description], static_cast<int>([(id)redirectResponse statusCode]), [[(id)redirectResponse allHeaderFields] objectForKey:@"Location"]);
 
657
    else
 
658
        LOG(Network, "Handle %p delegate connection:%p willSendRequest:%@ redirectResponse:non-HTTP", m_handle, connection, [newRequest description]); 
 
659
#endif
 
660
 
 
661
    if ([redirectResponse isKindOfClass:[NSHTTPURLResponse class]] && [(NSHTTPURLResponse *)redirectResponse statusCode] == 307) {
 
662
        String lastHTTPMethod = m_handle->lastHTTPMethod();
 
663
        if (!equalIgnoringCase(lastHTTPMethod, String([newRequest HTTPMethod]))) {
 
664
            NSMutableURLRequest *mutableRequest = [newRequest mutableCopy];
 
665
            [mutableRequest setHTTPMethod:lastHTTPMethod];
 
666
    
 
667
            FormData* body = m_handle->firstRequest().httpBody();
 
668
            if (!equalIgnoringCase(lastHTTPMethod, "GET") && body && !body->isEmpty())
 
669
                WebCore::setHTTPBody(mutableRequest, body);
 
670
 
 
671
            String originalContentType = m_handle->firstRequest().httpContentType();
 
672
            if (!originalContentType.isEmpty())
 
673
                [mutableRequest setValue:originalContentType forHTTPHeaderField:@"Content-Type"];
 
674
 
 
675
            newRequest = [mutableRequest autorelease];
 
676
        }
 
677
    }
 
678
 
 
679
    ResourceRequest request = newRequest;
 
680
 
 
681
    // Should not set Referer after a redirect from a secure resource to non-secure one.
 
682
    if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https"))
 
683
        request.clearHTTPReferrer();
 
684
 
 
685
    m_handle->willSendRequest(request, redirectResponse);
 
686
 
 
687
    return request.nsURLRequest();
 
688
}
 
689
 
 
690
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
 
691
{
 
692
    UNUSED_PARAM(connection);
 
693
 
 
694
    LOG(Network, "Handle %p delegate connectionShouldUseCredentialStorage:%p", m_handle, connection);
 
695
 
 
696
    if (!m_handle)
 
697
        return NO;
 
698
 
 
699
    return m_handle->shouldUseCredentialStorage();
 
700
}
 
701
 
 
702
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
 
703
{
 
704
    UNUSED_PARAM(connection);
 
705
 
 
706
    LOG(Network, "Handle %p delegate connection:%p didReceiveAuthenticationChallenge:%p", m_handle, connection, challenge);
 
707
 
 
708
    if (!m_handle) {
 
709
        [[challenge sender] cancelAuthenticationChallenge:challenge];
 
710
        return;
 
711
    }
 
712
    m_handle->didReceiveAuthenticationChallenge(core(challenge));
 
713
}
 
714
 
 
715
- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
 
716
{
 
717
    UNUSED_PARAM(connection);
 
718
 
 
719
    LOG(Network, "Handle %p delegate connection:%p didCancelAuthenticationChallenge:%p", m_handle, connection, challenge);
 
720
 
 
721
    if (!m_handle)
 
722
        return;
 
723
    m_handle->didCancelAuthenticationChallenge(core(challenge));
 
724
}
 
725
 
 
726
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
 
727
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
 
728
{
 
729
#if LOG_DISABLED
 
730
    UNUSED_PARAM(connection);
 
731
#endif
 
732
 
 
733
    LOG(Network, "Handle %p delegate connection:%p canAuthenticateAgainstProtectionSpace:%p", m_handle, connection, protectionSpace);
 
734
 
 
735
    if (!m_handle)
 
736
        return NO;
 
737
 
 
738
    return m_handle->canAuthenticateAgainstProtectionSpace(core(protectionSpace));
 
739
}
 
740
#endif
 
741
 
 
742
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)r
 
743
{
 
744
    UNUSED_PARAM(connection);
 
745
 
 
746
    LOG(Network, "Handle %p delegate connection:%p didReceiveResponse:%p (HTTP status %d, reported MIMEType '%s')", m_handle, connection, r, [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0, [[r MIMEType] UTF8String]);
 
747
 
 
748
    if (!m_handle || !m_handle->client())
 
749
        return;
 
750
 
 
751
    // Avoid MIME type sniffing if the response comes back as 304 Not Modified.
 
752
    int statusCode = [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0;
 
753
    if (statusCode != 304)
 
754
        adjustMIMETypeIfNecessary([r _CFURLResponse]);
 
755
 
 
756
    if ([m_handle->firstRequest().nsURLRequest() _propertyForKey:@"ForceHTMLMIMEType"])
 
757
        [r _setMIMEType:@"text/html"];
 
758
 
 
759
    m_handle->client()->didReceiveResponse(m_handle, r);
 
760
}
 
761
 
 
762
#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
 
763
- (void)connection:(NSURLConnection *)connection didReceiveDataArray:(NSArray *)dataArray
 
764
{
 
765
    UNUSED_PARAM(connection);
 
766
    LOG(Network, "Handle %p delegate connection:%p didReceiveDataArray:%p arraySize:%d", m_handle, connection, dataArray, [dataArray count]);
 
767
 
 
768
    if (!dataArray)
 
769
        return;
 
770
 
 
771
    if (!m_handle || !m_handle->client())
 
772
        return;
 
773
 
 
774
    m_handle->handleDataArray(reinterpret_cast<CFArrayRef>(dataArray));
 
775
    // The call to didReceiveData above can cancel a load, and if so, the delegate (self) could have been deallocated by this point.
 
776
}
 
777
#endif
 
778
 
 
779
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
 
780
{
 
781
    UNUSED_PARAM(connection);
 
782
    UNUSED_PARAM(lengthReceived);
 
783
 
 
784
    LOG(Network, "Handle %p delegate connection:%p didReceiveData:%p lengthReceived:%lld", m_handle, connection, data, lengthReceived);
 
785
 
 
786
    if (!m_handle || !m_handle->client())
 
787
        return;
 
788
    // FIXME: If we get more than 2B bytes in a single chunk, this code won't do the right thing.
 
789
    // However, with today's computers and networking speeds, this won't happen in practice.
 
790
    // Could be an issue with a giant local file.
 
791
 
 
792
    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793
 
793
    // -1 means we do not provide any data about transfer size to inspector so it would use
 
794
    // Content-Length headers or content size to show transfer size.
 
795
    m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], -1);
 
796
}
 
797
 
 
798
- (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data
 
799
{
 
800
    UNUSED_PARAM(connection);
 
801
 
 
802
    LOG(Network, "Handle %p delegate connection:%p willStopBufferingData:%p", m_handle, connection, data);
 
803
 
 
804
    if (!m_handle || !m_handle->client())
 
805
        return;
 
806
    // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
 
807
    // However, with today's computers and networking speeds, this won't happen in practice.
 
808
    // Could be an issue with a giant local file.
 
809
    m_handle->client()->willStopBufferingData(m_handle, (const char*)[data bytes], static_cast<int>([data length]));
 
810
}
 
811
 
 
812
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
 
813
{
 
814
    UNUSED_PARAM(connection);
 
815
    UNUSED_PARAM(bytesWritten);
 
816
 
 
817
    LOG(Network, "Handle %p delegate connection:%p didSendBodyData:%d totalBytesWritten:%d totalBytesExpectedToWrite:%d", m_handle, connection, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
 
818
 
 
819
    if (!m_handle || !m_handle->client())
 
820
        return;
 
821
    m_handle->client()->didSendData(m_handle, totalBytesWritten, totalBytesExpectedToWrite);
 
822
}
 
823
 
 
824
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
 
825
{
 
826
    UNUSED_PARAM(connection);
 
827
 
 
828
    LOG(Network, "Handle %p delegate connectionDidFinishLoading:%p", m_handle, connection);
 
829
 
 
830
    if (!m_handle || !m_handle->client())
 
831
        return;
 
832
 
 
833
    m_handle->client()->didFinishLoading(m_handle, 0);
 
834
}
 
835
 
 
836
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
 
837
{
 
838
    UNUSED_PARAM(connection);
 
839
 
 
840
    LOG(Network, "Handle %p delegate connection:%p didFailWithError:%@", m_handle, connection, error);
 
841
 
 
842
    if (!m_handle || !m_handle->client())
 
843
        return;
 
844
 
 
845
    m_handle->client()->didFail(m_handle, error);
 
846
}
 
847
 
 
848
 
 
849
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
 
850
{
 
851
    LOG(Network, "Handle %p delegate connection:%p willCacheResponse:%p", m_handle, connection, cachedResponse);
 
852
 
 
853
    UNUSED_PARAM(connection);
 
854
 
 
855
    if (!m_handle || !m_handle->client())
 
856
        return nil;
 
857
 
 
858
    // Workaround for <rdar://problem/6300990> Caching does not respect Vary HTTP header.
 
859
    // FIXME: WebCore cache has issues with Vary, too (bug 58797, bug 71509).
 
860
    if ([[cachedResponse response] isKindOfClass:[NSHTTPURLResponse class]]
 
861
        && [[(NSHTTPURLResponse *)[cachedResponse response] allHeaderFields] objectForKey:@"Vary"])
 
862
        return nil;
 
863
 
 
864
    NSCachedURLResponse *newResponse = m_handle->client()->willCacheResponse(m_handle, cachedResponse);
 
865
    if (newResponse != cachedResponse)
 
866
        return newResponse;
 
867
    
 
868
    CacheStoragePolicy policy = static_cast<CacheStoragePolicy>([newResponse storagePolicy]);
 
869
        
 
870
    m_handle->client()->willCacheResponse(m_handle, policy);
 
871
 
 
872
    if (static_cast<NSURLCacheStoragePolicy>(policy) != [newResponse storagePolicy])
 
873
        newResponse = [[[NSCachedURLResponse alloc] initWithResponse:[newResponse response]
 
874
                                                                data:[newResponse data]
 
875
                                                            userInfo:[newResponse userInfo]
 
876
                                                       storagePolicy:static_cast<NSURLCacheStoragePolicy>(policy)] autorelease];
 
877
 
 
878
    return newResponse;
 
879
}
 
880
 
 
881
@end
 
882
 
 
883
 
 
884
WebCoreSynchronousLoaderClient::~WebCoreSynchronousLoaderClient()
 
885
{
 
886
    [m_response release];
 
887
    [m_data release];
 
888
    [m_error release];
 
889
}
 
890
 
 
891
void WebCoreSynchronousLoaderClient::willSendRequest(ResourceHandle* handle, ResourceRequest& request, const ResourceResponse& /*redirectResponse*/)
 
892
{
 
893
    // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
 
894
    if (!protocolHostAndPortAreEqual(handle->firstRequest().url(), request.url())) {
 
895
        ASSERT(!m_error);
 
896
        m_error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil];
 
897
        m_isDone = true;
 
898
        request = 0;
 
899
        return;
 
900
    }
 
901
}
 
902
 
 
903
bool WebCoreSynchronousLoaderClient::shouldUseCredentialStorage(ResourceHandle*)
 
904
{
 
905
    // FIXME: We should ask FrameLoaderClient whether using credential storage is globally forbidden.
 
906
    return m_allowStoredCredentials;
 
907
}
 
908
 
 
909
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
 
910
bool WebCoreSynchronousLoaderClient::canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&)
 
911
{
 
912
    // FIXME: We should ask FrameLoaderClient. <http://webkit.org/b/65196>
 
913
    return true;
 
914
}
 
915
#endif
 
916
 
 
917
void WebCoreSynchronousLoaderClient::didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge)
 
918
{
 
919
    // FIXME: The user should be asked for credentials, as in async case.
 
920
    [challenge.sender() continueWithoutCredentialForAuthenticationChallenge:challenge.nsURLAuthenticationChallenge()];
 
921
}
 
922
 
 
923
void WebCoreSynchronousLoaderClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
 
924
{
 
925
    [m_response release];
 
926
    m_response = [response.nsURLResponse() copy];
 
927
}
 
928
 
 
929
void WebCoreSynchronousLoaderClient::didReceiveData(ResourceHandle*, const char* data, int length, int /*encodedDataLength*/)
 
930
{
 
931
    if (!m_data)
 
932
        m_data = [[NSMutableData alloc] init];
 
933
    [m_data appendBytes:data length:length];
 
934
}
 
935
 
 
936
void WebCoreSynchronousLoaderClient::didFinishLoading(ResourceHandle*, double)
 
937
{
 
938
    m_isDone = true;
 
939
}
 
940
 
 
941
void WebCoreSynchronousLoaderClient::didFail(ResourceHandle*, const ResourceError& error)
 
942
{
 
943
    ASSERT(!m_error);
 
944
 
 
945
    m_error = [error copy];
 
946
    m_isDone = true;
 
947
}
 
948
 
 
949
 
 
950
#endif // !USE(CFNETWORK)