+2008-03-25 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin
+
+ <rdar://problem/4516169> - Support WebArchives on Windows
+ And pave the way for many future WebArchive bug fixes and enhancements
+
+ This patch accomplishes two main goals:
+ 1 - Consolidates much of the spread out WebKitMac archive code into one place in WebCore. This allows for cleaner refactoring
+ in the future as well as adding more archive formats with ease.
+ 2 - Hooks up WebArchive support on Windows. Safari-style .webarchive files are nothing more than property lists readable by
+ CoreFoundation. While there are still some outstanding issues, including an NSKeyedArchiver chunk of data for the
+ ResourceResponse for each resource, this patch manually parses through the property list on CoreFoundation platforms and
+ gets many archives loading on Windows
+
+ My goal for this first cut was zero behavior change. As such, I went for a direct port of the WebKitMac code. There will be
+ opportunities for redesign and refactoring as followups.
+
+ * WebCore.base.exp:
+
+ * loader/DocumentLoader.cpp:
+ (WebCore::DocumentLoader::setupForReplaceByMIMEType): Ported from WebKitMac, WebDataSource
+ (WebCore::DocumentLoader::addAllArchiveResources):
+ (WebCore::DocumentLoader::addArchiveResource):
+ (WebCore::DocumentLoader::archiveResourceForURL):
+ (WebCore::DocumentLoader::popArchiveForSubframe):
+ (WebCore::DocumentLoader::clearArchiveResources):
+ * loader/DocumentLoader.h:
+
+ * loader/FrameLoader.cpp: Moved WebFrameLoaderClient and WebFrame code down into their more appropriate FrameLoader home
+ (WebCore::FrameLoader::FrameLoader):
+ (WebCore::FrameLoader::setDefersLoading):
+ (WebCore::FrameLoader::deliverArchivedResourcesAfterDelay):
+ (WebCore::FrameLoader::archiveResourceDeliveryTimerFired):
+ (WebCore::FrameLoader::loadURLIntoChildFrame):
+ (WebCore::FrameLoader::loadArchive):
+ (WebCore::FrameLoader::scheduleArchiveLoad):
+ (WebCore::FrameLoader::stopAllLoaders):
+ (WebCore::FrameLoader::cancelPendingArchiveLoad):
+ (WebCore::FrameLoader::isArchiveLoadPending):
+ (WebCore::FrameLoader::finishedLoadingDocument):
+ * loader/FrameLoader.h:
+
+ * loader/ResourceLoader.cpp:
+ (WebCore::ResourceLoader::load):
+
+ * loader/archive/Archive.h: Generic "Archive of web resources" class that is only useful when subclassed.
+ Contains a MainResource, subresources, and Archives for subframes
+ (WebCore::Archive::mainResource):
+ (WebCore::Archive::subresources):
+ (WebCore::Archive::subframeArchives):
+ (WebCore::Archive::setMainResource):
+ (WebCore::Archive::addSubresource):
+ (WebCore::Archive::addSubframeArchive):
+
+ * loader/archive/ArchiveFactory.cpp: A class that will take raw archive data and the MIMEtype, and create the
+ appropriate Archive class for it. Additionally it handles registering the known MIMEtypes for all known archive formats
+ (WebCore::archiveFactoryCreate):
+ (WebCore::archiveMIMETypes):
+ (WebCore::ArchiveFactory::isArchiveMimeType):
+ (WebCore::ArchiveFactory::create):
+ (WebCore::ArchiveFactory::registerKnownArchiveMIMETypes):
+ * loader/archive/ArchiveFactory.h:
+
+ * loader/archive/ArchiveResource.cpp: Analog to "WebResource" in WebKitMac. Contains the data and other important
+ attributes of an archived resource
+ (WebCore::ArchiveResource::create):
+ (WebCore::ArchiveResource::ArchiveResource):
+ (WebCore::ArchiveResource::response):
+ * loader/archive/ArchiveResource.h:
+ (WebCore::ArchiveResource::data):
+ (WebCore::ArchiveResource::url):
+ (WebCore::ArchiveResource::mimeType):
+ (WebCore::ArchiveResource::textEncoding):
+ (WebCore::ArchiveResource::frameName):
+ (WebCore::ArchiveResource::ignoreWhenUnarchiving):
+ (WebCore::ArchiveResource::shouldIgnoreWhenUnarchiving):
+
+ * loader/archive/ArchiveResourceCollection.cpp: Analog of "WebUnarchivingState" in WebKitMac. Contains a hash of
+ all the resources for every frame in an archive, and contains the archives for each subframe needed to load a multi-frame archive
+ (WebCore::ArchiveResourceCollection::ArchiveResourceCollection):
+ (WebCore::ArchiveResourceCollection::addAllResources):
+ (WebCore::ArchiveResourceCollection::addResource):
+ (WebCore::ArchiveResourceCollection::archiveResourceForURL):
+ (WebCore::ArchiveResourceCollection::popSubframeArchive):
+ * loader/archive/ArchiveResourceCollection.h:
+
+ * loader/archive/cf/LegacyWebArchive.cpp: Subclass of Archive specifically for Webkit's Objective-C based ".webarchive" format.
+ Mostly a collection of static methods involved in parsing and serializing a WebKit-style .webarchive. Is mostly supported
+ for any CF platform.
+ (WebCore::createPropertyListRepresentationFromResource):
+ (WebCore::createPropertyListRep):
+ (WebCore::createResourceResponseFromPropertyListData):
+ (WebCore::createResource):
+ (WebCore::LegacyWebArchive::create):
+ (WebCore::LegacyWebArchive::LegacyWebArchive):
+ (WebCore::LegacyWebArchive::init):
+ (WebCore::LegacyWebArchive::extract):
+ (WebCore::LegacyWebArchive::rawDataRepresentation):
+ (WebCore::createResourceResponseFromMacArchivedData):
+ (WebCore::propertyListDataFromResourceResponse):
+ * loader/archive/cf/LegacyWebArchive.h:
+ * loader/archive/cf/LegacyWebArchiveMac.mm:
+ (WebCore::createResourceResponseFromMacArchivedData):
+ (WebCore::propertyListDataFromResourceResponse):
+
+ * platform/network/mac/ResourceRequest.h:
+ * platform/network/mac/ResourceRequestMac.mm:
+ (WebCore::ResourceRequest::applyWebArchiveHackForMail): Tweak the resource request for Mac clients when loading WebArchives
+
2008-03-25 David Hyatt <hyatt@apple.com>
Cut and paste error in the zoom code. A width() should have been a height(). Regression tests caught this.
__ZN7WebCore11FileChooser10chooseFileERKNS_6StringE
__ZN7WebCore11FileChooserD1Ev
__ZN7WebCore11FrameLoader11completeURLERKNS_6StringE
+__ZN7WebCore11FrameLoader11loadArchiveEN3WTF10PassRefPtrINS_7ArchiveEEE
__ZN7WebCore11FrameLoader11setEncodingERKNS_6StringEb
__ZN7WebCore11FrameLoader12canCachePageEv
__ZN7WebCore11FrameLoader12shouldReloadERKNS_4KURLES3_
__ZN7WebCore11FrameLoader18currentHistoryItemEv
__ZN7WebCore11FrameLoader18shouldHideReferrerERKNS_4KURLERKNS_6StringE
__ZN7WebCore11FrameLoader20continueLoadWithDataEPNS_12SharedBufferERKNS_6StringES5_RKNS_4KURLE
+__ZN7WebCore11FrameLoader21loadURLIntoChildFrameERKNS_4KURLERKNS_6StringEPNS_5FrameE
__ZN7WebCore11FrameLoader21setCurrentHistoryItemEN3WTF10PassRefPtrINS_11HistoryItemEEE
__ZN7WebCore11FrameLoader22findFrameForNavigationERKNS_12AtomicStringE
__ZN7WebCore11FrameLoader22setPreviousHistoryItemEN3WTF10PassRefPtrINS_11HistoryItemEEE
__ZN7WebCore14CachedResource5derefEPNS_20CachedResourceClientE
__ZN7WebCore14DocumentLoader13attachToFrameEv
__ZN7WebCore14DocumentLoader15detachFromFrameEv
+__ZN7WebCore14DocumentLoader18addArchiveResourceEN3WTF10PassRefPtrINS_15ArchiveResourceEEE
__ZN7WebCore14DocumentLoader19prepareForLoadStartEv
__ZN7WebCore14DocumentLoader21addPlugInStreamLoaderEPNS_14ResourceLoaderE
+__ZN7WebCore14DocumentLoader21archiveResourceForURLERKNS_4KURLE
+__ZN7WebCore14DocumentLoader22addAllArchiveResourcesEPNS_7ArchiveE
__ZN7WebCore14DocumentLoader22cancelMainResourceLoadERKNS_13ResourceErrorE
__ZN7WebCore14DocumentLoader24removePlugInStreamLoaderEPNS_14ResourceLoaderE
__ZN7WebCore14DocumentLoader32replaceRequestURLForAnchorScrollERKNS_4KURLE
__ZN7WebCore14ResourceLoader14cancelledErrorEv
__ZN7WebCore14ResourceLoader19setShouldBufferDataEb
__ZN7WebCore14SecurityOrigin6createERKNS_6StringES3_tPS0_
+__ZN7WebCore15ArchiveResource6createEN3WTF10PassRefPtrINS_12SharedBufferEEERKNS_4KURLERKNS_6StringESA_SA_RKNS_16ResourceResponseE
+__ZN7WebCore15ArchiveResource8responseEv
__ZN7WebCore15BackForwardList10removeItemEPNS_11HistoryItemE
__ZN7WebCore15BackForwardList10setEnabledEb
__ZN7WebCore15BackForwardList11currentItemEv
__ZN7WebCore15VisiblePositionC1ERKNS_8PositionENS_9EAffinityE
__ZN7WebCore16FontPlatformDataC1EP6NSFontbb
__ZN7WebCore16FontPlatformDataD1Ev
+__ZN7WebCore16LegacyWebArchive21rawDataRepresentationEv
+__ZN7WebCore16LegacyWebArchive6createEN3WTF10PassRefPtrINS_15ArchiveResourceEEERNS1_6VectorIS4_Lm0EEERNS5_INS2_IS0_EELm0EEE
+__ZN7WebCore16LegacyWebArchive6createEPNS_12SharedBufferE
+__ZN7WebCore16LegacyWebArchive6createEv
__ZN7WebCore16MIMETypeRegistry24isSupportedImageMIMETypeERKNS_6StringE
__ZN7WebCore16MIMETypeRegistry26getSupportedImageMIMETypesEv
__ZN7WebCore16MIMETypeRegistry29getSupportedNonImageMIMETypesEv
#include "config.h"
#include "DocumentLoader.h"
+#include "ArchiveResourceCollection.h"
#include "CachedPage.h"
#include "DocLoader.h"
#include "Document.h"
#include "SharedBuffer.h"
#include "StringBuffer.h"
#include "XMLTokenizer.h"
+
#include <wtf/Assertions.h>
#include <wtf/unicode/Unicode.h>
stopLoadingSubresources();
stopLoadingPlugIns();
-
- frameLoader()->finalSetupForReplace(this);
+ clearArchiveResources();
}
void DocumentLoader::updateLoading()
return frameLoader()->subframeIsLoading();
}
+void DocumentLoader::addAllArchiveResources(Archive* archive)
+{
+ if (!m_archiveResourceCollection)
+ m_archiveResourceCollection.set(new ArchiveResourceCollection);
+
+ ASSERT(archive);
+ if (!archive)
+ return;
+
+ m_archiveResourceCollection->addAllResources(archive);
+}
+
+// FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on.
+// Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps?
+void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource)
+{
+ if (!m_archiveResourceCollection)
+ m_archiveResourceCollection.set(new ArchiveResourceCollection);
+
+ ASSERT(resource);
+ if (!resource)
+ return;
+
+ m_archiveResourceCollection->addResource(resource);
+}
+
+ArchiveResource* DocumentLoader::archiveResourceForURL(const KURL& url)
+{
+ if (!m_archiveResourceCollection)
+ return 0;
+
+ ArchiveResource* resource = m_archiveResourceCollection->archiveResourceForURL(url);
+
+ return resource && !resource->shouldIgnoreWhenUnarchiving() ? resource : 0;
+}
+
+PassRefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName)
+{
+ return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName) : 0;
+}
+
+void DocumentLoader::clearArchiveResources()
+{
+ m_archiveResourceCollection.clear();
+}
+
void DocumentLoader::addResponse(const ResourceResponse& r)
{
if (!m_stopRecordingResponses)
namespace WebCore {
+ class Archive;
+ class ArchiveResource;
+ class ArchiveResourceCollection;
class CachedPage;
class Frame;
class FrameLoader;
void unschedule(SchedulePair*);
#endif
+ void addAllArchiveResources(Archive*);
+ void addArchiveResource(PassRefPtr<ArchiveResource>);
+ ArchiveResource* archiveResourceForURL(const KURL&);
+ PassRefPtr<Archive> popArchiveForSubframe(const String& frameName);
+ void clearArchiveResources();
+
void addResponse(const ResourceResponse&);
const ResponseVector& responses() const { return m_responses; }
// page cache.
ResponseVector m_responses;
bool m_stopRecordingResponses;
+
+ OwnPtr<ArchiveResourceCollection> m_archiveResourceCollection;
};
}
#include "config.h"
#include "FrameLoader.h"
+#include "Archive.h"
+#include "ArchiveFactory.h"
#include "CString.h"
#include "Cache.h"
#include "CachedPage.h"
, m_isDisplayingInitialEmptyDocument(false)
, m_committedFirstRealDocumentLoad(false)
, m_didPerformFirstNavigation(false)
+ , m_archiveResourceDeliveryTimer(this, &FrameLoader::archiveResourceDeliveryTimerFired)
#ifndef NDEBUG
, m_didDispatchDidCommitLoad(false)
#endif
m_provisionalDocumentLoader->setDefersLoading(defers);
if (m_policyDocumentLoader)
m_policyDocumentLoader->setDefersLoading(defers);
- m_client->setDefersLoading(defers);
+ if (!defers)
+ deliverArchivedResourcesAfterDelay();
}
Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
ASSERT_NOT_REACHED();
}
+void FrameLoader::deliverArchivedResourcesAfterDelay()
+{
+ if (m_pendingArchiveResources.isEmpty())
+ return;
+ if (m_frame->page()->defersLoading())
+ return;
+ if (!m_archiveResourceDeliveryTimer.isActive())
+ m_archiveResourceDeliveryTimer.startOneShot(0);
+}
+
+void FrameLoader::archiveResourceDeliveryTimerFired(Timer<FrameLoader>*)
+{
+ if (m_pendingArchiveResources.isEmpty())
+ return;
+ if (m_frame->page()->defersLoading())
+ return;
+
+ ArchiveResourceMap copy;
+ copy.swap(m_pendingArchiveResources);
+
+ ArchiveResourceMap::const_iterator end = copy.end();
+ for (ArchiveResourceMap::const_iterator it = copy.begin(); it != end; ++it) {
+ RefPtr<ResourceLoader> loader = it->first;
+ ArchiveResource* resource = it->second.get();
+
+ SharedBuffer* data = resource->data();
+
+ loader->didReceiveResponse(resource->response());
+ loader->didReceiveData(data->data(), data->size(), data->size(), true);
+ loader->didFinishLoading();
+ }
+}
+
+/*
+ In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
+ The item that was the target of the user's navigation is designated as the "targetItem".
+ When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
+ which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
+*/
+void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame)
+{
+ ASSERT(childFrame);
+ HistoryItem* parentItem = currentHistoryItem();
+ FrameLoadType loadType = this->loadType();
+ FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory;
+
+ KURL workingURL = url;
+
+ // If we're moving in the backforward list, we might want to replace the content
+ // of this child frame with whatever was there at that point.
+ // Reload will maintain the frame contents, LoadSame will not.
+ if (parentItem && parentItem->children().size() &&
+ (isBackForwardLoadType(loadType) || loadType == FrameLoadTypeReloadAllowingStaleData))
+ {
+ HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree()->name());
+ if (childItem) {
+ // Use the original URL to ensure we get all the side-effects, such as
+ // onLoad handlers, of any redirects that happened. An example of where
+ // this is needed is Radar 3213556.
+ workingURL = KURL(childItem->originalURLString());
+ // These behaviors implied by these loadTypes should apply to the child frames
+ childLoadType = loadType;
+
+ if (isBackForwardLoadType(loadType)) {
+ // For back/forward, remember this item so we can traverse any child items as child frames load
+ childFrame->loader()->setProvisionalHistoryItem(childItem);
+ } else {
+ // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
+ childFrame->loader()->setCurrentHistoryItem(childItem);
+ }
+ }
+ }
+
+ RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name());
+
+ if (subframeArchive)
+ childFrame->loader()->loadArchive(subframeArchive.release());
+ else
+ childFrame->loader()->load(workingURL, referer, childLoadType, String(), 0, 0);
+}
+
+void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
+{
+ RefPtr<Archive> archive = prpArchive;
+
+ ArchiveResource* mainResource = archive->mainResource();
+ ASSERT(mainResource);
+ if (!mainResource)
+ return;
+
+ SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
+
+ ResourceRequest request(mainResource->url());
+#if PLATFORM(MAC)
+ request.applyWebArchiveHackForMail();
+#endif
+
+ RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
+ documentLoader->addAllArchiveResources(archive.get());
+ load(documentLoader.get());
+}
+
String FrameLoader::encoding() const
{
if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
}
-void FrameLoader::finalSetupForReplace(DocumentLoader* loader)
-{
- m_client->clearUnarchivingState(loader);
-}
-
void FrameLoader::load(const KURL& url, Event* event)
{
load(ResourceRequest(url), false, true, event, 0, HashMap<String, String>());
activeDocumentLoader()->receivedData(data, length);
}
-bool FrameLoader::willUseArchive(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) const
+bool FrameLoader::scheduleArchiveLoad(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL)
{
- return m_client->willUseArchive(loader, request, originalURL);
+ if (request.url() != originalURL)
+ return false;
+
+ DocumentLoader* activeLoader = activeDocumentLoader();
+ ASSERT(activeLoader);
+ if (!activeLoader)
+ return false;
+
+ ArchiveResource* resource = activeLoader->archiveResourceForURL(originalURL);
+ if (!resource)
+ return false;
+
+ m_pendingArchiveResources.set(loader, resource);
+ deliverArchivedResourcesAfterDelay();
+
+ return true;
}
void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
stopLoadingSubframes();
if (m_provisionalDocumentLoader)
m_provisionalDocumentLoader->stopLoading();
- if (m_documentLoader)
+ if (m_documentLoader) {
m_documentLoader->stopLoading();
+ m_documentLoader->clearArchiveResources();
+ m_archiveResourceDeliveryTimer.stop();
+ }
setProvisionalDocumentLoader(0);
- m_client->clearArchivedResources();
m_inStopAllLoaders = false;
}
void FrameLoader::cancelPendingArchiveLoad(ResourceLoader* loader)
{
- m_client->cancelPendingArchiveLoad(loader);
+ if (m_pendingArchiveResources.isEmpty())
+ return;
+ m_pendingArchiveResources.remove(loader);
+ if (m_pendingArchiveResources.isEmpty())
+ m_archiveResourceDeliveryTimer.stop();
}
DocumentLoader* FrameLoader::activeDocumentLoader() const
checkLoadComplete();
}
+#ifndef NDEBUG
bool FrameLoader::isArchiveLoadPending(ResourceLoader* loader) const
{
- return m_client->isArchiveLoadPending(loader);
+ return m_pendingArchiveResources.contains(loader);
}
+#endif
bool FrameLoader::isHostedByObjectElement() const
{
void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
{
#if PLATFORM(WIN)
- if (!m_creatingInitialEmptyDocument)
+ if (m_creatingInitialEmptyDocument)
+ return;
#endif
- m_client->finishedLoading(loader);
+ m_client->finishedLoading(loader);
+
+ // If loading a webarchive, run through webarchive machinery
+ const String& responseMIMEType = loader->responseMIMEType();
+ if (!ArchiveFactory::isArchiveMimeType(responseMIMEType))
+ return;
+
+ RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().get(), responseMIMEType));
+ if (!archive)
+ return;
+
+ loader->addAllArchiveResources(archive.get());
+
+ ArchiveResource* mainResource = archive->mainResource();
+ continueLoadWithData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), mainResource->url());
}
bool FrameLoader::isReplacing() const
namespace WebCore {
+ class Archive;
+ class ArchiveResource;
class AuthenticationChallenge;
class CachedPage;
class Document;
void prepareForLoadStart();
void setupForReplace();
void setupForReplaceByMIMEType(const String& newMIMEType);
- void finalSetupForReplace(DocumentLoader*);
void load(const KURL&, Event*);
void load(const FrameLoadRequest&, bool lockHistory, bool userGesture,
Event*, HTMLFormElement*, const HashMap<String, String>& formValues);
void load(DocumentLoader*);
void load(DocumentLoader*, FrameLoadType, PassRefPtr<FormState>);
+
+ void loadURLIntoChildFrame(const KURL&, const String& referer, Frame*);
+ void loadArchive(PassRefPtr<Archive> archive);
static bool canLoad(const KURL&, const String& referrer);
static bool canLoad(const KURL&, const Document*);
ResourceError cancelledError(const ResourceRequest&) const;
ResourceError fileDoesNotExistError(const ResourceResponse&) const;
ResourceError blockedError(const ResourceRequest&) const;
- bool willUseArchive(ResourceLoader*, const ResourceRequest&, const KURL&) const;
+ bool scheduleArchiveLoad(ResourceLoader*, const ResourceRequest&, const KURL&);
+#ifndef NDEBUG
bool isArchiveLoadPending(ResourceLoader*) const;
+#endif
void cannotShowMIMEType(const ResourceResponse&);
ResourceError interruptionForPolicyChangeError(const ResourceRequest&);
void redirectionTimerFired(Timer<FrameLoader>*);
void checkCompletedTimerFired(Timer<FrameLoader>*);
void checkLoadCompleteTimerFired(Timer<FrameLoader>*);
+
+ void deliverArchivedResourcesAfterDelay();
+ void archiveResourceDeliveryTimerFired(Timer<FrameLoader>*);
void cancelRedirection(bool newLoadInProgress = false);
RefPtr<HistoryItem> m_provisionalHistoryItem;
bool m_didPerformFirstNavigation;
+
+ typedef HashMap<RefPtr<ResourceLoader>, RefPtr<ArchiveResource> > ArchiveResourceMap;
+ ArchiveResourceMap m_pendingArchiveResources;
+ Timer<FrameLoader> m_archiveResourceDeliveryTimer;
#ifndef NDEBUG
bool m_didDispatchDidCommitLoad;
return false;
}
- if (frameLoader()->willUseArchive(this, clientRequest, r.url()))
+ if (frameLoader()->scheduleArchiveLoad(this, clientRequest, r.url()))
return true;
if (m_defersLoading) {
#ifndef Archive_h
#define Archive_h
-// FIXME: Code will go here!
+#include "ArchiveResource.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Archive : public RefCounted<Archive> {
+public:
+ ArchiveResource* mainResource() { return m_mainResource.get(); }
+ const Vector<RefPtr<ArchiveResource> >& subresources() const { return m_subresources; }
+ const Vector<RefPtr<Archive> >& subframeArchives() const { return m_subframeArchives; }
+
+protected:
+ // These methods are meant for subclasses for different archive types to add resources in to the archive,
+ // and should not be exposed as archives should be immutable to clients
+ void setMainResource(PassRefPtr<ArchiveResource> mainResource) { m_mainResource = mainResource; }
+ void addSubresource(PassRefPtr<ArchiveResource> subResource) { m_subresources.append(subResource); }
+ void addSubframeArchive(PassRefPtr<Archive> subframeArchive) { m_subframeArchives.append(subframeArchive); }
+
+private:
+ RefPtr<ArchiveResource> m_mainResource;
+ Vector<RefPtr<ArchiveResource> > m_subresources;
+ Vector<RefPtr<Archive> > m_subframeArchives;
+};
+
+}
#endif // Archive
#include "config.h"
#include "ArchiveFactory.h"
-// FIXME: Code will go here!
+#include "LegacyWebArchive.h"
+#include "MIMETypeRegistry.h"
+#include "PlatformString.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+
+namespace WebCore {
+
+typedef PassRefPtr<Archive> RawDataCreationFunction(SharedBuffer*);
+
+// The create functions in the archive classes return PassRefPtr to concrete subclasses
+// of Archive. This adaptor makes the functions have a uniform return type.
+template <typename ArchiveClass> static PassRefPtr<Archive> archiveFactoryCreate(SharedBuffer* buffer)
+{
+ return ArchiveClass::create(buffer);
+}
+
+static HashMap<String, RawDataCreationFunction*, CaseFoldingHash>& archiveMIMETypes()
+{
+ static HashMap<String, RawDataCreationFunction*, CaseFoldingHash> mimeTypes;
+ static bool initialized = false;
+
+ if (initialized)
+ return mimeTypes;
+
+#if PLATFORM(CF)
+ mimeTypes.set("application/x-webarchive", archiveFactoryCreate<LegacyWebArchive>);
+#endif
+
+ initialized = true;
+ return mimeTypes;
+}
+
+bool ArchiveFactory::isArchiveMimeType(const String& mimeType)
+{
+ return archiveMIMETypes().contains(mimeType);
+}
+
+PassRefPtr<Archive> ArchiveFactory::create(SharedBuffer* data, const String& mimeType)
+{
+ RawDataCreationFunction* function = archiveMIMETypes().get(mimeType);
+ return function ? function(data) : 0;
+}
+
+void ArchiveFactory::registerKnownArchiveMIMETypes()
+{
+ HashSet<String>& mimeTypes = MIMETypeRegistry::getSupportedNonImageMIMETypes();
+ HashMap<String, RawDataCreationFunction*, CaseFoldingHash>::iterator i = archiveMIMETypes().begin();
+ HashMap<String, RawDataCreationFunction*, CaseFoldingHash>::iterator end = archiveMIMETypes().end();
+
+ for (; i != end; ++i)
+ mimeTypes.add(i->first);
+}
+
+}
#ifndef ArchiveFactory_h
#define ArchiveFactory_h
-// FIXME: Code will go here!
+#include "Archive.h"
-#endif // ArchiveFactory
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class SharedBuffer;
+class String;
+
+class ArchiveFactory {
+public:
+ static bool isArchiveMimeType(const String&);
+ static PassRefPtr<Archive> create(SharedBuffer* data, const String& mimeType);
+ static void registerKnownArchiveMIMETypes();
+};
+
+}
+
+#endif // ArchiveFactory_h
#include "config.h"
#include "ArchiveResource.h"
-// FIXME: Code will go here!
+#include "SharedBuffer.h"
+
+namespace WebCore {
+
+PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName)
+{
+ return adoptRef(new ArchiveResource(data, url, mimeType, textEncoding, frameName));
+}
+
+PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& resourceResponse)
+{
+ return adoptRef(new ArchiveResource(data, url, mimeType, textEncoding, frameName, resourceResponse));
+}
+
+ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName)
+ : m_data(data)
+ , m_url(url)
+ , m_mimeType(mimeType)
+ , m_textEncoding(textEncoding)
+ , m_frameName(frameName)
+ , m_shouldIgnoreWhenUnarchiving(false)
+{
+}
+
+ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& response)
+ : m_data(data)
+ , m_url(url)
+ , m_mimeType(mimeType)
+ , m_textEncoding(textEncoding)
+ , m_frameName(frameName)
+ , m_response(response)
+ , m_shouldIgnoreWhenUnarchiving(false)
+{
+}
+
+const ResourceResponse& ArchiveResource::response()
+{
+ if (!m_response.isNull())
+ return m_response;
+
+ m_response = ResourceResponse(m_url, m_mimeType, m_data->size(), m_textEncoding, String());
+ return m_response;
+}
+
+}
#ifndef ArchiveResource_h
#define ArchiveResource_h
-// FIXME: Code will go here!
+#include "KURL.h"
+#include "PlatformString.h"
+#include "ResourceResponse.h"
+#include "SharedBuffer.h"
-#endif // ArchiveResource
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class ArchiveResource : public RefCounted<ArchiveResource> {
+public:
+ static PassRefPtr<ArchiveResource> create(PassRefPtr<SharedBuffer>, const KURL&, const String& mimeType, const String& textEncoding, const String& frameName);
+ static PassRefPtr<ArchiveResource> create(PassRefPtr<SharedBuffer>, const KURL&, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse&);
+
+ SharedBuffer* data() { return m_data.get(); }
+
+ const KURL& url() const { return m_url; }
+ const String& mimeType() const { return m_mimeType; }
+ const String& textEncoding() const { return m_textEncoding; }
+ const String& frameName() const { return m_frameName; }
+ const ResourceResponse& response();
+
+ void ignoreWhenUnarchiving() { m_shouldIgnoreWhenUnarchiving = true; }
+ bool shouldIgnoreWhenUnarchiving() const { return m_shouldIgnoreWhenUnarchiving; }
+
+private:
+ ArchiveResource(PassRefPtr<SharedBuffer>, const KURL&, const String& mimeType, const String& textEncoding, const String& frameName);
+ ArchiveResource(PassRefPtr<SharedBuffer>, const KURL&, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse&);
+
+ RefPtr<SharedBuffer> m_data;
+ KURL m_url;
+ String m_mimeType;
+ String m_textEncoding;
+ String m_frameName;
+
+ ResourceResponse m_response;
+
+ bool m_shouldIgnoreWhenUnarchiving;
+};
+
+}
+
+#endif // ArchiveResource_h
#include "config.h"
#include "ArchiveResourceCollection.h"
-// FIXME: Code will go here!
+namespace WebCore {
+
+ArchiveResourceCollection::ArchiveResourceCollection()
+{
+}
+
+void ArchiveResourceCollection::addAllResources(Archive* archive)
+{
+ ASSERT(archive);
+ if (!archive)
+ return;
+
+ const Vector<RefPtr<ArchiveResource> >& subresources = archive->subresources();
+ Vector<RefPtr<ArchiveResource> >::const_iterator iRes = subresources.begin();
+ Vector<RefPtr<ArchiveResource> >::const_iterator endRes = subresources.end();
+
+ for (; iRes != endRes; ++iRes)
+ m_subresources.set((*iRes)->url(), iRes->get());
+
+ const Vector<RefPtr<Archive> >& subframes = archive->subframeArchives();
+ Vector<RefPtr<Archive> >::const_iterator iFrame = subframes.begin();
+ Vector<RefPtr<Archive> >::const_iterator endFrame = subframes.end();
+
+ for (; iFrame != endFrame; ++iFrame) {
+ ASSERT((*iFrame)->mainResource());
+ const String& frameName = (*iFrame)->mainResource()->frameName();
+ if (!frameName.isNull())
+ m_subframes.set(frameName, iFrame->get());
+ }
+}
+
+// FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on.
+// Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps?
+void ArchiveResourceCollection::addResource(PassRefPtr<ArchiveResource> resource)
+{
+ ASSERT(resource);
+ if (!resource)
+ return;
+
+ const KURL& url = resource->url(); // get before passing PassRefPtr (which sets it to 0)
+ m_subresources.set(url, resource);
+}
+
+ArchiveResource* ArchiveResourceCollection::archiveResourceForURL(const KURL& url)
+{
+ ArchiveResource* resource = m_subresources.get(url).get();
+ if (!resource)
+ return 0;
+
+ return resource;
+}
+
+PassRefPtr<Archive> ArchiveResourceCollection::popSubframeArchive(const String& frameName)
+{
+ return m_subframes.take(frameName);
+}
+
+}
#ifndef ArchiveResourceCollection_h
#define ArchiveResourceCollection_h
-// FIXME: Code will go here!
+#include "Archive.h"
+#include "ArchiveResource.h"
+#include "KURL.h"
+#include "PlatformString.h"
-#endif // ArchiveResourceCollection
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class ArchiveResourceCollection : Noncopyable {
+public:
+ ArchiveResourceCollection();
+
+ void addResource(PassRefPtr<ArchiveResource>);
+ void addAllResources(Archive*);
+
+ ArchiveResource* archiveResourceForURL(const KURL&);
+ PassRefPtr<Archive> popSubframeArchive(const String& frameName);
+
+private:
+ HashMap<String, RefPtr<ArchiveResource> > m_subresources;
+ HashMap<String, RefPtr<Archive> > m_subframes;
+};
+
+}
+
+#endif
#include "config.h"
#include "LegacyWebArchive.h"
-// FIXME: Code will go here!
+#include "KURL.h"
+#include "Logging.h"
+#include "SharedBuffer.h"
+
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+static const CFStringRef LegacyWebArchiveMainResourceKey = CFSTR("WebMainResource");
+static const CFStringRef LegacyWebArchiveSubresourcesKey = CFSTR("WebSubresources");
+static const CFStringRef LegacyWebArchiveSubframeArchivesKey = CFSTR("WebSubframeArchives");
+static const CFStringRef LegacyWebArchiveResourceDataKey = CFSTR("WebResourceData");
+static const CFStringRef LegacyWebArchiveResourceFrameNameKey = CFSTR("WebResourceFrameName");
+static const CFStringRef LegacyWebArchiveResourceMIMETypeKey = CFSTR("WebResourceMIMEType");
+static const CFStringRef LegacyWebArchiveResourceURLKey = CFSTR("WebResourceURL");
+static const CFStringRef LegacyWebArchiveResourceTextEncodingNameKey = CFSTR("WebResourceTextEncodingName");
+static const CFStringRef LegacyWebArchiveResourceResponseKey = CFSTR("WebResourceResponse");
+static const CFStringRef LegacyWebArchiveResourceResponseVersionKey = CFSTR("WebResourceResponseVersion");
+
+static RetainPtr<CFDictionaryRef> createPropertyListRepresentationFromResource(ArchiveResource* resource, bool mainResource)
+{
+ if (!resource) {
+ // The property list representation of a null/empty WebResource has the following 3 objects stored as nil
+ RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 3, 0, 0));
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceDataKey, 0);
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceURLKey, 0);
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceMIMETypeKey, 0);
+
+ return propertyList;
+ }
+
+ RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 6, 0, &kCFTypeDictionaryValueCallBacks));
+
+ // Resource data can be empty, but must be represented by an empty CFDataRef
+ SharedBuffer* data = resource->data();
+ RetainPtr<CFDataRef> cfData;
+ if (data)
+ cfData.adoptCF(data->createCFData());
+ else
+ cfData.adoptCF(CFDataCreate(0, 0, 0));
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceDataKey, cfData.get());
+
+ // Resource URL cannot be null
+ RetainPtr<CFStringRef> cfURL(AdoptCF, resource->url().string().createCFString());
+ if (cfURL)
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceURLKey, cfURL.get());
+ else {
+ LOG(Archives, "LegacyWebArchive - NULL resource URL is invalid - returning null property list");
+ return 0;
+ }
+
+ // FrameName should be left out if empty for subresources, but always included for main resources
+ const String& frameName(resource->frameName());
+ if (!frameName.isEmpty() || mainResource) {
+ RetainPtr<CFStringRef> cfFrameName(AdoptCF, frameName.createCFString());
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceFrameNameKey, cfFrameName.get());
+ }
+
+ // Set MIMEType, TextEncodingName, and ResourceResponse only if they actually exist
+ const String& mimeType(resource->mimeType());
+ if (!mimeType.isEmpty()) {
+ RetainPtr<CFStringRef> cfMIMEType(AdoptCF, mimeType.createCFString());
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceMIMETypeKey, cfMIMEType.get());
+ }
+
+ const String& textEncoding(resource->textEncoding());
+ if (!textEncoding.isEmpty()) {
+ RetainPtr<CFStringRef> cfTextEncoding(AdoptCF, textEncoding.createCFString());
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceTextEncodingNameKey, cfTextEncoding.get());
+ }
+
+ // Don't include the resource response for the main resource
+ if (!mainResource) {
+ RetainPtr<CFDataRef> resourceResponseData = propertyListDataFromResourceResponse(resource->response());
+ if (resourceResponseData)
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceResponseKey, resourceResponseData.get());
+ }
+
+ return propertyList;
+}
+
+static RetainPtr<CFDictionaryRef> createPropertyListRep(Archive* archive)
+{
+ RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 3, 0, &kCFTypeDictionaryValueCallBacks));
+
+ RetainPtr<CFDictionaryRef> mainResourceDict = createPropertyListRepresentationFromResource(archive->mainResource(), true);
+ if (!mainResourceDict)
+ return 0;
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveMainResourceKey, mainResourceDict.get());
+
+ RetainPtr<CFMutableArrayRef> subresourcesArray(AdoptCF, CFArrayCreateMutable(0, archive->subresources().size(), &kCFTypeArrayCallBacks));
+ const Vector<RefPtr<ArchiveResource> >& subresources(archive->subresources());
+ for (unsigned i = 0; i < subresources.size(); ++i) {
+ RetainPtr<CFDictionaryRef> subresource = createPropertyListRepresentationFromResource(subresources[i].get(), false);
+ if (subresource)
+ CFArrayAppendValue(subresourcesArray.get(), subresource.get());
+ else
+ LOG(Archives, "LegacyWebArchive - Failed to create property list for subresource");
+ }
+ if (CFArrayGetCount(subresourcesArray.get()))
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveSubresourcesKey, subresourcesArray.get());
+
+ RetainPtr<CFMutableArrayRef> subframesArray(AdoptCF, CFArrayCreateMutable(0, archive->subframeArchives().size(), &kCFTypeArrayCallBacks));
+ const Vector<RefPtr<Archive> >& subframeArchives(archive->subframeArchives());
+ for (unsigned i = 0; i < subframeArchives.size(); ++i) {
+ RetainPtr<CFDictionaryRef> subframeArchive = createPropertyListRep(subframeArchives[i].get());
+ if (subframeArchive)
+ CFArrayAppendValue(subframesArray.get(), subframeArchive.get());
+ else
+ LOG(Archives, "LegacyWebArchive - Failed to create property list for subframe archive");
+ }
+ if (CFArrayGetCount(subframesArray.get()))
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveSubframeArchivesKey, subframesArray.get());
+
+ return propertyList;
+}
+
+static ResourceResponse createResourceResponseFromPropertyListData(CFDataRef data, CFStringRef responseDataType)
+{
+ ASSERT(data);
+ if (!data)
+ return ResourceResponse();
+
+ // If the ResourceResponseVersion (passed in as responseDataType) exists at all, this is a "new" webarchive that we can parse well in a cross platform manner
+ // If it doesn't exist, we will assume this is an "old" Cocoa-based WebArchive, and parse the ResourceResponse as such
+ if (!responseDataType)
+ return createResourceResponseFromMacArchivedData(data);
+
+ // FIXME: Parse the "new" format that the above comment references here
+ return ResourceResponse();
+}
+
+static PassRefPtr<ArchiveResource> createResource(CFDictionaryRef dictionary)
+{
+ ASSERT(dictionary);
+ if (!dictionary)
+ return 0;
+
+ CFDataRef resourceData = static_cast<CFDataRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceDataKey));
+ if (resourceData && CFGetTypeID(resourceData) != CFDataGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Resource data is not of type CFData, cannot create invalid resource");
+ return 0;
+ }
+
+ CFStringRef frameName = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceFrameNameKey));
+ if (frameName && CFGetTypeID(frameName) != CFStringGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Frame name is not of type CFString, cannot create invalid resource");
+ return 0;
+ }
+
+ CFStringRef mimeType = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceMIMETypeKey));
+ if (mimeType && CFGetTypeID(mimeType) != CFStringGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - MIME type is not of type CFString, cannot create invalid resource");
+ return 0;
+ }
+
+ CFStringRef url = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceURLKey));
+ if (url && CFGetTypeID(url) != CFStringGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - URL is not of type CFString, cannot create invalid resource");
+ return 0;
+ }
+
+ CFStringRef textEncoding = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceTextEncodingNameKey));
+ if (textEncoding && CFGetTypeID(textEncoding) != CFStringGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Text encoding is not of type CFString, cannot create invalid resource");
+ return 0;
+ }
+
+ ResourceResponse response;
+
+ CFDataRef resourceResponseData = static_cast<CFDataRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceResponseKey));
+ if (resourceResponseData) {
+ if (CFGetTypeID(resourceResponseData) != CFDataGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Resource response data is not of type CFData, cannot create invalid resource");
+ return 0;
+ }
+
+ CFStringRef resourceResponseVersion = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceResponseVersionKey));
+ if (resourceResponseVersion && CFGetTypeID(resourceResponseVersion) != CFStringGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Resource response version is not of type CFString, cannot create invalid resource");
+ return 0;
+ }
+
+ response = createResourceResponseFromPropertyListData(resourceResponseData, resourceResponseVersion);
+ }
+
+ return ArchiveResource::create(SharedBuffer::create(CFDataGetBytePtr(resourceData), CFDataGetLength(resourceData)), KURL(url), mimeType, textEncoding, frameName, response);
+}
+
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create()
+{
+ return adoptRef(new LegacyWebArchive);
+}
+
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(SharedBuffer* data)
+{
+ LOG(Archives, "LegacyWebArchive - Creating from raw data");
+
+ RefPtr<LegacyWebArchive> archive = create();
+ if (!archive->init(data))
+ return 0;
+
+ return archive.release();
+}
+
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(PassRefPtr<ArchiveResource> mainResource, Vector<PassRefPtr<ArchiveResource> >& subresources, Vector<PassRefPtr<LegacyWebArchive> >& subframeArchives)
+{
+ ASSERT(mainResource);
+ if (!mainResource)
+ return 0;
+
+ RefPtr<LegacyWebArchive> archive = create();
+ archive->setMainResource(mainResource);
+
+ for (unsigned i = 0; i < subresources.size(); ++i)
+ archive->addSubresource(subresources[i]);
+
+ for (unsigned i = 0; i < subframeArchives.size(); ++i)
+ archive->addSubframeArchive(subframeArchives[i]);
+
+ return archive.release();
+}
+
+LegacyWebArchive::LegacyWebArchive()
+{
+}
+
+bool LegacyWebArchive::init(SharedBuffer* data)
+{
+ ASSERT(data);
+ if (!data)
+ return false;
+
+ RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData());
+ if (!cfData)
+ return false;
+
+ CFStringRef errorString = 0;
+
+ RetainPtr<CFDictionaryRef> plist(AdoptCF, static_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(0, cfData.get(), kCFPropertyListImmutable, &errorString)));
+ if (!plist) {
+#ifndef NDEBUG
+ const char* cError = errorString ? CFStringGetCStringPtr(errorString, kCFStringEncodingUTF8) : "unknown error";
+ LOG(Archives, "LegacyWebArchive - Error parsing PropertyList from archive data - %s", cError);
+#endif
+ if (errorString)
+ CFRelease(errorString);
+ return false;
+ }
+
+ if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Archive property list is not the expected CFDictionary, aborting invalid WebArchive");
+ return false;
+ }
+
+ return extract(plist.get());
+}
+
+bool LegacyWebArchive::extract(CFDictionaryRef dictionary)
+{
+ ASSERT(dictionary);
+ if (!dictionary) {
+ LOG(Archives, "LegacyWebArchive - Null root CFDictionary, aborting invalid WebArchive");
+ return false;
+ }
+
+ CFDictionaryRef mainResourceDict = static_cast<CFDictionaryRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveMainResourceKey));
+ if (!mainResourceDict) {
+ LOG(Archives, "LegacyWebArchive - No main resource in archive, aborting invalid WebArchive");
+ return false;
+ }
+ if (CFGetTypeID(mainResourceDict) != CFDictionaryGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Main resource is not the expected CFDictionary, aborting invalid WebArchive");
+ return false;
+ }
+
+ setMainResource(createResource(mainResourceDict));
+ if (!mainResource()) {
+ LOG(Archives, "LegacyWebArchive - Failed to parse main resource from CFDictionary or main resource does not exist, aborting invalid WebArchive");
+ return false;
+ }
+
+ CFArrayRef subresourceArray = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveSubresourcesKey));
+ if (subresourceArray && CFGetTypeID(subresourceArray) != CFArrayGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Subresources is not the expected Array, aborting invalid WebArchive");
+ return false;
+ }
+
+ if (subresourceArray) {
+ CFIndex count = CFArrayGetCount(subresourceArray);
+ for (CFIndex i = 0; i < count; ++i) {
+ CFDictionaryRef subresourceDict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(subresourceArray, i));
+ if (CFGetTypeID(subresourceDict) != CFDictionaryGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Subresource is not expected CFDictionary, aborting invalid WebArchive");
+ return false;
+ }
+ addSubresource(createResource(subresourceDict));
+ }
+ }
+
+ CFArrayRef subframeArray = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveSubframeArchivesKey));
+ if (subframeArray && CFGetTypeID(subframeArray) != CFArrayGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Subframe archives is not the expected Array, aborting invalid WebArchive");
+ return false;
+ }
+
+ if (subframeArray) {
+ CFIndex count = CFArrayGetCount(subframeArray);
+ for (CFIndex i = 0; i < count; ++i) {
+ CFDictionaryRef subframeDict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(subframeArray, i));
+ if (CFGetTypeID(subframeDict) != CFDictionaryGetTypeID()) {
+ LOG(Archives, "LegacyWebArchive - Subframe array is not expected CFDictionary, aborting invalid WebArchive");
+ return false;
+ }
+
+ RefPtr<LegacyWebArchive> subframeArchive = create();
+ if (subframeArchive->extract(subframeDict))
+ addSubframeArchive(subframeArchive.release());
+ else
+ LOG(Archives, "LegacyWebArchive - Invalid subframe archive skipped");
+ }
+ }
+
+ return true;
+}
+
+RetainPtr<CFDataRef> LegacyWebArchive::rawDataRepresentation()
+{
+ RetainPtr<CFDictionaryRef> propertyList = createPropertyListRep(this);
+ if (!propertyList) {
+ LOG(Archives, "LegacyWebArchive - Failed to create property list for archive, returning no data");
+ return 0;
+ }
+
+ // FIXME: On Mac, WebArchives have been written out as Binary Property Lists until this change.
+ // Unless we jump through CFWriteStream hoops, they'll now be textual XML data. Is this okay?
+ RetainPtr<CFDataRef> plistData(AdoptCF, CFPropertyListCreateXMLData(0, propertyList.get()));
+ if (!plistData) {
+ LOG(Archives, "LegacyWebArchive - Failed to convert property list into raw data, returning no data");
+ return 0;
+ }
+
+ return plistData;
+}
+
+#if !PLATFORM(MAC)
+// FIXME: Is it possible to parse in a Cocoa-style resource response manually,
+// without NSKeyed(Un)Archiver, manipulating plists directly?
+// If so, the code that does it will go here.
+// In the meantime, Mac will continue to NSKeyed(Un)Archive the response as it always has
+ResourceResponse createResourceResponseFromMacArchivedData(CFDataRef responseData)
+{
+ return ResourceResponse();
+}
+
+RetainPtr<CFDataRef> propertyListDataFromResourceResponse(const ResourceResponse& response)
+{
+ // FIXME: Write out the "new" format described in ::createResourceResponseFromPropertyListData() up above
+ return 0;
+}
+#endif
+
+}
#ifndef LegacyWebArchive_h
#define LegacyWebArchive_h
-// FIXME: Code will go here!
+#include "Archive.h"
+
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class LegacyWebArchive : public Archive {
+public:
+ static PassRefPtr<LegacyWebArchive> create();
+ static PassRefPtr<LegacyWebArchive> create(SharedBuffer*);
+ static PassRefPtr<LegacyWebArchive> create(PassRefPtr<ArchiveResource> mainResource, Vector<PassRefPtr<ArchiveResource> >& subresources, Vector<PassRefPtr<LegacyWebArchive> >& subframeArchives);
+
+ RetainPtr<CFDataRef> rawDataRepresentation();
+
+private:
+ LegacyWebArchive();
+ bool init(SharedBuffer*);
+ bool extract(CFDictionaryRef);
+
+};
+
+ResourceResponse createResourceResponseFromMacArchivedData(CFDataRef);
+RetainPtr<CFDataRef> propertyListDataFromResourceResponse(const ResourceResponse&);
+
+}
#endif // Archive
#include "config.h"
#include "LegacyWebArchive.h"
-// FIXME: Code will go here!
+namespace WebCore {
+
+static const NSString *LegacyWebArchiveResourceResponseKey = @"WebResourceResponse";
+
+// FIXME: Is it possible to parse in a Cocoa-style resource response manually,
+// without NSKeyed(Un)Archiver, manipulating plists directly?
+ResourceResponse createResourceResponseFromMacArchivedData(CFDataRef responseData)
+{
+ ASSERT(responseData);
+ if (!responseData)
+ return ResourceResponse();
+
+ NSURLResponse *response;
+ NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)responseData];
+ @try {
+ id responseObject = [unarchiver decodeObjectForKey:LegacyWebArchiveResourceResponseKey];
+ if ([responseObject isKindOfClass:[NSURLResponse class]])
+ response = responseObject;
+ [unarchiver finishDecoding];
+ } @catch(id) {
+ response = nil;
+ }
+ [unarchiver release];
+
+ return ResourceResponse(response);
+}
+
+RetainPtr<CFDataRef> propertyListDataFromResourceResponse(const ResourceResponse& response)
+{
+ NSURLResponse *nsResponse = response.nsURLResponse();
+ if (!nsResponse)
+ return 0;
+
+ NSMutableData *responseData = (NSMutableData *)CFDataCreateMutable(0, 0);
+ NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:responseData];
+ [archiver encodeObject:nsResponse forKey:LegacyWebArchiveResourceResponseKey];
+ [archiver finishEncoding];
+ [archiver release];
+
+ return RetainPtr<CFDataRef>(AdoptCF, (CFDataRef)responseData);
+}
+
+}
: ResourceRequestBase()
, m_nsRequest(nsRequest) { }
+ void applyWebArchiveHackForMail();
NSURLRequest* nsURLRequest() const;
private:
m_nsRequest.adoptNS(nsRequest);
}
+void ResourceRequest::applyWebArchiveHackForMail()
+{
+ // Hack because Mail checks for this property to detect data / archive loads
+ [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)nsURLRequest()];
+}
+
}
+2008-03-25 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin
+
+ <rdar://problem/4516169> - Support WebArchives on Windows
+
+ * WebKit.xcodeproj/project.pbxproj:
+
2008-03-24 Brady Eidson <beidson@apple.com>
Reviewed by Darin's rubberstamp
5DE92FEF0BD7017E0059A5FD /* WebAssertions.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DE92FEE0BD7017E0059A5FD /* WebAssertions.h */; settings = {ATTRIBUTES = (Private, ); }; };
5DF7B1D10D161FD00062CD32 /* WebNetscapePlugInStreamLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DF7B1CF0D161FCF0062CD32 /* WebNetscapePlugInStreamLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
5DF7B1D20D161FD00062CD32 /* WebNetscapePlugInStreamLoaderClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5DF7B1D00D161FD00062CD32 /* WebNetscapePlugInStreamLoaderClient.mm */; };
- 650F74E409E488F70020118A /* WebUnarchivingState.h in Headers */ = {isa = PBXBuildFile; fileRef = 650F74E209E488F70020118A /* WebUnarchivingState.h */; };
- 650F74E509E488F70020118A /* WebUnarchivingState.m in Sources */ = {isa = PBXBuildFile; fileRef = 650F74E309E488F70020118A /* WebUnarchivingState.m */; };
65488DA1084FBCCB00831AD0 /* WebNSDictionaryExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 65488D9F084FBCCB00831AD0 /* WebNSDictionaryExtras.h */; };
65488DA2084FBCCB00831AD0 /* WebNSDictionaryExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = 65488DA0084FBCCB00831AD0 /* WebNSDictionaryExtras.m */; };
6550B7C7099EFAE90090D781 /* WebArchiver.h in Headers */ = {isa = PBXBuildFile; fileRef = 6550B7C5099EFAE90090D781 /* WebArchiver.h */; };
5DE92FEE0BD7017E0059A5FD /* WebAssertions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebAssertions.h; sourceTree = "<group>"; };
5DF7B1CF0D161FCF0062CD32 /* WebNetscapePlugInStreamLoaderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebNetscapePlugInStreamLoaderClient.h; sourceTree = "<group>"; };
5DF7B1D00D161FD00062CD32 /* WebNetscapePlugInStreamLoaderClient.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebNetscapePlugInStreamLoaderClient.mm; sourceTree = "<group>"; };
- 650F74E209E488F70020118A /* WebUnarchivingState.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebUnarchivingState.h; sourceTree = "<group>"; };
- 650F74E309E488F70020118A /* WebUnarchivingState.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WebUnarchivingState.m; sourceTree = "<group>"; };
65488D9F084FBCCB00831AD0 /* WebNSDictionaryExtras.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = WebNSDictionaryExtras.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
65488DA0084FBCCB00831AD0 /* WebNSDictionaryExtras.m */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = WebNSDictionaryExtras.m; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
6550B7C5099EFAE90090D781 /* WebArchiver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebArchiver.h; sourceTree = "<group>"; };
C0167BF70D7F5DD00028696E /* WebScriptDebugger.mm */,
515E27CC0458C86500CA2D3A /* WebUIDelegate.h */,
65A7D44A0568AB2600E70EF6 /* WebUIDelegatePrivate.h */,
- 650F74E209E488F70020118A /* WebUnarchivingState.h */,
51A8B579042834F700CA2D3A /* WebView.h */,
930D02BB06275F640076701E /* WebViewInternal.h */,
51A8B57D0428353A00CA2D3A /* WebViewPrivate.h */,
F5AEBB3D024A527601C1A526 /* WebPreferences.m */,
84311A1305EAAAF00088EDA4 /* WebResource.mm */,
7E6FEF0608985A7200C44C3F /* WebScriptDebugDelegate.mm */,
- 650F74E309E488F70020118A /* WebUnarchivingState.m */,
51A8B57A042834F700CA2D3A /* WebView.mm */,
);
name = WebView;
939810750824BF01008DF038 /* WebUIDelegate.h in Headers */,
939810830824BF01008DF038 /* WebUIDelegatePrivate.h in Headers */,
939810150824BF01008DF038 /* WebURLsWithTitles.h in Headers */,
- 650F74E409E488F70020118A /* WebUnarchivingState.h in Headers */,
939810700824BF01008DF038 /* WebView.h in Headers */,
939810460824BF01008DF038 /* WebViewFactory.h in Headers */,
9398109B0824BF01008DF038 /* WebViewInternal.h in Headers */,
939810CC0824BF01008DF038 /* WebStringTruncator.m in Sources */,
93EB178D09F88D460091F8FF /* WebSystemInterface.m in Sources */,
939810BE0824BF01008DF038 /* WebURLsWithTitles.m in Sources */,
- 650F74E509E488F70020118A /* WebUnarchivingState.m in Sources */,
939811070824BF01008DF038 /* WebView.mm in Sources */,
939810E80824BF01008DF038 /* WebViewFactory.mm in Sources */,
939810DD0824BF01008DF038 /* npapi.m in Sources */,
+2008-03-25 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin
+
+ <rdar://problem/4516169> - Support WebArchives on Windows
+ And paves the way for many future WebArchive bug fixes and enhancements
+
+ This change moves most of the real workhorse code about WebArchives into WebCore. It maintains
+ 1-to-1 relationships between a few objects in WebCore and WebKit. Such as:
+ * WebArchive <-> LegacyWebArchive
+ * WebResource <-> ArchiveResource
+ * WebUnarchivingState <-> ArchiveResourceCollection
+
+ The other biggest changes involve many FrameLoaderClient methods that existed soley for WebArchives
+ and now exist in WebCore
+
+ * WebCoreSupport/WebFrameLoaderClient.mm:
+ (WebFrameLoaderClient::clearUnarchivingState): Emptied - to be removed in a followup patch
+ (WebFrameLoaderClient::finalSetupForReplace):
+ (WebFrameLoaderClient::setDefersLoading):
+ (WebFrameLoaderClient::willUseArchive):
+ (WebFrameLoaderClient::isArchiveLoadPending):
+ (WebFrameLoaderClient::cancelPendingArchiveLoad):
+ (WebFrameLoaderClient::clearArchivedResources):
+ (WebFrameLoaderClient::createFrame):
+
+ * WebView/WebArchive.mm:
+ (+[WebArchivePrivate initialize]):
+ (-[WebArchivePrivate init]):
+ (-[WebArchivePrivate initWithCoreArchive:]):
+ (-[WebArchivePrivate coreArchive]):
+ (-[WebArchivePrivate setCoreArchive:]):
+ (-[WebArchivePrivate dealloc]):
+ (-[WebArchivePrivate finalize]):
+ (-[WebArchive init]):
+ (-[WebArchive initWithMainResource:subresources:subframeArchives:]):
+ (-[WebArchive initWithData:]):
+ (-[WebArchive initWithCoder:]):
+ (-[WebArchive encodeWithCoder:]):
+ (-[WebArchive mainResource]):
+ (-[WebArchive subresources]):
+ (-[WebArchive subframeArchives]):
+ (-[WebArchive data]):
+ (-[WebArchive _initWithCoreLegacyWebArchive:WebCore::]):
+ (-[WebArchive WebCore::]):
+ * WebView/WebArchiveInternal.h: Added.
+
+ * WebView/WebDataSource.mm:
+ (-[WebDataSourcePrivate dealloc]):
+ (-[WebDataSource _addSubframeArchives:]):
+ (-[WebDataSource _documentFragmentWithArchive:]):
+ (-[WebDataSource subresourceForURL:]):
+ (-[WebDataSource addSubresource:]):
+ * WebView/WebDataSourceInternal.h:
+
+ * WebView/WebFrame.mm:
+ (-[WebFrame loadArchive:]):
+ * WebView/WebFrameInternal.h:
+
+ * WebView/WebHTMLRepresentation.mm:
+ (-[WebHTMLRepresentation finishedLoadingWithDataSource:]):
+
+ * WebView/WebResource.mm:
+ (+[WebResourcePrivate initialize]):
+ (-[WebResourcePrivate init]):
+ (-[WebResourcePrivate initWithCoreResource:]):
+ (-[WebResourcePrivate dealloc]):
+ (-[WebResourcePrivate finalize]):
+ (-[WebResource initWithCoder:]):
+ (-[WebResource encodeWithCoder:]):
+ (-[WebResource data]):
+ (-[WebResource URL]):
+ (-[WebResource MIMEType]):
+ (-[WebResource textEncodingName]):
+ (-[WebResource frameName]):
+ (-[WebResource _initWithCoreResource:WebCore::]):
+ (-[WebResource WebCore::]):
+ (-[WebResource _ignoreWhenUnarchiving]):
+ (-[WebResource _initWithData:URL:MIMEType:textEncodingName:frameName:response:copyData:]):
+ (-[WebResource _fileWrapperRepresentation]):
+ (-[WebResource _response]):
+ (-[WebResource _stringValue]):
+ * WebView/WebResourceInternal.h: Added.
+ * WebView/WebResourcePrivate.h:
+
+ * WebView/WebUnarchivingState.h: Removed.
+ * WebView/WebUnarchivingState.m: Removed.
+
2008-03-24 Oliver Hunt <oliver@apple.com>
Reviewed by Mark Rowe.
void WebFrameLoaderClient::clearUnarchivingState(DocumentLoader* loader)
{
- [dataSource(loader) _clearUnarchivingState];
}
void WebFrameLoaderClient::willChangeEstimatedProgress()
void WebFrameLoaderClient::finalSetupForReplace(DocumentLoader* loader)
{
- [dataSource(loader) _clearUnarchivingState];
}
void WebFrameLoaderClient::updateGlobalHistory(const KURL& url)
void WebFrameLoaderClient::setDefersLoading(bool defers)
{
- if (!defers)
- deliverArchivedResourcesAfterDelay();
}
bool WebFrameLoaderClient::willUseArchive(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) const
{
- if (request.url() != originalURL)
- return false;
-
- WebResource *resource = [dataSource(core(m_webFrame.get())->loader()->activeDocumentLoader()) _archivedSubresourceForURL:originalURL];
- if (!resource)
- return false;
-
- m_pendingArchivedResources.set(loader, resource);
- // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
- deliverArchivedResourcesAfterDelay();
-
- return true;
+ return false;
}
bool WebFrameLoaderClient::isArchiveLoadPending(ResourceLoader* loader) const
{
- return m_pendingArchivedResources.contains(loader);
+ return false;
}
void WebFrameLoaderClient::cancelPendingArchiveLoad(ResourceLoader* loader)
{
- if (m_pendingArchivedResources.isEmpty())
- return;
- m_pendingArchivedResources.remove(loader);
- if (m_pendingArchivedResources.isEmpty())
- m_archivedResourcesDeliveryTimer.stop();
}
void WebFrameLoaderClient::clearArchivedResources()
{
- m_pendingArchivedResources.clear();
- m_archivedResourcesDeliveryTimer.stop();
}
bool WebFrameLoaderClient::canHandleRequest(const ResourceRequest& request) const
if ([newFrame _dataSource])
[[newFrame _dataSource] _documentLoader]->setOverrideEncoding([[m_webFrame.get() _dataSource] _documentLoader]->overrideEncoding());
- [m_webFrame.get() _loadURL:url referrer:referrer intoChild:newFrame];
+ core(m_webFrame.get())->loader()->loadURLIntoChildFrame(url, referrer, newCoreFrame.get());
// The frame's onload handler may have removed it from the document.
if (!newCoreFrame->tree()->parent())
*/
#import "WebArchive.h"
+#import "WebArchiveInternal.h"
#import "WebKitLogging.h"
+#import "WebResourceInternal.h"
#import "WebResourcePrivate.h"
#import "WebTypesInternal.h"
+#import <WebCore/ArchiveResource.h>
+#import <WebCore/LegacyWebArchive.h>
+#import <WebCore/WebCoreObjCExtras.h>
+
+using namespace WebCore;
+
NSString *WebArchivePboardType = @"Apple Web Archive pasteboard type";
static NSString * const WebMainResourceKey = @"WebMainResource";
@interface WebArchivePrivate : NSObject
{
- @public
- WebResource *mainResource;
- NSArray *subresources;
- NSArray *subframeArchives;
+@public
+ WebResource *cachedMainResource;
+ NSArray *cachedSubresources;
+ NSArray *cachedSubframeArchives;
+@private
+ LegacyWebArchive* coreArchive;
}
+
+- (id)initWithCoreArchive:(PassRefPtr<LegacyWebArchive>)coreArchive;
+- (LegacyWebArchive*)coreArchive;
+- (void)setCoreArchive:(PassRefPtr<LegacyWebArchive>)newCoreArchive;
@end
@implementation WebArchivePrivate
+#ifndef BUILDING_ON_TIGER
++ (void)initialize
+{
+ WebCoreObjCFinalizeOnMainThread(self);
+}
+#endif
+
+- (id)init
+{
+ self = [super init];
+ if (self)
+ coreArchive = LegacyWebArchive::create().releaseRef();
+ return self;
+}
+
+- (id)initWithCoreArchive:(PassRefPtr<LegacyWebArchive>)_coreArchive
+{
+ self = [super init];
+ if (!self || !_coreArchive) {
+ [self release];
+ return nil;
+ }
+
+ coreArchive = _coreArchive.releaseRef();
+
+ return self;
+}
+
+- (LegacyWebArchive*)coreArchive
+{
+ return coreArchive;
+}
+
+- (void)setCoreArchive:(PassRefPtr<LegacyWebArchive>)newCoreArchive
+{
+ ASSERT(coreArchive);
+ ASSERT(newCoreArchive);
+ coreArchive = newCoreArchive.releaseRef();
+}
+
- (void)dealloc
{
- [mainResource release];
- [subresources release];
- [subframeArchives release];
+ ASSERT(coreArchive);
+ coreArchive->deref();
+ coreArchive = 0;
+
+ [cachedMainResource release];
+ [cachedSubresources release];
+ [cachedSubframeArchives release];
+
[super dealloc];
}
+- (void)finalize
+{
+ ASSERT(coreArchive);
+ coreArchive->deref();
+ coreArchive = 0;
+
+ [super finalize];
+}
+
@end
+@implementation WebArchive
+
+- (id)init
+{
+ self = [super init];
+ if (!self)
+ return nil;
+ _private = [[WebArchivePrivate alloc] init];
+ return self;
+}
+
static BOOL isArrayOfClass(id object, Class elementClass)
{
if (![object isKindOfClass:[NSArray class]])
return YES;
}
-@implementation WebArchive
-
-- (id)init
+- (id)initWithMainResource:(WebResource *)mainResource subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
{
self = [super init];
if (!self)
return nil;
+
_private = [[WebArchivePrivate alloc] init];
- return self;
-}
-- (id)initWithMainResource:(WebResource *)mainResource subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
-{
- self = [self init];
- if (!self)
+ _private->cachedMainResource = [mainResource retain];
+ if (!_private->cachedMainResource) {
+ [self release];
return nil;
+ }
- _private->mainResource = [mainResource retain];
- _private->subresources = [subresources retain];
- _private->subframeArchives = [subframeArchives retain];
-
- if (!_private->mainResource) {
+ if (!subresources || isArrayOfClass(subresources, [WebResource class]))
+ _private->cachedSubresources = [subresources retain];
+ else {
[self release];
return nil;
}
-
- return self;
-}
-- (id)_initWithPropertyList:(id)propertyList
-{
- self = [self init];
- if (!self)
- return nil;
-
- if (![propertyList isKindOfClass:[NSDictionary class]]) {
+ if (!subframeArchives || isArrayOfClass(subframeArchives, [WebArchive class]))
+ _private->cachedSubframeArchives = [subframeArchives retain];
+ else {
[self release];
return nil;
}
- _private->mainResource = [[WebResource alloc] _initWithPropertyList:[propertyList objectForKey:WebMainResourceKey]];
- if (!_private->mainResource) {
+ RefPtr<ArchiveResource> coreMainResource = mainResource ? [mainResource _coreResource] : 0;
+
+ Vector<PassRefPtr<ArchiveResource> > coreResources;
+ NSEnumerator *enumerator = [subresources objectEnumerator];
+ WebResource *subresource;
+ while ((subresource = [enumerator nextObject]) != nil)
+ coreResources.append([subresource _coreResource]);
+
+ Vector<PassRefPtr<LegacyWebArchive> > coreArchives;
+ enumerator = [subframeArchives objectEnumerator];
+ WebArchive *subframeArchive;
+ while ((subframeArchive = [enumerator nextObject]) != nil)
+ coreArchives.append([subframeArchive->_private coreArchive]);
+
+ [_private setCoreArchive:LegacyWebArchive::create(coreMainResource.release(), coreResources, coreArchives)];
+ if (![_private coreArchive]) {
[self release];
return nil;
}
-
- _private->subresources = [[WebResource _resourcesFromPropertyLists:[propertyList objectForKey:WebSubresourcesKey]] retain];
-
- NSEnumerator *enumerator = [[propertyList objectForKey:WebSubframeArchivesKey] objectEnumerator];
- NSMutableArray *subframeArchives = [[NSMutableArray alloc] init];
- NSDictionary *archivePropertyList;
- while ((archivePropertyList = [enumerator nextObject]) != nil) {
- WebArchive *archive = [[WebArchive alloc] _initWithPropertyList:archivePropertyList];
- if (archive) {
- [subframeArchives addObject:archive];
- [archive release];
- }
- }
- _private->subframeArchives = subframeArchives;
return self;
}
- (id)initWithData:(NSData *)data
{
+ self = [super init];
+ if (!self)
+ return nil;
+
#if !LOG_DISABLED
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
#endif
- NSDictionary *propertyList = [NSPropertyListSerialization propertyListFromData:data
- mutabilityOption:NSPropertyListImmutable
- format:nil
- errorDescription:nil];
+
+ _private = [[WebArchivePrivate alloc] init];
+ [_private setCoreArchive:LegacyWebArchive::create(SharedBuffer::wrapNSData(data).get())];
+
#if !LOG_DISABLED
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime duration = end - start;
#endif
LOG(Timing, "Parsing web archive with [NSPropertyListSerialization propertyListFromData::::] took %f seconds", duration);
- return [self _initWithPropertyList:propertyList];
+ return self;
}
- (id)initWithCoder:(NSCoder *)decoder
{
- self = [self init];
- if (!self)
- return nil;
-
+ WebResource *mainResource = nil;
+ NSArray *subresources = nil;
+ NSArray *subframeArchives = nil;
+
@try {
id object = [decoder decodeObjectForKey:WebMainResourceKey];
if ([object isKindOfClass:[WebResource class]])
- _private->mainResource = [object retain];
+ mainResource = [object retain];
object = [decoder decodeObjectForKey:WebSubresourcesKey];
if (isArrayOfClass(object, [WebResource class]))
- _private->subresources = [object retain];
+ subresources = [object retain];
object = [decoder decodeObjectForKey:WebSubframeArchivesKey];
if (isArrayOfClass(object, [WebArchive class]))
- _private->subframeArchives = [object retain];
+ subframeArchives = [object retain];
} @catch(id) {
[self release];
return nil;
}
- if (!_private->mainResource) {
- [self release];
- return nil;
- }
-
- return self;
+ return [self initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives];
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
- [encoder encodeObject:_private->mainResource forKey:WebMainResourceKey];
- [encoder encodeObject:_private->subresources forKey:WebSubresourcesKey];
- [encoder encodeObject:_private->subframeArchives forKey:WebSubframeArchivesKey];
+ [encoder encodeObject:[self mainResource] forKey:WebMainResourceKey];
+ [encoder encodeObject:[self subresources] forKey:WebSubresourcesKey];
+ [encoder encodeObject:[self subframeArchives] forKey:WebSubframeArchivesKey];
}
- (void)dealloc
- (WebResource *)mainResource
{
- return [[_private->mainResource retain] autorelease];
+ // Currently from WebKit API perspective, WebArchives are entirely immutable once created
+ // If they ever become mutable, we'll need to rethink this.
+ if (!_private->cachedMainResource) {
+ LegacyWebArchive* coreArchive = [_private coreArchive];
+ if (coreArchive)
+ _private->cachedMainResource = [[WebResource alloc] _initWithCoreResource:coreArchive->mainResource()];
+ }
+
+ return [[_private->cachedMainResource retain] autorelease];
}
- (NSArray *)subresources
{
- return [[_private->subresources retain] autorelease];
+ // Currently from WebKit API perspective, WebArchives are entirely immutable once created
+ // If they ever become mutable, we'll need to rethink this.
+ if (!_private->cachedSubresources) {
+ LegacyWebArchive* coreArchive = [_private coreArchive];
+ if (!coreArchive)
+ _private->cachedSubresources = [[NSArray alloc] init];
+ else {
+ const Vector<RefPtr<ArchiveResource> >& subresources(coreArchive->subresources());
+ NSMutableArray *mutableArray = _private->cachedSubresources = [[NSMutableArray alloc] initWithCapacity:subresources.size()];
+ for (unsigned i = 0; i < subresources.size(); ++i) {
+ WebResource *resource = [[WebResource alloc] _initWithCoreResource:subresources[i].get()];
+ [mutableArray addObject:resource];
+ [resource release];
+ }
+ }
+ }
+
+ return [[_private->cachedSubresources retain] autorelease];
}
- (NSArray *)subframeArchives
{
- return [[_private->subframeArchives retain] autorelease];
-}
-
-- (NSDictionary *)_propertyListRepresentation
-{
- NSMutableDictionary *propertyList = [NSMutableDictionary dictionary];
- if (_private->mainResource) {
- [propertyList setObject:[_private->mainResource _propertyListRepresentation] forKey:WebMainResourceKey];
- }
- NSArray *propertyLists = [WebResource _propertyListsFromResources:_private->subresources];
- if ([propertyLists count] > 0) {
- [propertyList setObject:propertyLists forKey:WebSubresourcesKey];
- }
- NSEnumerator *enumerator = [_private->subframeArchives objectEnumerator];
- NSMutableArray *subarchivePropertyLists = [[NSMutableArray alloc] init];
- WebArchive *archive;
- while ((archive = [enumerator nextObject]) != nil) {
- [subarchivePropertyLists addObject:[archive _propertyListRepresentation]];
- }
- if ([subarchivePropertyLists count] > 0) {
- [propertyList setObject:subarchivePropertyLists forKey:WebSubframeArchivesKey];
+ // Currently from WebKit API perspective, WebArchives are entirely immutable once created
+ // If they ever become mutable, we'll need to rethink this.
+ if (!_private->cachedSubframeArchives) {
+ LegacyWebArchive* coreArchive = [_private coreArchive];
+ if (!coreArchive)
+ _private->cachedSubframeArchives = [[NSArray alloc] init];
+ else {
+ const Vector<RefPtr<Archive> >& subframeArchives(coreArchive->subframeArchives());
+ NSMutableArray *mutableArray = _private->cachedSubframeArchives = [[NSMutableArray alloc] initWithCapacity:subframeArchives.size()];
+ for (unsigned i = 0; i < subframeArchives.size(); ++i) {
+ WebArchive *archive = [[WebArchive alloc] _initWithCoreLegacyWebArchive:(LegacyWebArchive *)subframeArchives[i].get()];
+ [mutableArray addObject:archive];
+ [archive release];
+ }
+ }
}
- [subarchivePropertyLists release];
- return propertyList;
+
+ return [[_private->cachedSubframeArchives retain] autorelease];
}
- (NSData *)data
{
- NSDictionary *propertyList = [self _propertyListRepresentation];
#if !LOG_DISABLED
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
#endif
- NSData *data = [NSPropertyListSerialization dataFromPropertyList:propertyList format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil];
+
+ RetainPtr<CFDataRef> data = [_private coreArchive]->rawDataRepresentation();
+
#if !LOG_DISABLED
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime duration = end - start;
#endif
- LOG(Timing, "Serializing web archive with [NSPropertyListSerialization dataFromPropertyList:::] took %f seconds", duration);
- return data;
+ LOG(Timing, "Serializing web archive to raw CFPropertyList data took %f seconds", duration);
+
+ return [[(NSData *)data.get() retain] autorelease];
+}
+
+@end
+
+@implementation WebArchive (WebInternal)
+
+- (id)_initWithCoreLegacyWebArchive:(PassRefPtr<WebCore::LegacyWebArchive>)coreLegacyWebArchive
+{
+ self = [super init];
+ if (!self)
+ return nil;
+
+ _private = [[WebArchivePrivate alloc] initWithCoreArchive:coreLegacyWebArchive];
+ if (!_private) {
+ [self release];
+ return nil;
+ }
+
+ return self;
+}
+
+- (WebCore::LegacyWebArchive *)_coreLegacyWebArchive
+{
+ return [_private coreArchive];
}
@end
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 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.
+ * 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.
+ * 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.
+ * 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
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import <Foundation/Foundation.h>
+#import "WebArchive.h"
+#import <JavaScriptCore/Forward.h>
-@class WebArchive;
-@class WebResource;
-
-@interface WebUnarchivingState : NSObject
-{
- NSMutableDictionary *archivedSubframes;
- NSMutableDictionary *archivedResources;
+namespace WebCore {
+ class LegacyWebArchive;
}
-- (void)addArchive:(WebArchive *)archive;
-- (void)addResource:(WebResource *)resource;
-- (WebResource *)archivedResourceForURL:(NSURL *)URL;
-- (WebArchive *)popSubframeArchiveWithFrameName:(NSString *)frameName;
+@interface WebArchive (WebInternal)
+
+- (id)_initWithCoreLegacyWebArchive:(WTF::PassRefPtr<WebCore::LegacyWebArchive>)coreLegacyWebArchive;
+- (WebCore::LegacyWebArchive *)_coreLegacyWebArchive;
@end
#import "WebDataSource.h"
#import "WebArchive.h"
+#import "WebArchiveInternal.h"
#import "WebArchiver.h"
#import "WebDataSourceInternal.h"
#import "WebDocument.h"
#import "WebNSURLExtras.h"
#import "WebNSURLRequestExtras.h"
#import "WebPDFRepresentation.h"
+#import "WebResourceInternal.h"
#import "WebResourceLoadDelegate.h"
#import "WebResourcePrivate.h"
-#import "WebUnarchivingState.h"
#import "WebViewInternal.h"
#import <JavaScriptCore/Assertions.h>
#import <WebCore/FrameLoader.h>
#import <WebCore/KURL.h>
+#import <WebCore/LegacyWebArchive.h>
#import <WebCore/MIMETypeRegistry.h>
#import <WebCore/ResourceRequest.h>
#import <WebCore/SharedBuffer.h>
id <WebDocumentRepresentation> representation;
- WebUnarchivingState *unarchivingState;
BOOL representationFinishedLoading;
}
@end
loader->deref();
[representation release];
- [unarchivingState release];
[super dealloc];
}
- (void)_addSubframeArchives:(NSArray *)subframeArchives
{
+ // FIXME: This SPI is poor, poor design. Can we come up with another solution for those who need it?
+ DocumentLoader* loader = [self _documentLoader];
+ ASSERT(loader);
+
NSEnumerator *enumerator = [subframeArchives objectEnumerator];
WebArchive *archive;
while ((archive = [enumerator nextObject]) != nil)
- [self _addToUnarchiveState:archive];
+ loader->addAllArchiveResources([archive _coreLegacyWebArchive]);
}
- (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL
}
}
-- (void)_clearUnarchivingState
-{
- [_private->unarchivingState release];
- _private->unarchivingState = nil;
-}
-
- (void)_revertToProvisionalState
{
[self _setRepresentation:nil];
return repTypes;
}
-- (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
-{
- return [_private->unarchivingState archivedResourceForURL:URL];
-}
-
- (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement
{
DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive];
[[self webFrame] _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO];
}
+// FIXME: There are few reasons why this method and many of its related methods can't be pushed entirely into WebCore in the future.
- (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive
{
ASSERT(archive);
if ([WebView canShowMIMETypeAsHTML:MIMEType]) {
NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding];
// FIXME: seems poor form to do this as a side effect of getting a document fragment
- [self _addToUnarchiveState:archive];
+ if (DocumentLoader* loader = [self _documentLoader])
+ loader->addAllArchiveResources([archive _coreLegacyWebArchive]);
+
DOMDocumentFragment *fragment = [[self webFrame] _documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]];
[markupString release];
return fragment;
return url;
}
-- (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
-{
- return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName];
-}
-
- (WebView *)_webView
{
return [[self webFrame] webView];
[_private->representation setDataSource:self];
}
-- (void)_addToUnarchiveState:(WebArchive *)archive
-{
- if (!_private->unarchivingState)
- _private->unarchivingState = [[WebUnarchivingState alloc] init];
- [_private->unarchivingState addArchive:archive];
-}
-
- (DocumentLoader*)_documentLoader
{
return _private->loader;
NSData *data;
NSURLResponse *response;
- if (![[self webFrame] _getData:&data andResponse:&response forURL:[URL _web_originalDataAsString]])
- return [self _archivedSubresourceForURL:URL];
+ if (![[self webFrame] _getData:&data andResponse:&response forURL:[URL _web_originalDataAsString]]) {
+ DocumentLoader* loader = [self _documentLoader];
+ ArchiveResource* coreResource = loader->archiveResourceForURL(URL);
+ return coreResource ? [[[WebResource alloc] _initWithCoreResource:coreResource] autorelease] : nil;
+ }
return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease];
}
- (void)addSubresource:(WebResource *)subresource
-{
- if (subresource) {
- if (!_private->unarchivingState)
- _private->unarchivingState = [[WebUnarchivingState alloc] init];
- [_private->unarchivingState addResource:subresource];
- }
+{
+ _private->loader->addArchiveResource([subresource _coreResource]);
}
@end
@protocol WebDocumentRepresentation;
@interface WebDataSource (WebInternal)
-- (void)_addToUnarchiveState:(WebArchive *)archive;
- (void)_makeRepresentation;
- (BOOL)_isDocumentHTML;
- (WebView *)_webView;
-- (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName;
- (NSURL *)_URL;
- (DOMElement *)_imageElementWithImageResource:(WebResource *)resource;
- (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource;
- (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive;
+ (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission;
- (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement;
-- (WebResource *)_archivedSubresourceForURL:(NSURL *)URL;
- (id)_initWithDocumentLoader:(WebDocumentLoaderMac*)loader;
- (void)_finishedLoading;
- (void)_receivedData:(NSData *)data;
- (void)_revertToProvisionalState;
- (void)_setMainDocumentError:(NSError *)error;
-- (void)_clearUnarchivingState;
- (WebCoreDocumentLoader*)_documentLoader;
@end
#import "DOMHTMLElementInternal.h"
#import "DOMNodeInternal.h"
#import "DOMRangeInternal.h"
+#import "WebArchiveInternal.h"
#import "WebChromeClient.h"
#import "WebDataSourceInternal.h"
#import "WebDocumentLoaderMac.h"
#import <WebCore/HTMLFrameOwnerElement.h>
#import <WebCore/HistoryItem.h>
#import <WebCore/HitTestResult.h>
+#import <WebCore/LegacyWebArchive.h>
#import <WebCore/Page.h>
#import <WebCore/PluginData.h>
#import <WebCore/RenderView.h>
return [self _createFrameWithPage:ownerElement->document()->frame()->page() frameName:name frameView:frameView ownerElement:ownerElement];
}
-/*
- In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
- The item that was the target of the user's navigation is designated as the "targetItem".
- When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
- which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
-*/
-
-- (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
-{
- ASSERT(childFrame);
- HistoryItem* parentItem = _private->coreFrame->loader()->currentHistoryItem();
- FrameLoadType loadType = _private->coreFrame->loader()->loadType();
- FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory;
-
- // If we're moving in the backforward list, we might want to replace the content
- // of this child frame with whatever was there at that point.
- // Reload will maintain the frame contents, LoadSame will not.
- if (parentItem && parentItem->children().size() &&
- (isBackForwardLoadType(loadType)
- || loadType == FrameLoadTypeReloadAllowingStaleData))
- {
- HistoryItem* childItem = parentItem->childItemWithName([childFrame name]);
- if (childItem) {
- // Use the original URL to ensure we get all the side-effects, such as
- // onLoad handlers, of any redirects that happened. An example of where
- // this is needed is Radar 3213556.
- URL = [NSURL _web_URLWithDataAsString:childItem->originalURLString()];
- // These behaviors implied by these loadTypes should apply to the child frames
- childLoadType = loadType;
-
- if (isBackForwardLoadType(loadType)) {
- // For back/forward, remember this item so we can traverse any child items as child frames load
- childFrame->_private->coreFrame->loader()->setProvisionalHistoryItem(childItem);
- } else {
- // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
- childFrame->_private->coreFrame->loader()->setCurrentHistoryItem(childItem);
- }
- }
- }
-
- WebArchive *archive = [[self _dataSource] _popSubframeArchiveWithName:[childFrame name]];
- if (archive)
- [childFrame loadArchive:archive];
- else
- childFrame->_private->coreFrame->loader()->load([URL absoluteURL], referrer, childLoadType, String(), 0, 0);
-}
-
- (void)_attachScriptDebugger
{
if (_private->scriptDebugger)
- (void)loadArchive:(WebArchive *)archive
{
- WebResource *mainResource = [archive mainResource];
- if (mainResource) {
- SubstituteData substituteData(WebCore::SharedBuffer::wrapNSData([mainResource data]), [mainResource MIMEType], [mainResource textEncodingName], KURL());
- ResourceRequest request([mainResource URL]);
-
- // hack because Mail checks for this property to detect data / archive loads
- [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)request.nsURLRequest()];
-
- RefPtr<DocumentLoader> documentLoader = _private->coreFrame->loader()->client()->createDocumentLoader(request, substituteData);
-
- [dataSource(documentLoader.get()) _addToUnarchiveState:archive];
-
- _private->coreFrame->loader()->load(documentLoader.get());
- }
+ if (LegacyWebArchive* coreArchive = [archive _coreLegacyWebArchive])
+ _private->coreFrame->loader()->loadArchive(coreArchive);
}
- (void)stopLoading
- (WebFrame *)_findFrameWithSelection;
- (void)_clearSelectionInOtherFrames;
-- (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame;
-
- (void)_attachScriptDebugger;
- (void)_detachScriptDebugger;
}
}
-- (void)_loadDataSourceAsWebArchive
-{
- WebArchive *archive = [[WebArchive alloc] initWithData:[_private->dataSource data]];
- WebResource *mainResource = [archive mainResource];
- if (!mainResource) {
- [archive release];
- return;
- }
-
- NSData *data = [mainResource data];
- [data retain];
- [_private->parsedArchiveData release];
- _private->parsedArchiveData = data;
-
- [_private->dataSource _addToUnarchiveState:archive];
- [archive release];
-
- WebFrame *webFrame = [_private->dataSource webFrame];
-
- if (!webFrame)
- return;
-
- core(webFrame)->loader()->continueLoadWithData(SharedBuffer::wrapNSData(data).get(), [mainResource MIMEType], [mainResource textEncodingName], [mainResource URL]);
-}
-
- (void)finishedLoadingWithDataSource:(WebDataSource *)dataSource
{
WebFrame *frame = [dataSource webFrame];
}
if (frame) {
- if ([self _isDisplayingWebArchive])
- [self _loadDataSourceAsWebArchive];
- else {
+ if (![self _isDisplayingWebArchive]) {
// Telling the frame we received some data and passing nil as the data is our
// way to get work done that is normally done when the first bit of data is
// received, even for the case of a document with no data (like about:blank).
#import "WebFrameInternal.h"
#import "WebNSDictionaryExtras.h"
#import "WebNSURLExtras.h"
+
+#import <WebCore/ArchiveResource.h>
+#import <WebCore/LegacyWebArchive.h>
#import <WebCore/TextEncoding.h>
+#import <WebCore/WebCoreObjCExtras.h>
#import <WebCore/WebCoreURLResponse.h>
+#import <wtf/PassRefPtr.h>
+
using namespace WebCore;
static NSString * const WebResourceDataKey = @"WebResourceData";
@interface WebResourcePrivate : NSObject
{
@public
- NSData *data;
- NSURL *URL;
- NSString *frameName;
- NSString *MIMEType;
- NSString *textEncodingName;
- NSURLResponse *response;
- BOOL shouldIgnoreWhenUnarchiving;
+ ArchiveResource* coreResource;
}
+
+- (id)initWithCoreResource:(PassRefPtr<ArchiveResource>)coreResource;
@end
@implementation WebResourcePrivate
+#ifndef BUILDING_ON_TIGER
++ (void)initialize
+{
+ WebCoreObjCFinalizeOnMainThread(self);
+}
+#endif
+
+- (id)init
+{
+ return [super init];
+}
+
+- (id)initWithCoreResource:(PassRefPtr<ArchiveResource>)passedResource
+{
+ self = [super init];
+ if (!self)
+ return self;
+
+ // Acquire the PassRefPtr<>'s ref as our own manual ref
+ coreResource = passedResource.releaseRef();
+
+ return self;
+}
+
- (void)dealloc
{
- [data release];
- [URL release];
- [frameName release];
- [MIMEType release];
- [textEncodingName release];
- [response release];
+ if (coreResource)
+ coreResource->deref();
[super dealloc];
}
+- (void)finalize
+{
+ if (coreResource)
+ coreResource->deref();
+ [super finalize];
+}
+
@end
@implementation WebResource
- (id)initWithCoder:(NSCoder *)decoder
{
- self = [self init];
+ self = [super init];
if (!self)
return nil;
+ NSData *data = nil;
+ NSURL *url = nil;
+ NSString *mimeType = nil, *textEncoding = nil, *frameName = nil;
+ NSURLResponse *response = nil;
+
@try {
id object = [decoder decodeObjectForKey:WebResourceDataKey];
if ([object isKindOfClass:[NSData class]])
- _private->data = [object retain];
+ data = object;
object = [decoder decodeObjectForKey:WebResourceURLKey];
if ([object isKindOfClass:[NSURL class]])
- _private->URL = [object retain];
+ url = object;
object = [decoder decodeObjectForKey:WebResourceMIMETypeKey];
if ([object isKindOfClass:[NSString class]])
- _private->MIMEType = [object retain];
+ mimeType = object;
object = [decoder decodeObjectForKey:WebResourceTextEncodingNameKey];
if ([object isKindOfClass:[NSString class]])
- _private->textEncodingName = [object retain];
+ textEncoding = object;
object = [decoder decodeObjectForKey:WebResourceFrameNameKey];
if ([object isKindOfClass:[NSString class]])
- _private->frameName = [object retain];
+ frameName = object;
object = [decoder decodeObjectForKey:WebResourceResponseKey];
if ([object isKindOfClass:[NSURLResponse class]])
- _private->response = [object retain];
+ response = object;
} @catch(id) {
[self release];
return nil;
}
+ _private = [[WebResourcePrivate alloc] initWithCoreResource:ArchiveResource::create(SharedBuffer::wrapNSData(data), url, mimeType, textEncoding, frameName, response)];
+
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
- [encoder encodeObject:_private->data forKey:WebResourceDataKey];
- [encoder encodeObject:_private->URL forKey:WebResourceURLKey];
- [encoder encodeObject:_private->MIMEType forKey:WebResourceMIMETypeKey];
- [encoder encodeObject:_private->textEncodingName forKey:WebResourceTextEncodingNameKey];
- [encoder encodeObject:_private->frameName forKey:WebResourceFrameNameKey];
- [encoder encodeObject:_private->response forKey:WebResourceResponseKey];
+ ArchiveResource *resource = _private->coreResource;
+
+ NSData *data = nil;
+ NSURL *url = nil;
+ NSString *mimeType = nil, *textEncoding = nil, *frameName = nil;
+ NSURLResponse *response = nil;
+
+ if (resource) {
+ if (resource->data())
+ data = [resource->data()->createNSData() autorelease];
+ url = resource->url();
+ mimeType = resource->mimeType();
+ textEncoding = resource->textEncoding();
+ frameName = resource->frameName();
+ response = resource->response().nsURLResponse();
+ }
+ [encoder encodeObject:data forKey:WebResourceDataKey];
+ [encoder encodeObject:url forKey:WebResourceURLKey];
+ [encoder encodeObject:mimeType forKey:WebResourceMIMETypeKey];
+ [encoder encodeObject:textEncoding forKey:WebResourceTextEncodingNameKey];
+ [encoder encodeObject:frameName forKey:WebResourceFrameNameKey];
+ [encoder encodeObject:response forKey:WebResourceResponseKey];
}
- (void)dealloc
- (NSData *)data
{
- return _private->data;
+ return _private->coreResource ? [_private->coreResource->data()->createNSData() autorelease] : 0;
}
- (NSURL *)URL
{
- return _private->URL;
+ return _private->coreResource ? (NSURL *)_private->coreResource->url() : 0;
}
- (NSString *)MIMEType
{
- return _private->MIMEType;
+ return _private->coreResource ? (NSString *)_private->coreResource->mimeType() : 0;
}
- (NSString *)textEncodingName
{
- return _private->textEncodingName;
+ return _private->coreResource ? (NSString *)_private->coreResource->textEncoding() : 0;
}
- (NSString *)frameName
{
- return _private->frameName;
+ return _private->coreResource ? (NSString *)_private->coreResource->frameName() : 0;
}
- (id)description
@end
-@implementation WebResource (WebResourcePrivate)
+@implementation WebResource (WebResourceInternal)
-// SPI for Mail (5066325)
-- (void)_ignoreWhenUnarchiving
+- (id)_initWithCoreResource:(WebCore::ArchiveResource *)coreResource
{
- _private->shouldIgnoreWhenUnarchiving = YES;
+ self = [super init];
+ if (!self)
+ return nil;
+
+ _private = [[WebResourcePrivate alloc] initWithCoreResource:coreResource];
+
+ return self;
}
-- (BOOL)_shouldIgnoreWhenUnarchiving
+- (WebCore::ArchiveResource *)_coreResource
{
- return _private->shouldIgnoreWhenUnarchiving;
+ return _private->coreResource;
}
-+ (NSArray *)_resourcesFromPropertyLists:(NSArray *)propertyLists
-{
- if (![propertyLists isKindOfClass:[NSArray class]]) {
- return nil;
- }
- NSEnumerator *enumerator = [propertyLists objectEnumerator];
- NSMutableArray *resources = [NSMutableArray array];
- NSDictionary *propertyList;
- while ((propertyList = [enumerator nextObject]) != nil) {
- WebResource *resource = [[WebResource alloc] _initWithPropertyList:propertyList];
- if (resource) {
- [resources addObject:resource];
- [resource release];
- }
- }
- return resources;
-}
+@end
+
+@implementation WebResource (WebResourcePrivate)
-+ (NSArray *)_propertyListsFromResources:(NSArray *)resources
+// SPI for Mail (5066325)
+// FIXME: This "ignoreWhenUnarchiving" concept is an ugly one - can we find a cleaner solution for those who need this SPI?
+- (void)_ignoreWhenUnarchiving
{
- NSEnumerator *enumerator = [resources objectEnumerator];
- NSMutableArray *propertyLists = [NSMutableArray array];
- WebResource *resource;
- while ((resource = [enumerator nextObject]) != nil) {
- [propertyLists addObject:[resource _propertyListRepresentation]];
- }
- return propertyLists;
+ if (_private->coreResource)
+ _private->coreResource->ignoreWhenUnarchiving();
}
- (id)_initWithData:(NSData *)data
response:(NSURLResponse *)response
copyData:(BOOL)copyData
{
- [self init];
-
- if (!data) {
- [self release];
- return nil;
- }
- _private->data = copyData ? [data copy] : [data retain];
-
- if (!URL) {
- [self release];
+ self = [super init];
+ if (!self)
return nil;
- }
- _private->URL = [URL copy];
- if (!MIMEType) {
+ if (!data || !URL || !MIMEType) {
[self release];
return nil;
}
- _private->MIMEType = [MIMEType copy];
-
- _private->textEncodingName = [textEncodingName copy];
- _private->frameName = [frameName copy];
- _private->response = [response retain];
-
+
+ _private = [[WebResourcePrivate alloc] initWithCoreResource:ArchiveResource::create(SharedBuffer::wrapNSData(copyData ? [[data copy] autorelease] : data), URL, MIMEType, textEncodingName, frameName, response)];
+
return self;
}
copyData:NO];
}
-- (id)_initWithPropertyList:(id)propertyList
+- (NSFileWrapper *)_fileWrapperRepresentation
{
- if (![propertyList isKindOfClass:[NSDictionary class]]) {
- [self release];
- return nil;
- }
+ SharedBuffer* coreData = _private->coreResource ? _private->coreResource->data() : 0;
+ NSData *data = coreData ? [coreData->createNSData() autorelease] : nil;
- NSURLResponse *response = nil;
- NSData *responseData = [propertyList objectForKey:WebResourceResponseKey];
- if ([responseData isKindOfClass:[NSData class]]) {
- NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:responseData];
- @try {
- id responseObject = [unarchiver decodeObjectForKey:WebResourceResponseKey];
- if ([responseObject isKindOfClass:[NSURLResponse class]])
- response = responseObject;
- [unarchiver finishDecoding];
- } @catch(id) {
- response = nil;
- }
- [unarchiver release];
+ NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:data] autorelease];
+ NSString *preferredFilename = _private->coreResource ? (NSString *)_private->coreResource->response().suggestedFilename() : nil;
+ if (!preferredFilename || ![preferredFilename length]) {
+ NSURL *url = _private->coreResource ? (NSURL *)_private->coreResource->url() : nil;
+ NSString *mimeType = _private->coreResource ? (NSString *)_private->coreResource->mimeType() : nil;
+ preferredFilename = [url _webkit_suggestedFilenameWithMIMEType:mimeType];
}
-
- NSData *data = [propertyList objectForKey:WebResourceDataKey];
- NSString *URLString = [propertyList _webkit_stringForKey:WebResourceURLKey];
- return [self _initWithData:[data isKindOfClass:[NSData class]] ? data : nil
- URL:URLString ? [NSURL _web_URLWithDataAsString:URLString] : nil
- MIMEType:[propertyList _webkit_stringForKey:WebResourceMIMETypeKey]
- textEncodingName:[propertyList _webkit_stringForKey:WebResourceTextEncodingNameKey]
- frameName:[propertyList _webkit_stringForKey:WebResourceFrameNameKey]
- response:response
- copyData:NO];
-}
-
-- (NSFileWrapper *)_fileWrapperRepresentation
-{
- NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:_private->data] autorelease];
- NSString *preferredFilename = [_private->response suggestedFilename];
- if (!preferredFilename || ![preferredFilename length])
- preferredFilename = [_private->URL _webkit_suggestedFilenameWithMIMEType:_private->MIMEType];
+
[wrapper setPreferredFilename:preferredFilename];
return wrapper;
}
-- (id)_propertyListRepresentation
-{
- NSMutableDictionary *propertyList = [NSMutableDictionary dictionary];
- [propertyList setObject:_private->data forKey:WebResourceDataKey];
- [propertyList setObject:[_private->URL _web_originalDataAsString] forKey:WebResourceURLKey];
- [propertyList setObject:_private->MIMEType forKey:WebResourceMIMETypeKey];
- if (_private->textEncodingName != nil) {
- [propertyList setObject:_private->textEncodingName forKey:WebResourceTextEncodingNameKey];
- }
- if (_private->frameName != nil) {
- [propertyList setObject:_private->frameName forKey:WebResourceFrameNameKey];
- }
- if (_private->response != nil) {
- NSMutableData *responseData = [[NSMutableData alloc] init];
- NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:responseData];
- [archiver encodeObject:_private->response forKey:WebResourceResponseKey];
- [archiver finishEncoding];
- [archiver release];
- [propertyList setObject:responseData forKey:WebResourceResponseKey];
- [responseData release];
- }
- return propertyList;
-}
-
- (NSURLResponse *)_response
{
- if (_private->response != nil) {
- return _private->response;
- }
- return [[[NSURLResponse alloc] initWithURL:_private->URL
- MIMEType:_private->MIMEType
- expectedContentLength:[_private->data length]
- textEncodingName:_private->textEncodingName] autorelease];
+ NSURLResponse *response = nil;
+ if (_private->coreResource)
+ response = _private->coreResource->response().nsURLResponse();
+
+ return response ? response : [[[NSURLResponse alloc] init] autorelease];
}
- (NSString *)_stringValue
{
- WebCore::TextEncoding encoding(_private->textEncodingName);
+ WebCore::TextEncoding encoding(_private->coreResource ? (NSString *)_private->coreResource->textEncoding() : nil);
if (!encoding.isValid())
encoding = WindowsLatin1Encoding();
- return encoding.decode(reinterpret_cast<const char*>([_private->data bytes]), [_private->data length]);
+
+ SharedBuffer* coreData = _private->coreResource ? _private->coreResource->data() : 0;
+
+ return encoding.decode(reinterpret_cast<const char*>(coreData ? coreData->data() : 0), coreData ? coreData->size() : 0);
}
@end
--- /dev/null
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#import "WebResource.h"
+
+namespace WebCore {
+ class ArchiveResource;
+}
+
+@interface WebResource (WebResourceInternal)
+
+- (id)_initWithCoreResource:(WebCore::ArchiveResource *)coreResource;
+- (WebCore::ArchiveResource *)_coreResource;
+
+@end
- (id)_initWithData:(NSData *)data URL:(NSURL *)URL response:(NSURLResponse *)response;
-- (BOOL)_shouldIgnoreWhenUnarchiving;
- (void)_ignoreWhenUnarchiving;
-+ (NSArray *)_resourcesFromPropertyLists:(NSArray *)propertyLists;
-+ (NSArray *)_propertyListsFromResources:(NSArray *)resources;
-
-- (id)_initWithPropertyList:(id)propertyList;
-
- (NSFileWrapper *)_fileWrapperRepresentation;
-- (id)_propertyListRepresentation;
- (NSURLResponse *)_response;
- (NSString *)_stringValue;
+++ /dev/null
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
- *
- * 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.
- */
-
-#import "WebUnarchivingState.h"
-
-#import "WebArchive.h"
-#import <JavaScriptCore/Assertions.h>
-#import "WebResource.h"
-#import "WebResourcePrivate.h"
-#import "WebNSURLExtras.h"
-
-@implementation WebUnarchivingState
-
-- (id)init
-{
- if (!(self = [super init]))
- return nil;
-
- archivedSubframes = [[NSMutableDictionary alloc] init];
- archivedResources = [[NSMutableDictionary alloc] init];
-
- return self;
-}
-
-- (void)dealloc
-{
- [archivedSubframes release];
- [archivedResources release];
- [super dealloc];
-}
-
-- (void)addArchive:(WebArchive *)archive
-{
- NSEnumerator *enumerator = [[archive subresources] objectEnumerator];
- WebResource *subresource;
- while ((subresource = [enumerator nextObject]) != nil)
- [archivedResources setObject:subresource forKey:[[subresource URL] _web_originalDataAsString]];
-
- enumerator = [[archive subframeArchives] objectEnumerator];
- WebArchive *subframeArchive;
- while ((subframeArchive = [enumerator nextObject]) != nil) {
- NSString *frameName = [[subframeArchive mainResource] frameName];
- if (frameName)
- [archivedSubframes setObject:subframeArchive forKey:frameName];
- }
-}
-
-- (void)addResource:(WebResource *)subresource
-{
- [archivedResources setObject:subresource forKey:[[subresource URL] _web_originalDataAsString]];
-}
-
-- (WebResource *)archivedResourceForURL:(NSURL *)URL
-{
- WebResource *resource = [archivedResources objectForKey:[URL _web_originalDataAsString]];
- if ([resource _shouldIgnoreWhenUnarchiving])
- return nil;
- return resource;
-}
-
-- (WebArchive *)popSubframeArchiveWithFrameName:(NSString *)frameName
-{
- ASSERT(frameName != nil);
-
- WebArchive *archive = [[[archivedSubframes objectForKey:frameName] retain] autorelease];
- if (archive != nil)
- [archivedSubframes removeObjectForKey:frameName];
-
- return archive;
-}
-
-@end