📄 webbasenetscapepluginstream.mm
字号:
/* * Copyright (C) 2005, 2006, 2007 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. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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. */#if ENABLE(NETSCAPE_PLUGIN_API)#import "WebBaseNetscapePluginStream.h"#import "WebNetscapePluginView.h"#import "WebFrameInternal.h"#import "WebKitErrorsPrivate.h"#import "WebKitLogging.h"#import "WebNSObjectExtras.h"#import "WebNSURLExtras.h"#import "WebNSURLRequestExtras.h"#import "WebNetscapePluginPackage.h"#import <Foundation/NSURLResponse.h>#import <runtime/JSLock.h>#import <WebCore/DocumentLoader.h>#import <WebCore/Frame.h>#import <WebCore/FrameLoader.h>#import <WebCore/WebCoreObjCExtras.h>#import <WebKitSystemInterface.h>#import <wtf/HashMap.h>#import <wtf/StdLibExtras.h>using namespace WebCore;#define WEB_REASON_NONE -1static NSString *CarbonPathFromPOSIXPath(NSString *posixPath);typedef HashMap<NPStream*, NPP> StreamMap;static StreamMap& streams(){ DEFINE_STATIC_LOCAL(StreamMap, staticStreams, ()); return staticStreams;}NPP WebNetscapePluginStream::ownerForStream(NPStream *stream){ return streams().get(stream);}NPReason WebNetscapePluginStream::reasonForError(NSError *error){ if (!error) return NPRES_DONE; if ([[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled) return NPRES_USER_BREAK; return NPRES_NETWORK_ERR;}NSError *WebNetscapePluginStream::pluginCancelledConnectionError() const{ return [[[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInCancelledConnection contentURL:m_responseURL ? m_responseURL.get() : m_requestURL.get() pluginPageURL:nil pluginName:[[m_pluginView.get() pluginPackage] name] MIMEType:m_mimeType.get()] autorelease];}NSError *WebNetscapePluginStream::errorForReason(NPReason reason) const{ if (reason == NPRES_DONE) return nil; if (reason == NPRES_USER_BREAK) return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:m_responseURL ? m_responseURL.get() : m_requestURL.get()]; return pluginCancelledConnectionError();}WebNetscapePluginStream::WebNetscapePluginStream(FrameLoader* frameLoader) : m_plugin(0) , m_transferMode(0) , m_offset(0) , m_fileDescriptor(-1) , m_sendNotification(false) , m_notifyData(0) , m_headers(0) , m_reason(NPRES_BASE) , m_isTerminated(false) , m_newStreamSuccessful(false) , m_frameLoader(frameLoader) , m_pluginFuncs(0) , m_deliverDataTimer(this, &WebNetscapePluginStream::deliverDataTimerFired){ memset(&m_stream, 0, sizeof(NPStream));}WebNetscapePluginStream::WebNetscapePluginStream(NSURLRequest *request, NPP plugin, bool sendNotification, void* notifyData) : m_requestURL([request URL]) , m_plugin(0) , m_transferMode(0) , m_offset(0) , m_fileDescriptor(-1) , m_sendNotification(sendNotification) , m_notifyData(notifyData) , m_headers(0) , m_reason(NPRES_BASE) , m_isTerminated(false) , m_newStreamSuccessful(false) , m_frameLoader(0) , m_request(AdoptNS, [request mutableCopy]) , m_pluginFuncs(0) , m_deliverDataTimer(this, &WebNetscapePluginStream::deliverDataTimerFired){ memset(&m_stream, 0, sizeof(NPStream)); WebNetscapePluginView *view = (WebNetscapePluginView *)plugin->ndata; // This check has already been done by the plug-in view. ASSERT(FrameLoader::canLoad([request URL], String(), core([view webFrame])->document())); ASSERT([request URL]); ASSERT(plugin); setPlugin(plugin); streams().add(&m_stream, plugin); if (core([view webFrame])->loader()->shouldHideReferrer([request URL], core([view webFrame])->loader()->outgoingReferrer())) [m_request.get() _web_setHTTPReferrer:nil];}WebNetscapePluginStream::~WebNetscapePluginStream(){ ASSERT(!m_plugin); ASSERT(m_isTerminated); ASSERT(!m_stream.ndata); // The stream file should have been deleted, and the path freed, in -_destroyStream ASSERT(!m_path); ASSERT(m_fileDescriptor == -1); free((void *)m_stream.url); free(m_headers); streams().remove(&m_stream);}void WebNetscapePluginStream::setPlugin(NPP plugin){ if (plugin) { m_plugin = plugin; m_pluginView = static_cast<WebNetscapePluginView *>(m_plugin->ndata); WebNetscapePluginPackage *pluginPackage = [m_pluginView.get() pluginPackage]; m_pluginFuncs = [pluginPackage pluginFuncs]; } else { WebNetscapePluginView *view = m_pluginView.get(); m_plugin = 0; m_pluginFuncs = 0; [view disconnectStream:this]; m_pluginView = 0; } }void WebNetscapePluginStream::startStream(NSURL *url, long long expectedContentLength, NSDate *lastModifiedDate, NSString *mimeType, NSData *headers){ ASSERT(!m_isTerminated); m_responseURL = url; m_mimeType = mimeType; free((void *)m_stream.url); m_stream.url = strdup([m_responseURL.get() _web_URLCString]); m_stream.ndata = this; m_stream.end = expectedContentLength > 0 ? (uint32)expectedContentLength : 0; m_stream.lastmodified = (uint32)[lastModifiedDate timeIntervalSince1970]; m_stream.notifyData = m_notifyData; if (headers) { unsigned len = [headers length]; m_headers = (char*) malloc(len + 1); [headers getBytes:m_headers]; m_headers[len] = 0; m_stream.headers = m_headers; } m_transferMode = NP_NORMAL; m_offset = 0; m_reason = WEB_REASON_NONE; // FIXME: If WebNetscapePluginStream called our initializer we wouldn't have to do this here. m_fileDescriptor = -1; // FIXME: Need a way to check if stream is seekable [m_pluginView.get() willCallPlugInFunction]; NPError npErr = m_pluginFuncs->newstream(m_plugin, (char *)[m_mimeType.get() UTF8String], &m_stream, NO, &m_transferMode); [m_pluginView.get() didCallPlugInFunction]; LOG(Plugins, "NPP_NewStream URL=%@ MIME=%@ error=%d", m_responseURL.get(), m_mimeType.get(), npErr); if (npErr != NPERR_NO_ERROR) { LOG_ERROR("NPP_NewStream failed with error: %d responseURL: %@", npErr, m_responseURL.get()); // Calling cancelLoadWithError: cancels the load, but doesn't call NPP_DestroyStream. cancelLoadWithError(pluginCancelledConnectionError()); return; } m_newStreamSuccessful = true; switch (m_transferMode) { case NP_NORMAL: LOG(Plugins, "Stream type: NP_NORMAL"); break; case NP_ASFILEONLY: LOG(Plugins, "Stream type: NP_ASFILEONLY"); break; case NP_ASFILE: LOG(Plugins, "Stream type: NP_ASFILE"); break; case NP_SEEK: LOG_ERROR("Stream type: NP_SEEK not yet supported"); cancelLoadAndDestroyStreamWithError(pluginCancelledConnectionError()); break; default: LOG_ERROR("unknown stream type"); }}void WebNetscapePluginStream::start(){ ASSERT(m_request); ASSERT(!m_frameLoader); ASSERT(!m_loader); m_loader = NetscapePlugInStreamLoader::create(core([m_pluginView.get() webFrame]), this); m_loader->setShouldBufferData(false); m_loader->documentLoader()->addPlugInStreamLoader(m_loader.get()); m_loader->load(m_request.get());}void WebNetscapePluginStream::stop(){ ASSERT(!m_frameLoader); if (!m_loader->isDone()) cancelLoadAndDestroyStreamWithError(m_loader->cancelledError());}void WebNetscapePluginStream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response){ NSURLResponse *r = response.nsURLResponse(); NSMutableData *theHeaders = nil; long long expectedContentLength = [r expectedContentLength]; if ([r isKindOfClass:[NSHTTPURLResponse class]]) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)r; theHeaders = [NSMutableData dataWithCapacity:1024]; // FIXME: it would be nice to be able to get the raw HTTP header block. // This includes the HTTP version, the real status text, // all headers in their original order and including duplicates, // and all original bytes verbatim, rather than sent through Unicode translation. // Unfortunately NSHTTPURLResponse doesn't provide access at that low a level. [theHeaders appendBytes:"HTTP " length:5]; char statusStr[10]; long statusCode = [httpResponse statusCode]; snprintf(statusStr, sizeof(statusStr), "%ld", statusCode); [theHeaders appendBytes:statusStr length:strlen(statusStr)]; [theHeaders appendBytes:" OK\n" length:4]; // HACK: pass the headers through as UTF-8. // This is not the intended behavior; we're supposed to pass original bytes verbatim. // But we don't have the original bytes, we have NSStrings built by the URL loading system. // It hopefully shouldn't matter, since RFC2616/RFC822 require ASCII-only headers, // but surely someone out there is using non-ASCII characters, and hopefully UTF-8 is adequate here. // It seems better than NSASCIIStringEncoding, which will lose information if non-ASCII is used. NSDictionary *headerDict = [httpResponse allHeaderFields]; NSArray *keys = [[headerDict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; NSEnumerator *i = [keys objectEnumerator]; NSString *k; while ((k = [i nextObject]) != nil) { NSString *v = [headerDict objectForKey:k]; [theHeaders appendData:[k dataUsingEncoding:NSUTF8StringEncoding]]; [theHeaders appendBytes:": " length:2];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -