void PluginStream::didReceiveData(NetscapePlugInStreamLoader* loader, const char* data, int length)
{
    ASSERT(loader == m_loader);
    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);

#if PLATFORM(ANDROID)
//TODO: This needs to be upstreamed to WebKit.
        if (!m_delayDeliveryTimer.isActive())
#endif
        deliverData();
    }

    if (m_streamState != StreamStopped && isHandleValid(m_tempFileHandle)) {
        int bytesWritten = writeToFile(m_tempFileHandle, data, length);
        if (bytesWritten != length)
            cancelAndDestroyStream(NPRES_NETWORK_ERR);
    }
}
Beispiel #2
0
void PluginStream::didReceiveData(NetscapePlugInStreamLoader* loader, const char* data, int length)
{
    ASSERT_UNUSED(loader, loader == m_loader);
    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 = std::make_unique<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);
    }
}
Beispiel #3
0
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_t totalBytes = m_deliveryData->size();
    int32_t totalBytesDelivered = 0;

    if (m_loader)
        m_loader->setDefersLoading(true);
    while (totalBytesDelivered < totalBytes) {
        int32_t deliveryBytes = m_pluginFuncs->writeready(m_instance, &m_stream);

        if (deliveryBytes <= 0) {
            m_delayDeliveryTimer.startOneShot(0);
            break;
        } else {
            deliveryBytes = min(deliveryBytes, totalBytes - totalBytesDelivered);
            int32_t 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();
                if (m_loader)
                    m_loader->setDefersLoading(false);
                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::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 (protocolIsJavaScript(responseURL))
        m_stream.url = fastStrDup(decodeURLEscapeSequences(responseURL.string()).utf8().data());
    else
        m_stream.url = fastStrDup(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 = makeString("HTTP ", String::number(m_resourceResponse.httpStatusCode()), " OK\n");
        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);
}