⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pluginstream.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
字号:
/* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 Collabora, Ltd. 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.  */#include "config.h"#include "PluginStream.h"#include "CString.h"#include "DocumentLoader.h"#include "Frame.h"#include "FrameLoader.h"#include "PluginDebug.h"#include "SharedBuffer.h"#include "SubresourceLoader.h"// We use -2 here because some plugins like to return -1 to indicate error// and this way we won't clash with them.static const int WebReasonNone = -2;using std::max;using std::min;namespace WebCore {typedef HashMap<NPStream*, NPP> StreamMap;static StreamMap& streams(){    static StreamMap staticStreams;    return staticStreams;}PluginStream::PluginStream(PluginStreamClient* client, Frame* frame, const ResourceRequest& resourceRequest, bool sendNotification, void* notifyData, const NPPluginFuncs* pluginFuncs, NPP instance, const PluginQuirkSet& quirks)    : m_resourceRequest(resourceRequest)    , m_client(client)    , m_frame(frame)    , m_notifyData(notifyData)    , m_sendNotification(sendNotification)    , m_streamState(StreamBeforeStarted)    , m_loadManually(false)    , m_delayDeliveryTimer(this, &PluginStream::delayDeliveryTimerFired)    , m_deliveryData(0)    , m_tempFileHandle(invalidPlatformFileHandle)    , m_pluginFuncs(pluginFuncs)    , m_instance(instance)    , m_quirks(quirks){    ASSERT(m_instance);    m_stream.url = 0;    m_stream.ndata = 0;    m_stream.pdata = 0;    m_stream.end = 0;    m_stream.notifyData = 0;    m_stream.lastmodified = 0;    streams().add(&m_stream, m_instance);}PluginStream::~PluginStream(){    ASSERT(m_streamState != StreamStarted);    ASSERT(!m_loader);    free((char*)m_stream.url);    streams().remove(&m_stream);}void PluginStream::start(){    ASSERT(!m_loadManually);    m_loader = NetscapePlugInStreamLoader::create(m_frame, this);    m_loader->setShouldBufferData(false);    m_loader->documentLoader()->addPlugInStreamLoader(m_loader.get());    m_loader->load(m_resourceRequest);}void PluginStream::stop(){    m_streamState = StreamStopped;    if (m_loadManually) {        ASSERT(!m_loader);        DocumentLoader* documentLoader = m_frame->loader()->activeDocumentLoader();        ASSERT(documentLoader);        if (documentLoader->isLoadingMainResource())            documentLoader->cancelMainResourceLoad(m_frame->loader()->cancelledError(m_resourceRequest));        return;    }    if (m_loader) {        m_loader->cancel();        m_loader = 0;    }}void PluginStream::startStream(){    ASSERT(m_streamState == StreamBeforeStarted);    const KURL& responseURL = m_resourceResponse.url();    // Some plugins (Flash) expect that javascript URLs are passed back decoded as this is the    // format used when requesting the URL.    if (responseURL.protocolIs("javascript"))        m_stream.url = strdup(decodeURLEscapeSequences(responseURL.string()).utf8().data());    else        m_stream.url = strdup(responseURL.string().utf8().data());        CString mimeTypeStr = m_resourceResponse.mimeType().utf8();        long long expectedContentLength = m_resourceResponse.expectedContentLength();    if (m_resourceResponse.isHTTP()) {        Vector<UChar> stringBuilder;        String separator(": ");        String statusLine = String::format("HTTP %lu OK\n", m_resourceResponse.httpStatusCode());        stringBuilder.append(statusLine.characters(), statusLine.length());        HTTPHeaderMap::const_iterator end = m_resourceResponse.httpHeaderFields().end();        for (HTTPHeaderMap::const_iterator it = m_resourceResponse.httpHeaderFields().begin(); it != end; ++it) {            stringBuilder.append(it->first.characters(), it->first.length());            stringBuilder.append(separator.characters(), separator.length());            stringBuilder.append(it->second.characters(), it->second.length());            stringBuilder.append('\n');        }        m_headers = String::adopt(stringBuilder).utf8();        // If the content is encoded (most likely compressed), then don't send its length to the plugin,        // which is only interested in the decoded length, not yet known at the moment.        // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.        String contentEncoding = m_resourceResponse.httpHeaderField("Content-Encoding");        if (!contentEncoding.isNull() && contentEncoding != "identity")            expectedContentLength = -1;    }    m_stream.headers = m_headers.data();    m_stream.pdata = 0;    m_stream.ndata = this;    m_stream.end = max(expectedContentLength, 0LL);    m_stream.lastmodified = m_resourceResponse.lastModifiedDate();    m_stream.notifyData = m_notifyData;    m_transferMode = NP_NORMAL;    m_offset = 0;    m_reason = WebReasonNone;    // Protect the stream if destroystream is called from within the newstream handler    RefPtr<PluginStream> protect(this);    // calling into a plug-in could result in re-entrance if the plug-in yields    // control to the system (rdar://5744899). prevent this by deferring further    // loading while calling into the plug-in.    if (m_loader)        m_loader->setDefersLoading(true);    NPError npErr = m_pluginFuncs->newstream(m_instance, (NPMIMEType)mimeTypeStr.data(), &m_stream, false, &m_transferMode);    if (m_loader)        m_loader->setDefersLoading(false);        // If the stream was destroyed in the call to newstream we return    if (m_reason != WebReasonNone)        return;            if (npErr != NPERR_NO_ERROR) {        cancelAndDestroyStream(npErr);        return;    }    m_streamState = StreamStarted;    if (m_transferMode == NP_NORMAL)        return;    m_path = openTemporaryFile("WKP", m_tempFileHandle);    // Something went wrong, cancel loading the stream    if (!isHandleValid(m_tempFileHandle))        cancelAndDestroyStream(NPRES_NETWORK_ERR);}NPP PluginStream::ownerForStream(NPStream* stream){    return streams().get(stream);}void PluginStream::cancelAndDestroyStream(NPReason reason){    RefPtr<PluginStream> protect(this);    destroyStream(reason);    stop();}void PluginStream::destroyStream(NPReason reason){    m_reason = reason;    if (m_reason != NPRES_DONE) {        // Stop any pending data from being streamed        if (m_deliveryData)            m_deliveryData->resize(0);    } else if (m_deliveryData && m_deliveryData->size() > 0) {        // There is more data to be streamed, don't destroy the stream now.        return;    }    destroyStream();}void PluginStream::destroyStream(){    if (m_streamState == StreamStopped)        return;    ASSERT(m_reason != WebReasonNone);    ASSERT(!m_deliveryData || m_deliveryData->size() == 0);    closeFile(m_tempFileHandle);    bool newStreamCalled = m_stream.ndata;    if (newStreamCalled) {        if (m_reason == NPRES_DONE && (m_transferMode == NP_ASFILE || m_transferMode == NP_ASFILEONLY)) {            ASSERT(!m_path.isNull());            if (m_loader)                m_loader->setDefersLoading(true);            m_pluginFuncs->asfile(m_instance, &m_stream, m_path.data());            if (m_loader)                m_loader->setDefersLoading(false);        }        if (m_streamState != StreamBeforeStarted) {            if (m_loader)                m_loader->setDefersLoading(true);            NPError npErr = m_pluginFuncs->destroystream(m_instance, &m_stream, m_reason);            if (m_loader)                m_loader->setDefersLoading(false);            LOG_NPERROR(npErr);        }        m_stream.ndata = 0;    }    if (m_sendNotification) {        // Flash 9 can dereference null if we call NPP_URLNotify without first calling NPP_NewStream        // for requests made with NPN_PostURLNotify; see <rdar://5588807>        if (m_loader)            m_loader->setDefersLoading(true);        if (!newStreamCalled && m_quirks.contains(PluginQuirkFlashURLNotifyBug) &&            equalIgnoringCase(m_resourceRequest.httpMethod(), "POST")) {            // Protect the stream if NPN_DestroyStream is called from NPP_NewStream            RefPtr<PluginStream> protect(this);            m_transferMode = NP_NORMAL;            m_stream.url = "";            m_stream.notifyData = m_notifyData;            static char emptyMimeType[] = "";            m_pluginFuncs->newstream(m_instance, emptyMimeType, &m_stream, false, &m_transferMode);            m_pluginFuncs->destroystream(m_instance, &m_stream, m_reason);            // in successful requests, the URL is dynamically allocated and freed in our            // destructor, so reset it to 0            m_stream.url = 0;        }        m_pluginFuncs->urlnotify(m_instance, m_resourceRequest.url().string().utf8().data(), m_reason, m_notifyData);        if (m_loader)            m_loader->setDefersLoading(false);    }    m_streamState = StreamStopped;    // streamDidFinishLoading can cause us to be deleted.    RefPtr<PluginStream> protect(this);    if (!m_loadManually)        m_client->streamDidFinishLoading(this);    if (!m_path.isNull()) {        String tempFilePath = String::fromUTF8(m_path.data());        deleteFile(tempFilePath);    }}void PluginStream::delayDeliveryTimerFired(Timer<PluginStream>* timer){    ASSERT(timer == &m_delayDeliveryTimer);    deliverData();}void PluginStream::deliverData(){    ASSERT(m_deliveryData);        if (m_streamState == StreamStopped)        // FIXME: We should cancel our job in the SubresourceLoader on error so we don't reach this case        return;    ASSERT(m_streamState != StreamBeforeStarted);    if (!m_stream.ndata || m_deliveryData->size() == 0)        return;    int32 totalBytes = m_deliveryData->size();    int32 totalBytesDelivered = 0;    if (m_loader)        m_loader->setDefersLoading(true);    while (totalBytesDelivered < totalBytes) {        int32 deliveryBytes = m_pluginFuncs->writeready(m_instance, &m_stream);        if (deliveryBytes <= 0) {            m_delayDeliveryTimer.startOneShot(0);            break;        } else {            deliveryBytes = min(deliveryBytes, totalBytes - totalBytesDelivered);            int32 dataLength = deliveryBytes;            char* data = m_deliveryData->data() + totalBytesDelivered;            // Write the data            deliveryBytes = m_pluginFuncs->write(m_instance, &m_stream, m_offset, dataLength, (void*)data);            if (deliveryBytes < 0) {                LOG_PLUGIN_NET_ERROR();                cancelAndDestroyStream(NPRES_NETWORK_ERR);                return;            }            deliveryBytes = min(deliveryBytes, dataLength);            m_offset += deliveryBytes;            totalBytesDelivered += deliveryBytes;        }    }    if (m_loader)        m_loader->setDefersLoading(false);    if (totalBytesDelivered > 0) {        if (totalBytesDelivered < totalBytes) {            int remainingBytes = totalBytes - totalBytesDelivered;            memmove(m_deliveryData->data(), m_deliveryData->data() + totalBytesDelivered, remainingBytes);            m_deliveryData->resize(remainingBytes);        } else {            m_deliveryData->resize(0);            if (m_reason != WebReasonNone)                destroyStream();        }    } }void PluginStream::sendJavaScriptStream(const KURL& requestURL, const CString& resultString){    didReceiveResponse(0, ResourceResponse(requestURL, "text/plain", resultString.length(), "", ""));    if (m_streamState == StreamStopped)        return;    if (!resultString.isNull()) {        didReceiveData(0, resultString.data(), resultString.length());        if (m_streamState == StreamStopped)            return;    }    m_loader = 0;    destroyStream(resultString.isNull() ? NPRES_NETWORK_ERR : NPRES_DONE);}void PluginStream::didReceiveResponse(NetscapePlugInStreamLoader* loader, const ResourceResponse& response){    ASSERT(loader == m_loader);    ASSERT(m_streamState == StreamBeforeStarted);    m_resourceResponse = response;    startStream();}void PluginStream::didReceiveData(NetscapePlugInStreamLoader* loader, const char* data, int length){    ASSERT(loader == m_loader);    ASSERT(length > 0);    ASSERT(m_streamState == StreamStarted);    // If the plug-in cancels the stream in deliverData it could be deleted,     // so protect it here.    RefPtr<PluginStream> protect(this);    if (m_transferMode != NP_ASFILEONLY) {        if (!m_deliveryData)            m_deliveryData.set(new Vector<char>);        int oldSize = m_deliveryData->size();        m_deliveryData->resize(oldSize + length);        memcpy(m_deliveryData->data() + oldSize, data, length);        deliverData();    }    if (m_streamState != StreamStopped && isHandleValid(m_tempFileHandle)) {        int bytesWritten = writeToFile(m_tempFileHandle, data, length);        if (bytesWritten != length)            cancelAndDestroyStream(NPRES_NETWORK_ERR);    }}void PluginStream::didFail(NetscapePlugInStreamLoader* loader, const ResourceError&){    ASSERT(loader == m_loader);    LOG_PLUGIN_NET_ERROR();    // destroyStream can result in our being deleted    RefPtr<PluginStream> protect(this);    destroyStream(NPRES_NETWORK_ERR);    m_loader = 0;}void PluginStream::didFinishLoading(NetscapePlugInStreamLoader* loader){    ASSERT(loader == m_loader);    ASSERT(m_streamState == StreamStarted);    // destroyStream can result in our being deleted    RefPtr<PluginStream> protect(this);    destroyStream(NPRES_DONE);    m_loader = 0;}bool PluginStream::wantsAllStreams() const{    if (!m_pluginFuncs->getvalue)        return false;    void* result = 0;    if (m_pluginFuncs->getvalue(m_instance, NPPVpluginWantsAllNetworkStreams, &result) != NPERR_NO_ERROR)        return false;    return result != 0;}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -