📄 resourcehandlemac.mm
字号:
/* * Copyright (C) 2004, 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#import "config.h"#import "ResourceHandleInternal.h"#import "AuthenticationChallenge.h"#import "AuthenticationMac.h"#import "BlockExceptions.h"#import "DocLoader.h"#import "FormDataStreamMac.h"#import "Frame.h"#import "FrameLoader.h"#import "Page.h"#import "ResourceError.h"#import "ResourceResponse.h"#import "SchedulePair.h"#import "SharedBuffer.h"#import "SubresourceLoader.h"#import "WebCoreSystemInterface.h"#import <wtf/UnusedParam.h>#ifdef BUILDING_ON_TIGERtypedef int NSInteger;#endifusing namespace WebCore;@interface WebCoreResourceHandleAsDelegate : NSObject <NSURLAuthenticationChallengeSender>{ ResourceHandle* m_handle;#ifndef BUILDING_ON_TIGER NSURL *m_url;#endif}- (id)initWithHandle:(ResourceHandle*)handle;- (void)detachHandle;@end@interface NSURLConnection (NSURLConnectionTigerPrivate)- (NSData *)_bufferedData;@end#ifndef BUILDING_ON_TIGER@interface WebCoreSynchronousLoader : NSObject { NSURL *m_url; NSURLResponse *m_response; NSMutableData *m_data; NSError *m_error; BOOL m_isDone;}+ (NSData *)loadRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error;@endstatic NSString *WebCoreSynchronousLoaderRunLoopMode = @"WebCoreSynchronousLoaderRunLoopMode";#endifnamespace WebCore {#ifdef BUILDING_ON_TIGERstatic unsigned inNSURLConnectionCallback;#endif#ifndef NDEBUGstatic bool isInitializingConnection;#endif class CallbackGuard {public: CallbackGuard() {#ifdef BUILDING_ON_TIGER ++inNSURLConnectionCallback;#endif } ~CallbackGuard() {#ifdef BUILDING_ON_TIGER ASSERT(inNSURLConnectionCallback > 0); --inNSURLConnectionCallback;#endif }};ResourceHandleInternal::~ResourceHandleInternal(){}ResourceHandle::~ResourceHandle(){ releaseDelegate();}static const double MaxFoundationVersionWithoutdidSendBodyDataDelegate = 677.21;bool ResourceHandle::didSendBodyDataDelegateExists(){ return NSFoundationVersionNumber > MaxFoundationVersionWithoutdidSendBodyDataDelegate;}bool ResourceHandle::start(Frame* frame){ if (!frame) return false; BEGIN_BLOCK_OBJC_EXCEPTIONS; // If we are no longer attached to a Page, this must be an attempted load from an // onUnload handler, so let's just block it. Page* page = frame->page(); if (!page) return false;#ifndef NDEBUG isInitializingConnection = YES;#endif id delegate; if (d->m_mightDownloadFromHandle) { ASSERT(!d->m_proxy); d->m_proxy = wkCreateNSURLConnectionDelegateProxy(); [d->m_proxy.get() setDelegate:ResourceHandle::delegate()]; [d->m_proxy.get() release]; delegate = d->m_proxy.get(); } else delegate = ResourceHandle::delegate(); if (!ResourceHandle::didSendBodyDataDelegateExists()) associateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream], this); NSURLConnection *connection; if (d->m_shouldContentSniff) #ifdef BUILDING_ON_TIGER connection = [[NSURLConnection alloc] initWithRequest:d->m_request.nsURLRequest() delegate:delegate];#else connection = [[NSURLConnection alloc] initWithRequest:d->m_request.nsURLRequest() delegate:delegate startImmediately:NO];#endif else { NSMutableURLRequest *request = [d->m_request.nsURLRequest() mutableCopy]; wkSetNSURLRequestShouldContentSniff(request, NO);#ifdef BUILDING_ON_TIGER connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate];#else connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO];#endif [request release]; }#ifndef BUILDING_ON_TIGER bool scheduled = false; if (SchedulePairHashSet* scheduledPairs = page->scheduledRunLoopPairs()) { SchedulePairHashSet::iterator end = scheduledPairs->end(); for (SchedulePairHashSet::iterator it = scheduledPairs->begin(); it != end; ++it) { if (NSRunLoop *runLoop = (*it)->nsRunLoop()) { [connection scheduleInRunLoop:runLoop forMode:(NSString *)(*it)->mode()]; scheduled = true; } } } // Start the connection if we did schedule with at least one runloop. // We can't start the connection until we have one runloop scheduled. if (scheduled) [connection start]; else d->m_startWhenScheduled = true;#endif#ifndef NDEBUG isInitializingConnection = NO;#endif d->m_connection = connection; if (d->m_connection) { [connection release]; if (d->m_defersLoading) wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), YES); return true; } END_BLOCK_OBJC_EXCEPTIONS; return false;}void ResourceHandle::cancel(){ if (!ResourceHandle::didSendBodyDataDelegateExists()) disassociateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream]); [d->m_connection.get() cancel];}void ResourceHandle::setDefersLoading(bool defers){ d->m_defersLoading = defers; if (d->m_connection) wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), defers);}void ResourceHandle::schedule(SchedulePair* pair){#ifndef BUILDING_ON_TIGER NSRunLoop *runLoop = pair->nsRunLoop(); if (!runLoop) return; [d->m_connection.get() scheduleInRunLoop:runLoop forMode:(NSString *)pair->mode()]; if (d->m_startWhenScheduled) { [d->m_connection.get() start]; d->m_startWhenScheduled = false; }#else UNUSED_PARAM(pair);#endif}void ResourceHandle::unschedule(SchedulePair* pair){#ifndef BUILDING_ON_TIGER if (NSRunLoop *runLoop = pair->nsRunLoop()) [d->m_connection.get() unscheduleFromRunLoop:runLoop forMode:(NSString *)pair->mode()];#else UNUSED_PARAM(pair);#endif}WebCoreResourceHandleAsDelegate *ResourceHandle::delegate(){ if (!d->m_delegate) { WebCoreResourceHandleAsDelegate *delegate = [[WebCoreResourceHandleAsDelegate alloc] initWithHandle:this]; d->m_delegate = delegate; [delegate release]; } return d->m_delegate.get();}void ResourceHandle::releaseDelegate(){ if (!d->m_delegate) return; if (d->m_proxy) [d->m_proxy.get() setDelegate:nil]; [d->m_delegate.get() detachHandle]; d->m_delegate = nil;}bool ResourceHandle::supportsBufferedData(){ static bool supportsBufferedData = [NSURLConnection instancesRespondToSelector:@selector(_bufferedData)]; return supportsBufferedData;}PassRefPtr<SharedBuffer> ResourceHandle::bufferedData(){ if (ResourceHandle::supportsBufferedData()) return SharedBuffer::wrapNSData([d->m_connection.get() _bufferedData]); return 0;}id ResourceHandle::releaseProxy(){ id proxy = [[d->m_proxy.get() retain] autorelease]; d->m_proxy = nil; [proxy setDelegate:nil]; return proxy;}NSURLConnection *ResourceHandle::connection() const{ return d->m_connection.get();}bool ResourceHandle::loadsBlocked(){#ifndef BUILDING_ON_TIGER return false;#else // On Tiger, if we're in an NSURLConnection callback, that blocks all other NSURLConnection callbacks. // On Leopard and newer, it blocks only callbacks on that same NSURLConnection object, which is not // a problem in practice. return inNSURLConnectionCallback != 0;#endif}bool ResourceHandle::willLoadFromCache(ResourceRequest& request){ request.setCachePolicy(ReturnCacheDataDontLoad); NSURLResponse *nsURLResponse = nil; BEGIN_BLOCK_OBJC_EXCEPTIONS; [NSURLConnection sendSynchronousRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:nil]; END_BLOCK_OBJC_EXCEPTIONS; return nsURLResponse;}void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame*){ NSError *nsError = nil; NSURLResponse *nsURLResponse = nil; NSData *result = nil; ASSERT(!request.isEmpty()); BEGIN_BLOCK_OBJC_EXCEPTIONS; #ifndef BUILDING_ON_TIGER result = [WebCoreSynchronousLoader loadRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:&nsError];#else result = [NSURLConnection sendSynchronousRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:&nsError];#endif END_BLOCK_OBJC_EXCEPTIONS; if (nsError == nil) response = nsURLResponse; else { response = ResourceResponse(request.url(), String(), 0, String(), String()); if ([nsError domain] == NSURLErrorDomain) switch ([nsError code]) { case NSURLErrorUserCancelledAuthentication: // FIXME: we should really return the actual HTTP response, but sendSynchronousRequest doesn't provide us with one. response.setHTTPStatusCode(401); break; default: response.setHTTPStatusCode([nsError code]); } else response.setHTTPStatusCode(404); } data.resize([result length]); memcpy(data.data(), [result bytes], [result length]); error = nsError;}bool ResourceHandle::shouldUseCredentialStorage(){ if (client()) return client()->shouldUseCredentialStorage(this); return false;}void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge){ ASSERT(!d->m_currentMacChallenge); ASSERT(d->m_currentWebChallenge.isNull()); // Since NSURLConnection networking relies on keeping a reference to the original NSURLAuthenticationChallenge, // we make sure that is actually present ASSERT(challenge.nsURLAuthenticationChallenge()); d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge(); NSURLAuthenticationChallenge *webChallenge = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:d->m_currentMacChallenge sender:(id<NSURLAuthenticationChallengeSender>)delegate()]; d->m_currentWebChallenge = core(webChallenge); [webChallenge release]; if (client()) client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge);}void ResourceHandle::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge){ ASSERT(d->m_currentMacChallenge); ASSERT(!d->m_currentWebChallenge.isNull()); ASSERT(d->m_currentWebChallenge == challenge); if (client()) client()->didCancelAuthenticationChallenge(this, challenge);}void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential){ ASSERT(!challenge.isNull()); if (challenge != d->m_currentWebChallenge) return; [[d->m_currentMacChallenge sender] useCredential:mac(credential) forAuthenticationChallenge:d->m_currentMacChallenge]; clearAuthentication();}void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& challenge){ ASSERT(!challenge.isNull()); if (challenge != d->m_currentWebChallenge) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -