summaryrefslogtreecommitdiffstats
path: root/WebCore/xml
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-05 14:34:32 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-05 14:34:32 -0800
commit635860845790a19bf50bbc51ba8fb66a96dde068 (patch)
treeef6ad9ff73a5b57f65249d4232a202fa77e6a140 /WebCore/xml
parent8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (diff)
downloadexternal_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.zip
external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.gz
external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.bz2
auto import from //depot/cupcake/@136594
Diffstat (limited to 'WebCore/xml')
-rw-r--r--WebCore/xml/XMLHttpRequest.cpp617
-rw-r--r--WebCore/xml/XMLHttpRequest.h60
-rw-r--r--WebCore/xml/XMLHttpRequest.idl2
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.cpp2
-rw-r--r--WebCore/xml/XMLSerializer.cpp3
-rw-r--r--WebCore/xml/XPathExpressionNode.cpp3
-rw-r--r--WebCore/xml/XPathGrammar.y4
-rw-r--r--WebCore/xml/XPathParser.cpp11
-rw-r--r--WebCore/xml/XPathPath.h2
-rw-r--r--WebCore/xml/XPathValue.cpp3
-rw-r--r--WebCore/xml/XSLImportRule.cpp2
-rw-r--r--WebCore/xml/XSLStyleSheet.cpp32
-rw-r--r--WebCore/xml/XSLStyleSheet.h3
-rw-r--r--WebCore/xml/XSLTExtensions.cpp1
-rw-r--r--WebCore/xml/XSLTProcessor.cpp16
-rw-r--r--WebCore/xml/XSLTUnicodeSort.cpp54
16 files changed, 464 insertions, 351 deletions
diff --git a/WebCore/xml/XMLHttpRequest.cpp b/WebCore/xml/XMLHttpRequest.cpp
index 67aba0b..f16755a 100644
--- a/WebCore/xml/XMLHttpRequest.cpp
+++ b/WebCore/xml/XMLHttpRequest.cpp
@@ -2,6 +2,7 @@
* Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
+ * Copyright (C) 2008 David Levin <levin@chromium.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,118 +23,126 @@
#include "XMLHttpRequest.h"
#include "CString.h"
-#include "Console.h"
#include "DOMImplementation.h"
-#include "DOMWindow.h"
+#include "Document.h"
#include "Event.h"
#include "EventException.h"
#include "EventListener.h"
#include "EventNames.h"
#include "File.h"
-#include "Frame.h"
-#include "FrameLoader.h"
#include "HTTPParsers.h"
-#include "InspectorController.h"
-#include "JSDOMBinding.h"
-#include "JSDOMWindow.h"
#include "KURL.h"
#include "KURLHash.h"
-#include "Page.h"
+#include "ResourceError.h"
+#include "ResourceRequest.h"
+#include "ScriptExecutionContext.h"
#include "Settings.h"
-#include "SubresourceLoader.h"
#include "SystemTime.h"
#include "TextResourceDecoder.h"
+#include "ThreadableLoader.h"
#include "XMLHttpRequestException.h"
#include "XMLHttpRequestProgressEvent.h"
#include "XMLHttpRequestUpload.h"
#include "markup.h"
-#include <runtime/JSLock.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Threading.h>
+
+#if USE(JSC)
+#include "JSDOMWindow.h"
+#endif
namespace WebCore {
-struct PreflightResultCacheItem {
- PreflightResultCacheItem(unsigned expiryDelta, bool credentials, HashSet<String>* methods, HashSet<String, CaseFoldingHash>* headers)
- : m_absoluteExpiryTime(currentTime() + expiryDelta)
+typedef HashSet<String, CaseFoldingHash> HeadersSet;
+
+struct XMLHttpRequestStaticData {
+ XMLHttpRequestStaticData();
+ String m_proxyHeaderPrefix;
+ String m_secHeaderPrefix;
+ HashSet<String, CaseFoldingHash> m_forbiddenRequestHeaders;
+ HashSet<String, CaseFoldingHash> m_allowedCrossSiteResponseHeaders;
+};
+
+XMLHttpRequestStaticData::XMLHttpRequestStaticData()
+ : m_proxyHeaderPrefix("proxy-")
+ , m_secHeaderPrefix("sec-")
+{
+ m_forbiddenRequestHeaders.add("accept-charset");
+ m_forbiddenRequestHeaders.add("accept-encoding");
+ m_forbiddenRequestHeaders.add("connection");
+ m_forbiddenRequestHeaders.add("content-length");
+ m_forbiddenRequestHeaders.add("content-transfer-encoding");
+ m_forbiddenRequestHeaders.add("date");
+ m_forbiddenRequestHeaders.add("expect");
+ m_forbiddenRequestHeaders.add("host");
+ m_forbiddenRequestHeaders.add("keep-alive");
+ m_forbiddenRequestHeaders.add("referer");
+ m_forbiddenRequestHeaders.add("te");
+ m_forbiddenRequestHeaders.add("trailer");
+ m_forbiddenRequestHeaders.add("transfer-encoding");
+ m_forbiddenRequestHeaders.add("upgrade");
+ m_forbiddenRequestHeaders.add("via");
+
+ m_allowedCrossSiteResponseHeaders.add("cache-control");
+ m_allowedCrossSiteResponseHeaders.add("content-language");
+ m_allowedCrossSiteResponseHeaders.add("content-type");
+ m_allowedCrossSiteResponseHeaders.add("expires");
+ m_allowedCrossSiteResponseHeaders.add("last-modified");
+ m_allowedCrossSiteResponseHeaders.add("pragma");
+}
+
+class PreflightResultCacheItem : Noncopyable {
+public:
+ PreflightResultCacheItem(bool credentials)
+ : m_absoluteExpiryTime(0)
, m_credentials(credentials)
- , m_methods(methods)
- , m_headers(headers)
{
}
+ bool parse(const ResourceResponse&);
+ bool allowsCrossSiteMethod(const String&) const;
+ bool allowsCrossSiteHeaders(const HTTPHeaderMap&) const;
+ bool allowsRequest(bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const;
+
+private:
+ template<class HashType>
+ static void addToAccessControlAllowList(const String& string, unsigned start, unsigned end, HashSet<String, HashType>&);
+ template<class HashType>
+ static bool parseAccessControlAllowList(const String& string, HashSet<String, HashType>&);
+ static bool parseAccessControlMaxAge(const String& string, unsigned& expiryDelta);
+
// FIXME: A better solution to holding onto the absolute expiration time might be
// to start a timer for the expiration delta, that removes this from the cache when
// it fires.
double m_absoluteExpiryTime;
bool m_credentials;
- OwnPtr<HashSet<String> > m_methods;
- OwnPtr<HashSet<String, CaseFoldingHash> > m_headers;
+ HashSet<String> m_methods;
+ HeadersSet m_headers;
};
-typedef HashMap<std::pair<String, KURL>, PreflightResultCacheItem*> PreflightResultCache;
+class PreflightResultCache : Noncopyable {
+public:
+ static PreflightResultCache& shared();
-static PreflightResultCache& preflightResultCache()
-{
- static PreflightResultCache cache;
- return cache;
-}
+ void appendEntry(const String& origin, const KURL&, PreflightResultCacheItem*);
+ bool canSkipPreflight(const String& origin, const KURL&, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders);
-static void appendPreflightResultCacheEntry(String origin, KURL url, unsigned expiryDelta,
- bool credentials, HashSet<String>* methods, HashSet<String, CaseFoldingHash>* headers)
-{
- ASSERT(!preflightResultCache().contains(std::make_pair(origin, url)));
+private:
+ PreflightResultCache() { }
- PreflightResultCacheItem* item = new PreflightResultCacheItem(expiryDelta, credentials, methods, headers);
- preflightResultCache().set(std::make_pair(origin, url), item);
-}
+ typedef HashMap<std::pair<String, KURL>, PreflightResultCacheItem*> PreflightResultHashMap;
-static bool isSafeRequestHeader(const String& name)
-{
- static HashSet<String, CaseFoldingHash> forbiddenHeaders;
- static String proxyString("proxy-");
- static String secString("sec-");
-
- if (forbiddenHeaders.isEmpty()) {
- forbiddenHeaders.add("accept-charset");
- forbiddenHeaders.add("accept-encoding");
- forbiddenHeaders.add("connection");
- forbiddenHeaders.add("content-length");
- forbiddenHeaders.add("content-transfer-encoding");
- forbiddenHeaders.add("date");
- forbiddenHeaders.add("expect");
- forbiddenHeaders.add("host");
- forbiddenHeaders.add("keep-alive");
- forbiddenHeaders.add("referer");
- forbiddenHeaders.add("te");
- forbiddenHeaders.add("trailer");
- forbiddenHeaders.add("transfer-encoding");
- forbiddenHeaders.add("upgrade");
- forbiddenHeaders.add("via");
- }
-
- return !forbiddenHeaders.contains(name) && !name.startsWith(proxyString, false) &&
- !name.startsWith(secString, false);
-}
+ PreflightResultHashMap m_preflightHashMap;
+ Mutex m_mutex;
+};
static bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name)
{
return equalIgnoringCase(name, "accept") || equalIgnoringCase(name, "accept-language") || equalIgnoringCase(name, "content-type");
}
-static bool isOnAccessControlResponseHeaderWhitelist(const String& name)
-{
- static HashSet<String, CaseFoldingHash> allowedHeaders;
- if (allowedHeaders.isEmpty()) {
- allowedHeaders.add("cache-control");
- allowedHeaders.add("content-language");
- allowedHeaders.add("content-type");
- allowedHeaders.add("expires");
- allowedHeaders.add("last-modified");
- allowedHeaders.add("pragma");
- }
-
- return allowedHeaders.contains(name);
-}
-
// Determines if a string is a valid token, as defined by
// "token" in section 2.2 of RFC 2616.
static bool isValidToken(const String& name)
@@ -163,12 +172,156 @@ static bool isValidHeaderValue(const String& name)
return !name.contains('\r') && !name.contains('\n');
}
-XMLHttpRequest::XMLHttpRequest(Document* doc)
- : ActiveDOMObject(doc, this)
+static bool isSetCookieHeader(const AtomicString& name)
+{
+ return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2");
+}
+
+template<class HashType>
+void PreflightResultCacheItem::addToAccessControlAllowList(const String& string, unsigned start, unsigned end, HashSet<String, HashType>& set)
+{
+ StringImpl* stringImpl = string.impl();
+ if (!stringImpl)
+ return;
+
+ // Skip white space from start.
+ while (start <= end && isSpaceOrNewline((*stringImpl)[start]))
+ start++;
+
+ // only white space
+ if (start > end)
+ return;
+
+ // Skip white space from end.
+ while (end && isSpaceOrNewline((*stringImpl)[end]))
+ end--;
+
+ // substringCopy() is called on the strings because the cache is accessed on multiple threads.
+ set.add(string.substringCopy(start, end - start + 1));
+}
+
+
+template<class HashType>
+bool PreflightResultCacheItem::parseAccessControlAllowList(const String& string, HashSet<String, HashType>& set)
+{
+ int start = 0;
+ int end;
+ while ((end = string.find(',', start)) != -1) {
+ if (start == end)
+ return false;
+
+ addToAccessControlAllowList(string, start, end - 1, set);
+ start = end + 1;
+ }
+ if (start != static_cast<int>(string.length()))
+ addToAccessControlAllowList(string, start, string.length() - 1, set);
+
+ return true;
+}
+
+bool PreflightResultCacheItem::parseAccessControlMaxAge(const String& string, unsigned& expiryDelta)
+{
+ // FIXME: this will not do the correct thing for a number starting with a '+'
+ bool ok = false;
+ expiryDelta = string.toUIntStrict(&ok);
+ return ok;
+}
+
+bool PreflightResultCacheItem::parse(const ResourceResponse& response)
+{
+ m_methods.clear();
+ if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), m_methods))
+ return false;
+
+ m_headers.clear();
+ if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), m_headers))
+ return false;
+
+ unsigned expiryDelta = 0;
+ if (!parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta))
+ expiryDelta = 5;
+
+ m_absoluteExpiryTime = currentTime() + expiryDelta;
+ return true;
+}
+
+bool PreflightResultCacheItem::allowsCrossSiteMethod(const String& method) const
+{
+ return m_methods.contains(method) || method == "GET" || method == "POST";
+}
+
+bool PreflightResultCacheItem::allowsCrossSiteHeaders(const HTTPHeaderMap& requestHeaders) const
+{
+ HTTPHeaderMap::const_iterator end = requestHeaders.end();
+ for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
+ if (!m_headers.contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first))
+ return false;
+ }
+ return true;
+}
+
+bool PreflightResultCacheItem::allowsRequest(bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const
+{
+ if (m_absoluteExpiryTime < currentTime())
+ return false;
+ if (includeCredentials && !m_credentials)
+ return false;
+ if (!allowsCrossSiteMethod(method))
+ return false;
+ if (!allowsCrossSiteHeaders(requestHeaders))
+ return false;
+ return true;
+}
+
+PreflightResultCache& PreflightResultCache::shared()
+{
+ AtomicallyInitializedStatic(PreflightResultCache&, cache = *new PreflightResultCache);
+ return cache;
+}
+
+void PreflightResultCache::appendEntry(const String& origin, const KURL& url, PreflightResultCacheItem* preflightResult)
+{
+ MutexLocker lock(m_mutex);
+ // Note that the entry may already be present in the HashMap if another thread is accessing the same location.
+ m_preflightHashMap.set(std::make_pair(origin.copy(), url.copy()), preflightResult);
+}
+
+bool PreflightResultCache::canSkipPreflight(const String& origin, const KURL& url, bool includeCredentials,
+ const String& method, const HTTPHeaderMap& requestHeaders)
+{
+ MutexLocker lock(m_mutex);
+ PreflightResultHashMap::iterator cacheIt = m_preflightHashMap.find(std::make_pair(origin, url));
+ if (cacheIt == m_preflightHashMap.end())
+ return false;
+
+ if (cacheIt->second->allowsRequest(includeCredentials, method, requestHeaders))
+ return true;
+
+ delete cacheIt->second;
+ m_preflightHashMap.remove(cacheIt);
+ return false;
+}
+
+static const XMLHttpRequestStaticData* staticData = 0;
+
+static const XMLHttpRequestStaticData* createXMLHttpRequestStaticData()
+{
+ staticData = new XMLHttpRequestStaticData;
+ return staticData;
+}
+
+static const XMLHttpRequestStaticData* initializeXMLHttpRequestStaticData()
+{
+ // Uses dummy to avoid warnings about an unused variable.
+ AtomicallyInitializedStatic(const XMLHttpRequestStaticData*, dummy = createXMLHttpRequestStaticData());
+ return dummy;
+}
+
+XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext* context)
+ : ActiveDOMObject(context, this)
, m_async(true)
, m_includeCredentials(false)
, m_state(UNSENT)
- , m_identifier(std::numeric_limits<unsigned long>::max())
, m_responseText("")
, m_createdDocument(false)
, m_error(false)
@@ -178,7 +331,7 @@ XMLHttpRequest::XMLHttpRequest(Document* doc)
, m_receivedLength(0)
, m_lastSendLineNumber(0)
{
- ASSERT(document());
+ initializeXMLHttpRequestStaticData();
}
XMLHttpRequest::~XMLHttpRequest()
@@ -193,12 +346,22 @@ Document* XMLHttpRequest::document() const
return static_cast<Document*>(scriptExecutionContext());
}
+#if ENABLE(DASHBOARD_SUPPORT)
+bool XMLHttpRequest::usesDashboardBackwardCompatibilityMode() const
+{
+ if (scriptExecutionContext()->isWorkerContext())
+ return false;
+ Settings* settings = document()->settings();
+ return settings && settings->usesDashboardBackwardCompatibilityMode();
+}
+#endif
+
XMLHttpRequest::State XMLHttpRequest::readyState() const
{
return m_state;
}
-const JSC::UString& XMLHttpRequest::responseText() const
+const ScriptString& XMLHttpRequest::responseText() const
{
return m_responseText;
}
@@ -209,7 +372,7 @@ Document* XMLHttpRequest::responseXML() const
return 0;
if (!m_createdDocument) {
- if (m_response.isHTTP() && !responseIsXML()) {
+ if ((m_response.isHTTP() && !responseIsXML()) || scriptExecutionContext()->isWorkerContext()) {
// The W3C spec requires this.
m_responseXML = 0;
} else {
@@ -272,7 +435,7 @@ void XMLHttpRequest::removeEventListener(const AtomicString& eventType, EventLis
bool XMLHttpRequest::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec)
{
// FIXME: check for other error conditions enumerated in the spec.
- if (evt->type().isEmpty()) {
+ if (!evt || evt->type().isEmpty()) {
ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
return true;
}
@@ -297,7 +460,7 @@ void XMLHttpRequest::changeState(State newState)
void XMLHttpRequest::callReadyStateChangeListener()
{
- if (!document() || !document()->frame())
+ if (!scriptExecutionContext())
return;
dispatchReadyStateChangeEvent();
@@ -375,7 +538,7 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, con
bool XMLHttpRequest::initSend(ExceptionCode& ec)
{
- if (!document())
+ if (!scriptExecutionContext())
return false;
if (m_state != OPENED || m_loader) {
@@ -403,8 +566,7 @@ void XMLHttpRequest::send(Document* document, ExceptionCode& ec)
String contentType = getRequestHeader("Content-Type");
if (contentType.isEmpty()) {
#if ENABLE(DASHBOARD_SUPPORT)
- Settings* settings = document->settings();
- if (settings && settings->usesDashboardBackwardCompatibilityMode())
+ if (usesDashboardBackwardCompatibilityMode())
setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
else
#endif
@@ -435,8 +597,7 @@ void XMLHttpRequest::send(const String& body, ExceptionCode& ec)
String contentType = getRequestHeader("Content-Type");
if (contentType.isEmpty()) {
#if ENABLE(DASHBOARD_SUPPORT)
- Settings* settings = document()->settings();
- if (settings && settings->usesDashboardBackwardCompatibilityMode())
+ if (usesDashboardBackwardCompatibilityMode())
setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
else
#endif
@@ -474,7 +635,7 @@ void XMLHttpRequest::createRequest(ExceptionCode& ec)
m_upload->dispatchLoadStartEvent();
}
- m_sameOriginRequest = document()->securityOrigin()->canRequest(m_url);
+ m_sameOriginRequest = scriptExecutionContext()->securityOrigin()->canRequest(m_url);
if (!m_sameOriginRequest) {
makeCrossSiteAccessRequest(ec);
@@ -540,7 +701,7 @@ void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec)
ResourceRequest request(url);
request.setHTTPMethod(m_method);
request.setAllowHTTPCookies(m_includeCredentials);
- request.setHTTPOrigin(document()->securityOrigin()->toString());
+ request.setHTTPOrigin(scriptExecutionContext()->securityOrigin()->toString());
if (m_requestHeaders.size() > 0)
request.addHTTPHeaderFields(m_requestHeaders);
@@ -551,43 +712,14 @@ void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec)
loadRequestSynchronously(request, ec);
}
-static bool canSkipPrelight(PreflightResultCache::iterator cacheIt, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders)
-{
- PreflightResultCacheItem* item = cacheIt->second;
- if (item->m_absoluteExpiryTime < currentTime())
- return false;
- if (includeCredentials && !item->m_credentials)
- return false;
- if (!item->m_methods->contains(method) && method != "GET" && method != "POST")
- return false;
- HTTPHeaderMap::const_iterator end = requestHeaders.end();
- for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
- if (!item->m_headers->contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first))
- return false;
- }
-
- return true;
-}
-
void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec)
{
- String origin = document()->securityOrigin()->toString();
+ String origin = scriptExecutionContext()->securityOrigin()->toString();
KURL url = m_url;
url.setUser(String());
url.setPass(String());
- bool skipPreflight = false;
-
- PreflightResultCache::iterator cacheIt = preflightResultCache().find(std::make_pair(origin, url));
- if (cacheIt != preflightResultCache().end()) {
- skipPreflight = canSkipPrelight(cacheIt, m_includeCredentials, m_method, m_requestHeaders);
- if (!skipPreflight) {
- delete cacheIt->second;
- preflightResultCache().remove(cacheIt);
- }
- }
-
- if (!skipPreflight) {
+ if (!PreflightResultCache::shared().canSkipPreflight(origin, url, m_includeCredentials, m_method, m_requestHeaders)) {
m_inPreflight = true;
ResourceRequest preflightRequest(url);
preflightRequest.setHTTPMethod("OPTIONS");
@@ -659,7 +791,7 @@ void XMLHttpRequest::handleAsynchronousPreflightResult()
ResourceRequest request(url);
request.setHTTPMethod(m_method);
request.setAllowHTTPCookies(m_includeCredentials);
- request.setHTTPOrigin(document()->securityOrigin()->toString());
+ request.setHTTPOrigin(scriptExecutionContext()->securityOrigin()->toString());
if (m_requestHeaders.size() > 0)
request.addHTTPHeaderFields(m_requestHeaders);
@@ -679,15 +811,13 @@ void XMLHttpRequest::loadRequestSynchronously(ResourceRequest& request, Exceptio
ResourceError error;
ResourceResponse response;
- if (document()->frame())
- m_identifier = document()->frame()->loader()->loadResourceSynchronously(request, error, response, data);
-
+ unsigned long identifier = ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, error, response, data);
m_loader = 0;
// No exception for file:/// resources, see <rdar://problem/4962298>.
// Also, if we have an HTTP response, then it wasn't a network error in fact.
if (error.isNull() || request.url().isLocalFile() || response.httpStatusCode() > 0) {
- processSyncLoadResults(data, response, ec);
+ processSyncLoadResults(identifier, data, response, ec);
return;
}
@@ -711,8 +841,9 @@ void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request)
// FIXME: Maybe create can return null for other reasons too?
// We need to keep content sniffing enabled for local files due to CFNetwork not providing a MIME type
// for local files otherwise, <rdar://problem/5671813>.
- bool sendResourceLoadCallbacks = !m_inPreflight;
- m_loader = SubresourceLoader::create(document()->frame(), this, request, false, sendResourceLoadCallbacks, request.url().isLocalFile());
+ LoadCallbacks callbacks = m_inPreflight ? DoNotSendLoadCallbacks : SendLoadCallbacks;
+ ContentSniff contentSniff = request.url().isLocalFile() ? SniffContent : DoNotSniffContent;
+ m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, callbacks, contentSniff);
if (m_loader) {
// Neither this object nor the JavaScript wrapper should be deleted while
@@ -724,6 +855,9 @@ void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request)
void XMLHttpRequest::abort()
{
+ // internalAbort() calls dropProtection(), which may release the last reference.
+ RefPtr<XMLHttpRequest> protect(this);
+
bool sendFlag = m_loader;
internalAbort();
@@ -770,10 +904,7 @@ void XMLHttpRequest::internalAbort()
void XMLHttpRequest::clearResponse()
{
m_response = ResourceResponse();
- {
- JSC::JSLock lock(false);
- m_responseText = "";
- }
+ m_responseText = "";
m_createdDocument = false;
m_responseXML = 0;
}
@@ -818,6 +949,7 @@ void XMLHttpRequest::abortError()
void XMLHttpRequest::dropProtection()
{
+#if USE(JSC)
// The XHR object itself holds on to the responseText, and
// thus has extra cost even independent of any
// responseText or responseXML objects it has handed
@@ -825,10 +957,10 @@ void XMLHttpRequest::dropProtection()
// can't be recouped until the load is done, so only
// report the extra cost at that point.
- if (JSDOMWindow* window = toJSDOMWindow(document()->frame())) {
- if (JSC::JSValue* wrapper = getCachedDOMObjectWrapper(*window->globalData(), this))
- JSC::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2);
- }
+ if (JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext()))
+ if (DOMObject* wrapper = getCachedDOMObjectWrapper(*globalObject->globalData(), this))
+ JSC::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2);
+#endif
unsetPendingActivity(this);
}
@@ -837,13 +969,21 @@ void XMLHttpRequest::overrideMimeType(const String& override)
{
m_mimeTypeOverride = override;
}
-
-void XMLHttpRequest::setRequestHeader(const String& name, const String& value, ExceptionCode& ec)
+
+static void reportUnsafeUsage(ScriptExecutionContext* context, const String& message)
+{
+ if (!context)
+ return;
+ // FIXME: It's not good to report the bad usage without indicating what source line it came from.
+ // We should pass additional parameters so we can tell the console where the mistake occurred.
+ context->addMessage(ConsoleDestination, JSMessageSource, ErrorMessageLevel, message, 1, String());
+}
+
+void XMLHttpRequest::setRequestHeader(const AtomicString& name, const String& value, ExceptionCode& ec)
{
if (m_state != OPENED || m_loader) {
#if ENABLE(DASHBOARD_SUPPORT)
- Settings* settings = document() ? document()->settings() : 0;
- if (settings && settings->usesDashboardBackwardCompatibilityMode())
+ if (usesDashboardBackwardCompatibilityMode())
return;
#endif
@@ -857,23 +997,28 @@ void XMLHttpRequest::setRequestHeader(const String& name, const String& value, E
}
// A privileged script (e.g. a Dashboard widget) can set any headers.
- if (!document()->securityOrigin()->canLoadLocalResources() && !isSafeRequestHeader(name)) {
- if (document() && document()->frame())
- document()->frame()->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Refused to set unsafe header \"" + name + "\"", 1, String());
+ if (!scriptExecutionContext()->securityOrigin()->canLoadLocalResources() && !isSafeRequestHeader(name)) {
+ reportUnsafeUsage(scriptExecutionContext(), "Refused to set unsafe header \"" + name + "\"");
return;
}
setRequestHeaderInternal(name, value);
}
-void XMLHttpRequest::setRequestHeaderInternal(const String& name, const String& value)
+void XMLHttpRequest::setRequestHeaderInternal(const AtomicString& name, const String& value)
{
pair<HTTPHeaderMap::iterator, bool> result = m_requestHeaders.add(name, value);
if (!result.second)
result.first->second += ", " + value;
}
-String XMLHttpRequest::getRequestHeader(const String& name) const
+bool XMLHttpRequest::isSafeRequestHeader(const String& name) const
+{
+ return !staticData->m_forbiddenRequestHeaders.contains(name) && !name.startsWith(staticData->m_proxyHeaderPrefix, false)
+ && !name.startsWith(staticData->m_secHeaderPrefix, false);
+}
+
+String XMLHttpRequest::getRequestHeader(const AtomicString& name) const
{
return m_requestHeaders.get(name);
}
@@ -886,24 +1031,33 @@ String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const
}
Vector<UChar> stringBuilder;
- String separator(": ");
HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it!= end; ++it) {
+ // Hide Set-Cookie header fields from the XMLHttpRequest client for these reasons:
+ // 1) If the client did have access to the fields, then it could read HTTP-only
+ // cookies; those cookies are supposed to be hidden from scripts.
+ // 2) There's no known harm in hiding Set-Cookie header fields entirely; we don't
+ // know any widely used technique that requires access to them.
+ // 3) Firefox has implemented this policy.
+ if (isSetCookieHeader(it->first) && !scriptExecutionContext()->securityOrigin()->canLoadLocalResources())
+ continue;
+
if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->first))
continue;
stringBuilder.append(it->first.characters(), it->first.length());
- stringBuilder.append(separator.characters(), separator.length());
+ stringBuilder.append(':');
+ stringBuilder.append(' ');
stringBuilder.append(it->second.characters(), it->second.length());
- stringBuilder.append((UChar)'\r');
- stringBuilder.append((UChar)'\n');
+ stringBuilder.append('\r');
+ stringBuilder.append('\n');
}
return String::adopt(stringBuilder);
}
-String XMLHttpRequest::getResponseHeader(const String& name, ExceptionCode& ec) const
+String XMLHttpRequest::getResponseHeader(const AtomicString& name, ExceptionCode& ec) const
{
if (m_state < LOADING) {
ec = INVALID_STATE_ERR;
@@ -913,12 +1067,25 @@ String XMLHttpRequest::getResponseHeader(const String& name, ExceptionCode& ec)
if (!isValidToken(name))
return "";
- if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name))
+ // See comment in getAllResponseHeaders above.
+ if (isSetCookieHeader(name) && !scriptExecutionContext()->securityOrigin()->canLoadLocalResources()) {
+ reportUnsafeUsage(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
return "";
+ }
+
+ if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name)) {
+ reportUnsafeUsage(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
+ return "";
+ }
return m_response.httpHeaderField(name);
}
+bool XMLHttpRequest::isOnAccessControlResponseHeaderWhitelist(const String& name) const
+{
+ return staticData->m_allowedCrossSiteResponseHeaders.contains(name);
+}
+
String XMLHttpRequest::responseMIMEType() const
{
String mimeType = extractMIMETypeFromMediaType(m_mimeTypeOverride);
@@ -967,67 +1134,62 @@ String XMLHttpRequest::statusText(ExceptionCode& ec) const
return String();
}
-void XMLHttpRequest::processSyncLoadResults(const Vector<char>& data, const ResourceResponse& response, ExceptionCode& ec)
+void XMLHttpRequest::processSyncLoadResults(unsigned long identifier, const Vector<char>& data, const ResourceResponse& response, ExceptionCode& ec)
{
- if (m_sameOriginRequest && !document()->securityOrigin()->canRequest(response.url())) {
+ if (m_sameOriginRequest && !scriptExecutionContext()->securityOrigin()->canRequest(response.url())) {
abort();
return;
}
- didReceiveResponse(0, response);
+ didReceiveResponse(response);
changeState(HEADERS_RECEIVED);
const char* bytes = static_cast<const char*>(data.data());
int len = static_cast<int>(data.size());
- didReceiveData(0, bytes, len);
+ didReceiveData(bytes, len);
- didFinishLoading(0);
+ didFinishLoading(identifier);
if (m_error)
ec = XMLHttpRequestException::NETWORK_ERR;
}
-void XMLHttpRequest::didFail(SubresourceLoader* loader, const ResourceError& error)
+void XMLHttpRequest::didFail()
{
// If we are already in an error state, for instance we called abort(), bail out early.
if (m_error)
return;
- if (error.isCancellation()) {
- abortError();
+ internalAbort();
+ networkError();
+}
+
+void XMLHttpRequest::didGetCancelled()
+{
+ // If we are already in an error state, for instance we called abort(), bail out early.
+ if (m_error)
return;
- }
- networkError();
- return;
+ abortError();
}
-void XMLHttpRequest::didFinishLoading(SubresourceLoader* loader)
+void XMLHttpRequest::didFinishLoading(unsigned long identifier)
{
if (m_error)
return;
if (m_inPreflight) {
- didFinishLoadingPreflight(loader);
+ didFinishLoadingPreflight();
return;
}
- ASSERT(loader == m_loader);
-
if (m_state < HEADERS_RECEIVED)
changeState(HEADERS_RECEIVED);
- {
- JSC::JSLock lock(false);
- if (m_decoder)
- m_responseText += m_decoder->flush();
- }
+ if (m_decoder)
+ m_responseText += m_decoder->flush();
- if (Frame* frame = document()->frame()) {
- if (Page* page = frame->page()) {
- page->inspectorController()->resourceRetrievedByXMLHttpRequest(m_loader ? m_loader->identifier() : m_identifier, m_responseText);
- page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, "XHR finished loading: \"" + m_url + "\".", m_lastSendLineNumber, m_lastSendURL);
- }
- }
+ scriptExecutionContext()->resourceRetrievedByXMLHttpRequest(identifier, m_responseText);
+ scriptExecutionContext()->addMessage(InspectorControllerDestination, JSMessageSource, LogMessageLevel, "XHR finished loading: \"" + m_url + "\".", m_lastSendLineNumber, m_lastSendURL);
bool hadLoader = m_loader;
m_loader = 0;
@@ -1039,7 +1201,7 @@ void XMLHttpRequest::didFinishLoading(SubresourceLoader* loader)
dropProtection();
}
-void XMLHttpRequest::didFinishLoadingPreflight(SubresourceLoader* loader)
+void XMLHttpRequest::didFinishLoadingPreflight()
{
ASSERT(m_inPreflight);
ASSERT(!m_sameOriginRequest);
@@ -1052,16 +1214,7 @@ void XMLHttpRequest::didFinishLoadingPreflight(SubresourceLoader* loader)
unsetPendingActivity(this);
}
-void XMLHttpRequest::willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse& redirectResponse)
-{
- // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
- if (!document()->securityOrigin()->canRequest(request.url())) {
- internalAbort();
- networkError();
- }
-}
-
-void XMLHttpRequest::didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
if (!m_upload)
return;
@@ -1080,12 +1233,8 @@ bool XMLHttpRequest::accessControlCheck(const ResourceResponse& response)
if (accessControlOriginString == "*" && !m_includeCredentials)
return true;
- KURL accessControlOriginURL(accessControlOriginString);
- if (!accessControlOriginURL.isValid())
- return false;
-
- RefPtr<SecurityOrigin> accessControlOrigin = SecurityOrigin::create(accessControlOriginURL);
- if (!accessControlOrigin->isSameSchemeHostPort(document()->securityOrigin()))
+ RefPtr<SecurityOrigin> accessControlOrigin = SecurityOrigin::createFromString(accessControlOriginString);
+ if (!accessControlOrigin->isSameSchemeHostPort(scriptExecutionContext()->securityOrigin()))
return false;
if (m_includeCredentials) {
@@ -1097,10 +1246,10 @@ bool XMLHttpRequest::accessControlCheck(const ResourceResponse& response)
return true;
}
-void XMLHttpRequest::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
+void XMLHttpRequest::didReceiveResponse(const ResourceResponse& response)
{
if (m_inPreflight) {
- didReceiveResponsePreflight(loader, response);
+ didReceiveResponsePreflight(response);
return;
}
@@ -1117,34 +1266,7 @@ void XMLHttpRequest::didReceiveResponse(SubresourceLoader* loader, const Resourc
m_responseEncoding = response.textEncodingName();
}
-template<class HashType>
-static bool parseAccessControlAllowList(const String& string, HashSet<String, HashType>* set)
-{
- int start = 0;
- int end;
- while ((end = string.find(',', start)) != -1) {
- if (start == end)
- return false;
-
- // FIXME: this could be made more efficient by not not allocating twice.
- set->add(string.substring(start, end - start).stripWhiteSpace());
- start = end + 1;
- }
- if (start != static_cast<int>(string.length()))
- set->add(string.substring(start).stripWhiteSpace());
-
- return true;
-}
-
-static bool parseAccessControlMaxAge(const String& string, unsigned& expiryDelta)
-{
- // FIXME: this will not do the correct thing for a number starting with a '+'
- bool ok = false;
- expiryDelta = string.toUIntStrict(&ok);
- return ok;
-}
-
-void XMLHttpRequest::didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse& response)
+void XMLHttpRequest::didReceiveResponsePreflight(const ResourceResponse& response)
{
ASSERT(m_inPreflight);
ASSERT(!m_sameOriginRequest);
@@ -1154,44 +1276,23 @@ void XMLHttpRequest::didReceiveResponsePreflight(SubresourceLoader*, const Resou
return;
}
- OwnPtr<HashSet<String> > methods(new HashSet<String>);
- if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), methods.get())) {
- networkError();
- return;
- }
-
- if (!methods->contains(m_method) && m_method != "GET" && m_method != "POST") {
- networkError();
- return;
- }
-
- OwnPtr<HashSet<String, CaseFoldingHash> > headers(new HashSet<String, CaseFoldingHash>);
- if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), headers.get())) {
+ OwnPtr<PreflightResultCacheItem> preflightResult(new PreflightResultCacheItem(m_includeCredentials));
+ if (!preflightResult->parse(response)
+ || !preflightResult->allowsCrossSiteMethod(m_method)
+ || !preflightResult->allowsCrossSiteHeaders(m_requestHeaders)) {
networkError();
return;
}
- HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
- for (HTTPHeaderMap::const_iterator it = m_requestHeaders.begin(); it != end; ++it) {
- if (!headers->contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first)) {
- networkError();
- return;
- }
- }
-
- unsigned expiryDelta = 0;
- if (!parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta))
- expiryDelta = 5;
-
- appendPreflightResultCacheEntry(document()->securityOrigin()->toString(), m_url, expiryDelta, m_includeCredentials, methods.release(), headers.release());
+ PreflightResultCache::shared().appendEntry(scriptExecutionContext()->securityOrigin()->toString(), m_url, preflightResult.release());
}
-void XMLHttpRequest::receivedCancellation(SubresourceLoader*, const AuthenticationChallenge& challenge)
+void XMLHttpRequest::didReceiveAuthenticationCancellation(const ResourceResponse& failureResponse)
{
- m_response = challenge.failureResponse();
+ m_response = failureResponse;
}
-void XMLHttpRequest::didReceiveData(SubresourceLoader*, const char* data, int len)
+void XMLHttpRequest::didReceiveData(const char* data, int len)
{
if (m_inPreflight)
return;
@@ -1210,18 +1311,13 @@ void XMLHttpRequest::didReceiveData(SubresourceLoader*, const char* data, int le
else
m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
}
- if (len == 0)
+ if (!len)
return;
if (len == -1)
len = strlen(data);
- String decoded = m_decoder->decode(data, len);
-
- {
- JSC::JSLock lock(false);
- m_responseText += decoded;
- }
+ m_responseText += m_decoder->decode(data, len);
if (!m_error) {
updateAndDispatchOnProgress(len);
@@ -1298,6 +1394,11 @@ void XMLHttpRequest::dispatchProgressEvent(long long expectedLength)
static_cast<unsigned>(m_receivedLength), static_cast<unsigned>(expectedLength));
}
+bool XMLHttpRequest::canSuspend() const
+{
+ return !m_loader;
+}
+
void XMLHttpRequest::stop()
{
internalAbort();
@@ -1305,8 +1406,8 @@ void XMLHttpRequest::stop()
void XMLHttpRequest::contextDestroyed()
{
+ ASSERT(!m_loader);
ActiveDOMObject::contextDestroyed();
- internalAbort();
}
ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const
diff --git a/WebCore/xml/XMLHttpRequest.h b/WebCore/xml/XMLHttpRequest.h
index 6962ab1..d7c0d36 100644
--- a/WebCore/xml/XMLHttpRequest.h
+++ b/WebCore/xml/XMLHttpRequest.h
@@ -26,18 +26,21 @@
#include "EventTarget.h"
#include "FormData.h"
#include "ResourceResponse.h"
-#include "SubresourceLoaderClient.h"
+#include "ScriptString.h"
+#include "ThreadableLoaderClient.h"
#include <wtf/OwnPtr.h>
namespace WebCore {
class Document;
class File;
+class ResourceRequest;
class TextResourceDecoder;
+class ThreadableLoader;
-class XMLHttpRequest : public RefCounted<XMLHttpRequest>, public EventTarget, private SubresourceLoaderClient, public ActiveDOMObject {
+class XMLHttpRequest : public RefCounted<XMLHttpRequest>, public EventTarget, private ThreadableLoaderClient, public ActiveDOMObject {
public:
- static PassRefPtr<XMLHttpRequest> create(Document* document) { return adoptRef(new XMLHttpRequest(document)); }
+ static PassRefPtr<XMLHttpRequest> create(ScriptExecutionContext* context) { return adoptRef(new XMLHttpRequest(context)); }
~XMLHttpRequest();
// These exact numeric values are important because JS expects them.
@@ -52,6 +55,7 @@ public:
virtual XMLHttpRequest* toXMLHttpRequest() { return this; }
virtual void contextDestroyed();
+ virtual bool canSuspend() const;
virtual void stop();
virtual ScriptExecutionContext* scriptExecutionContext() const;
@@ -67,14 +71,14 @@ public:
void send(const String&, ExceptionCode&);
void send(File*, ExceptionCode&);
void abort();
- void setRequestHeader(const String& name, const String& value, ExceptionCode&);
+ void setRequestHeader(const AtomicString& name, const String& value, ExceptionCode&);
void overrideMimeType(const String& override);
String getAllResponseHeaders(ExceptionCode&) const;
- String getResponseHeader(const String& name, ExceptionCode&) const;
- const JSC::UString& responseText() const;
+ String getResponseHeader(const AtomicString& name, ExceptionCode&) const;
+ const ScriptString& responseText() const;
Document* responseXML() const;
void setLastSendLineNumber(unsigned lineNumber) { m_lastSendLineNumber = lineNumber; }
- void setLastSendURL(JSC::UString url) { m_lastSendURL = url; }
+ void setLastSendURL(const String& url) { m_lastSendURL = url; }
XMLHttpRequestUpload* upload();
XMLHttpRequestUpload* optionalUpload() const { return m_upload.get(); }
@@ -110,26 +114,30 @@ public:
using RefCounted<XMLHttpRequest>::deref;
private:
- XMLHttpRequest(Document*);
+ XMLHttpRequest(ScriptExecutionContext*);
virtual void refEventTarget() { ref(); }
virtual void derefEventTarget() { deref(); }
Document* document() const;
- virtual void willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse& redirectResponse);
- virtual void didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
- virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
- virtual void didReceiveData(SubresourceLoader*, const char* data, int size);
- virtual void didFail(SubresourceLoader*, const ResourceError&);
- virtual void didFinishLoading(SubresourceLoader*);
- virtual void receivedCancellation(SubresourceLoader*, const AuthenticationChallenge&);
+#if ENABLE(DASHBOARD_SUPPORT)
+ bool usesDashboardBackwardCompatibilityMode() const;
+#endif
+
+ virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
+ virtual void didReceiveResponse(const ResourceResponse&);
+ virtual void didReceiveData(const char* data, int lengthReceived);
+ virtual void didFinishLoading(unsigned long identifier);
+ virtual void didFail();
+ virtual void didGetCancelled();
+ virtual void didReceiveAuthenticationCancellation(const ResourceResponse&);
// Special versions for the preflight
- void didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse&);
- void didFinishLoadingPreflight(SubresourceLoader*);
+ void didReceiveResponsePreflight(const ResourceResponse&);
+ void didFinishLoadingPreflight();
- void processSyncLoadResults(const Vector<char>& data, const ResourceResponse&, ExceptionCode&);
+ void processSyncLoadResults(unsigned long identifier, const Vector<char>& data, const ResourceResponse&, ExceptionCode&);
void updateAndDispatchOnProgress(unsigned int len);
String responseMIMEType() const;
@@ -137,8 +145,9 @@ private:
bool initSend(ExceptionCode&);
- String getRequestHeader(const String& name) const;
- void setRequestHeaderInternal(const String& name, const String& value);
+ String getRequestHeader(const AtomicString& name) const;
+ void setRequestHeaderInternal(const AtomicString& name, const String& value);
+ bool isSafeRequestHeader(const String&) const;
void changeState(State newState);
void callReadyStateChangeListener();
@@ -159,6 +168,8 @@ private:
void loadRequestSynchronously(ResourceRequest&, ExceptionCode&);
void loadRequestAsynchronously(ResourceRequest&);
+ bool isOnAccessControlResponseHeaderWhitelist(const String&) const;
+
bool isSimpleCrossSiteAccessRequest() const;
String accessControlOrigin() const;
bool accessControlCheck(const ResourceResponse&);
@@ -193,22 +204,21 @@ private:
bool m_async;
bool m_includeCredentials;
- RefPtr<SubresourceLoader> m_loader;
+ RefPtr<ThreadableLoader> m_loader;
State m_state;
ResourceResponse m_response;
String m_responseEncoding;
RefPtr<TextResourceDecoder> m_decoder;
- unsigned long m_identifier;
- // Unlike most strings in the DOM, we keep this as a JSC::UString, not a WebCore::String.
+ // Unlike most strings in the DOM, we keep this as a ScriptString, not a WebCore::String.
// That's because these strings can easily get huge (they are filled from the network with
// no parsing) and because JS can easily observe many intermediate states, so it's very useful
// to be able to share the buffer with JavaScript versions of the whole or partial string.
// In contrast, this string doesn't interact much with the rest of the engine so it's not that
// big a cost that it isn't a String.
- JSC::UString m_responseText;
+ ScriptString m_responseText;
mutable bool m_createdDocument;
mutable RefPtr<Document> m_responseXML;
@@ -224,7 +234,7 @@ private:
long long m_receivedLength;
unsigned m_lastSendLineNumber;
- JSC::UString m_lastSendURL;
+ String m_lastSendURL;
};
} // namespace WebCore
diff --git a/WebCore/xml/XMLHttpRequest.idl b/WebCore/xml/XMLHttpRequest.idl
index fa6b9ca..315d95c 100644
--- a/WebCore/xml/XMLHttpRequest.idl
+++ b/WebCore/xml/XMLHttpRequest.idl
@@ -75,7 +75,7 @@ module xml {
raises(DOMException);
[Custom, ConvertNullStringTo=Null] DOMString getResponseHeader(in DOMString header)
raises(DOMException);
- readonly attribute [ConvertNullStringTo=Null] DOMString responseText;
+ readonly attribute [CustomGetter] DOMString responseText; // The custom getter implements ConvertNullStringTo=Null
readonly attribute Document responseXML;
readonly attribute unsigned short status
getter raises(DOMException);
diff --git a/WebCore/xml/XMLHttpRequestUpload.cpp b/WebCore/xml/XMLHttpRequestUpload.cpp
index cef1798..a58c271 100644
--- a/WebCore/xml/XMLHttpRequestUpload.cpp
+++ b/WebCore/xml/XMLHttpRequestUpload.cpp
@@ -87,7 +87,7 @@ void XMLHttpRequestUpload::removeEventListener(const AtomicString& eventType, Ev
bool XMLHttpRequestUpload::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec)
{
// FIXME: check for other error conditions enumerated in the spec.
- if (evt->type().isEmpty()) {
+ if (!evt || evt->type().isEmpty()) {
ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
return true;
}
diff --git a/WebCore/xml/XMLSerializer.cpp b/WebCore/xml/XMLSerializer.cpp
index ac7dc19..7b49897 100644
--- a/WebCore/xml/XMLSerializer.cpp
+++ b/WebCore/xml/XMLSerializer.cpp
@@ -1,6 +1,5 @@
/*
- * This file is part of the KDE libraries
- * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ * Copyright (C) 2003, 2006 Apple Inc. All rights reserved.
* Copyright (C) 2006 Samuel Weinig (sam@webkit.org)
*
* This library is free software; you can redistribute it and/or
diff --git a/WebCore/xml/XPathExpressionNode.cpp b/WebCore/xml/XPathExpressionNode.cpp
index 88e349e..647c6af 100644
--- a/WebCore/xml/XPathExpressionNode.cpp
+++ b/WebCore/xml/XPathExpressionNode.cpp
@@ -31,13 +31,14 @@
#include "Node.h"
#include "XPathValue.h"
+#include <wtf/StdLibExtras.h>
namespace WebCore {
namespace XPath {
EvaluationContext& Expression::evaluationContext()
{
- static EvaluationContext evaluationContext;
+ DEFINE_STATIC_LOCAL(EvaluationContext, evaluationContext, ());
return evaluationContext;
}
diff --git a/WebCore/xml/XPathGrammar.y b/WebCore/xml/XPathGrammar.y
index 50a69c2..15a859b 100644
--- a/WebCore/xml/XPathGrammar.y
+++ b/WebCore/xml/XPathGrammar.y
@@ -68,8 +68,8 @@ using namespace XPath;
%{
-int xpathyylex(YYSTYPE* yylval) { return Parser::current()->lex(yylval); }
-void xpathyyerror(const char* str) { }
+static int xpathyylex(YYSTYPE* yylval) { return Parser::current()->lex(yylval); }
+static void xpathyyerror(const char*) { }
%}
diff --git a/WebCore/xml/XPathParser.cpp b/WebCore/xml/XPathParser.cpp
index 77c3011..5501df1 100644
--- a/WebCore/xml/XPathParser.cpp
+++ b/WebCore/xml/XPathParser.cpp
@@ -36,6 +36,7 @@
#include "XPathException.h"
#include "XPathNSResolver.h"
#include "XPathStep.h"
+#include <wtf/StdLibExtras.h>
int xpathyyparse(void*);
@@ -53,6 +54,8 @@ Parser* Parser::currentParser = 0;
enum XMLCat { NameStart, NameCont, NotPartOfName };
+typedef HashMap<String, Step::Axis> AxisNamesMap;
+
static XMLCat charCat(UChar aChar)
{
//### might need to add some special cases from the XML spec.
@@ -70,7 +73,7 @@ static XMLCat charCat(UChar aChar)
return NotPartOfName;
}
-static void setUpAxisNamesMap(HashMap<String, Step::Axis>& axisNames)
+static void setUpAxisNamesMap(AxisNamesMap& axisNames)
{
struct AxisName {
const char* name;
@@ -97,12 +100,12 @@ static void setUpAxisNamesMap(HashMap<String, Step::Axis>& axisNames)
static bool isAxisName(const String& name, Step::Axis& type)
{
- static HashMap<String, Step::Axis> axisNames;
+ DEFINE_STATIC_LOCAL(AxisNamesMap, axisNames, ());
if (axisNames.isEmpty())
setUpAxisNamesMap(axisNames);
- HashMap<String, Step::Axis>::iterator it = axisNames.find(name);
+ AxisNamesMap::iterator it = axisNames.find(name);
if (it == axisNames.end())
return false;
type = it->second;
@@ -111,7 +114,7 @@ static bool isAxisName(const String& name, Step::Axis& type)
static bool isNodeTypeName(const String& name)
{
- static HashSet<String> nodeTypeNames;
+ DEFINE_STATIC_LOCAL(HashSet<String>, nodeTypeNames, ());
if (nodeTypeNames.isEmpty()) {
nodeTypeNames.add("comment");
nodeTypeNames.add("text");
diff --git a/WebCore/xml/XPathPath.h b/WebCore/xml/XPathPath.h
index 97692b2..46e57ff 100644
--- a/WebCore/xml/XPathPath.h
+++ b/WebCore/xml/XPathPath.h
@@ -32,8 +32,6 @@
#include "XPathExpressionNode.h"
#include "XPathNodeSet.h"
-int xpathyyparse(void*);
-
namespace WebCore {
namespace XPath {
diff --git a/WebCore/xml/XPathValue.cpp b/WebCore/xml/XPathValue.cpp
index b3cad38..bac0e13 100644
--- a/WebCore/xml/XPathValue.cpp
+++ b/WebCore/xml/XPathValue.cpp
@@ -33,6 +33,7 @@
#include "XPathUtil.h"
#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
#include <limits>
using std::numeric_limits;
@@ -45,7 +46,7 @@ const Value::AdoptTag Value::adopt = {};
const NodeSet& Value::toNodeSet() const
{
if (!m_data) {
- static NodeSet emptyNodeSet;
+ DEFINE_STATIC_LOCAL(NodeSet, emptyNodeSet, ());
return emptyNodeSet;
}
diff --git a/WebCore/xml/XSLImportRule.cpp b/WebCore/xml/XSLImportRule.cpp
index 2efafa3..6ceb108 100644
--- a/WebCore/xml/XSLImportRule.cpp
+++ b/WebCore/xml/XSLImportRule.cpp
@@ -61,7 +61,7 @@ void XSLImportRule::setXSLStyleSheet(const String& url, const String& sheet)
XSLStyleSheet* parent = parentStyleSheet();
if (parent)
- m_styleSheet->setOwnerDocument(parent->ownerDocument());
+ m_styleSheet->setParentStyleSheet(parent);
m_styleSheet->parseString(sheet);
m_loading = false;
diff --git a/WebCore/xml/XSLStyleSheet.cpp b/WebCore/xml/XSLStyleSheet.cpp
index 9443652..0d112a5 100644
--- a/WebCore/xml/XSLStyleSheet.cpp
+++ b/WebCore/xml/XSLStyleSheet.cpp
@@ -60,6 +60,7 @@ XSLStyleSheet::XSLStyleSheet(XSLImportRule* parentRule, const String& href)
, m_embedded(false)
, m_processed(false) // Child sheets get marked as processed when the libxslt engine has finally seen them.
, m_stylesheetDocTaken(false)
+ , m_parentStyleSheet(0)
{
}
@@ -70,6 +71,7 @@ XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& href, bool embedde
, m_embedded(embedded)
, m_processed(true) // The root sheet starts off processed.
, m_stylesheetDocTaken(false)
+ , m_parentStyleSheet(0)
{
}
@@ -131,7 +133,7 @@ DocLoader* XSLStyleSheet::docLoader()
return m_ownerDocument->docLoader();
}
-bool XSLStyleSheet::parseString(const String& string, bool strict)
+bool XSLStyleSheet::parseString(const String& string, bool)
{
// Parse in a single chunk into an xmlDocPtr
const UChar BOM = 0xFEFF;
@@ -147,10 +149,29 @@ bool XSLStyleSheet::parseString(const String& string, bool strict)
xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc);
xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc);
- m_stylesheetDoc = xmlReadMemory(reinterpret_cast<const char*>(string.characters()), string.length() * sizeof(UChar),
+ const char* buffer = reinterpret_cast<const char*>(string.characters());
+ int size = string.length() * sizeof(UChar);
+
+ xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt(buffer, size);
+
+ if (m_parentStyleSheet) {
+ // The XSL transform may leave the newly-transformed document
+ // with references to the symbol dictionaries of the style sheet
+ // and any of its children. XML document disposal can corrupt memory
+ // if a document uses more than one symbol dictionary, so we
+ // ensure that all child stylesheets use the same dictionaries as their
+ // parents.
+ xmlDictFree(ctxt->dict);
+ ctxt->dict = m_parentStyleSheet->m_stylesheetDoc->dict;
+ xmlDictReference(ctxt->dict);
+ }
+
+ m_stylesheetDoc = xmlCtxtReadMemory(ctxt, buffer, size,
href().utf8().data(),
BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE",
XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_NOWARNING | XML_PARSE_NOCDATA);
+ xmlFreeParserCtxt(ctxt);
+
loadChildSheets();
xmlSetStructuredErrorFunc(0, 0);
@@ -235,6 +256,13 @@ xsltStylesheetPtr XSLStyleSheet::compileStyleSheet()
return result;
}
+void XSLStyleSheet::setParentStyleSheet(XSLStyleSheet* parent)
+{
+ m_parentStyleSheet = parent;
+ if (parent)
+ m_ownerDocument = parent->ownerDocument();
+}
+
xmlDocPtr XSLStyleSheet::locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri)
{
bool matchedParent = (parentDoc == document());
diff --git a/WebCore/xml/XSLStyleSheet.h b/WebCore/xml/XSLStyleSheet.h
index 8946529..fe97b54 100644
--- a/WebCore/xml/XSLStyleSheet.h
+++ b/WebCore/xml/XSLStyleSheet.h
@@ -70,7 +70,7 @@ public:
DocLoader* docLoader();
Document* ownerDocument() { return m_ownerDocument; }
- void setOwnerDocument(Document* doc) { m_ownerDocument = doc; }
+ void setParentStyleSheet(XSLStyleSheet* parent);
xmlDocPtr document();
@@ -90,6 +90,7 @@ private:
bool m_embedded;
bool m_processed;
bool m_stylesheetDocTaken;
+ XSLStyleSheet* m_parentStyleSheet;
};
} // namespace WebCore
diff --git a/WebCore/xml/XSLTExtensions.cpp b/WebCore/xml/XSLTExtensions.cpp
index d89f08b..069ddd8 100644
--- a/WebCore/xml/XSLTExtensions.cpp
+++ b/WebCore/xml/XSLTExtensions.cpp
@@ -27,6 +27,7 @@
#include "config.h"
#if ENABLE(XSLT)
+#include "XSLTExtensions.h"
#include <libxml/xpathInternals.h>
diff --git a/WebCore/xml/XSLTProcessor.cpp b/WebCore/xml/XSLTProcessor.cpp
index ab554c4..198c90c 100644
--- a/WebCore/xml/XSLTProcessor.cpp
+++ b/WebCore/xml/XSLTProcessor.cpp
@@ -36,7 +36,7 @@
#include "FrameLoader.h"
#include "FrameView.h"
#include "HTMLDocument.h"
-#include "HTMLTokenizer.h"
+#include "HTMLTokenizer.h" // for parseHTMLDocumentFragment
#include "Page.h"
#include "ResourceError.h"
#include "ResourceHandle.h"
@@ -74,7 +74,7 @@ SOFT_LINK(libxslt, xsltNextImport, xsltStylesheetPtr, (xsltStylesheetPtr style),
namespace WebCore {
-void XSLTProcessor::genericErrorFunc(void* userData, const char* msg, ...)
+void XSLTProcessor::genericErrorFunc(void*, const char*, ...)
{
// It would be nice to do something with this error message.
}
@@ -107,7 +107,7 @@ void XSLTProcessor::parseErrorFunc(void* userData, xmlError* error)
static XSLTProcessor* globalProcessor = 0;
static DocLoader* globalDocLoader = 0;
static xmlDocPtr docLoaderFunc(const xmlChar* uri,
- xmlDictPtr dict,
+ xmlDictPtr,
int options,
void* ctxt,
xsltLoadType type)
@@ -284,7 +284,7 @@ PassRefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourc
return result.release();
}
-static inline RefPtr<DocumentFragment> createFragmentFromSource(const String& sourceString, const String& sourceMIMEType, Node* sourceNode, Document* outputDoc)
+static inline RefPtr<DocumentFragment> createFragmentFromSource(const String& sourceString, const String& sourceMIMEType, Document* outputDoc)
{
RefPtr<DocumentFragment> fragment = new DocumentFragment(outputDoc);
@@ -433,24 +433,24 @@ PassRefPtr<DocumentFragment> XSLTProcessor::transformToFragment(Node* sourceNode
if (!transformToString(sourceNode, resultMIMEType, resultString, resultEncoding))
return 0;
- return createFragmentFromSource(resultString, resultMIMEType, sourceNode, outputDoc);
+ return createFragmentFromSource(resultString, resultMIMEType, outputDoc);
}
-void XSLTProcessor::setParameter(const String& namespaceURI, const String& localName, const String& value)
+void XSLTProcessor::setParameter(const String& /*namespaceURI*/, const String& localName, const String& value)
{
// FIXME: namespace support?
// should make a QualifiedName here but we'd have to expose the impl
m_parameters.set(localName, value);
}
-String XSLTProcessor::getParameter(const String& namespaceURI, const String& localName) const
+String XSLTProcessor::getParameter(const String& /*namespaceURI*/, const String& localName) const
{
// FIXME: namespace support?
// should make a QualifiedName here but we'd have to expose the impl
return m_parameters.get(localName);
}
-void XSLTProcessor::removeParameter(const String& namespaceURI, const String& localName)
+void XSLTProcessor::removeParameter(const String& /*namespaceURI*/, const String& localName)
{
// FIXME: namespace support?
m_parameters.remove(localName);
diff --git a/WebCore/xml/XSLTUnicodeSort.cpp b/WebCore/xml/XSLTUnicodeSort.cpp
index ed66112..b0b9c72 100644
--- a/WebCore/xml/XSLTUnicodeSort.cpp
+++ b/WebCore/xml/XSLTUnicodeSort.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,10 +32,8 @@
#if ENABLE(XSLT)
#include "PlatformString.h"
-
#include <libxslt/templates.h>
#include <libxslt/xsltutils.h>
-
#include <wtf/unicode/Collator.h>
#if PLATFORM(MAC)
@@ -43,57 +41,29 @@
#endif
#if PLATFORM(MAC)
+
SOFT_LINK_LIBRARY(libxslt)
SOFT_LINK(libxslt, xsltComputeSortResult, xmlXPathObjectPtr*, (xsltTransformContextPtr ctxt, xmlNodePtr sort), (ctxt, sort))
SOFT_LINK(libxslt, xsltEvalAttrValueTemplate, xmlChar*, (xsltTransformContextPtr ctxt, xmlNodePtr node, const xmlChar *name, const xmlChar *ns), (ctxt, node, name, ns))
-static void init_xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
-static void (*softLink_xsltTransformError)(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *, ...) WTF_ATTRIBUTE_PRINTF(4, 5) = init_xsltTransformError;
+static void xsltTransformErrorTrampoline(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char* message, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
-static void init_xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char* msg, ...)
+void xsltTransformErrorTrampoline(xsltTransformContextPtr context, xsltStylesheetPtr style, xmlNodePtr node, const char* message, ...)
{
- softLink_xsltTransformError = (void (*) (xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *, ...))dlsym(libxsltLibrary(), "xsltTransformError");
- ASSERT(softLink_xsltTransformError);
-
va_list args;
- va_start(args, msg);
-#if PLATFORM(WIN_OS)
- char str[1024];
- vsnprintf(str, sizeof(str) - 1, msg, args);
-#else
- char* str;
- vasprintf(&str, msg, args);
-#endif
+ va_start(args, message);
+ char* messageWithArgs;
+ vasprintf(&messageWithArgs, message, args);
va_end(args);
- softLink_xsltTransformError(ctxt, style, node, "%s", str);
+ static void (*xsltTransformErrorPointer)(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char*, ...) WTF_ATTRIBUTE_PRINTF(4, 5)
+ = reinterpret_cast<void (*)(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char*, ...)>(dlsym(libxsltLibrary(), "xsltTransformError"));
+ xsltTransformErrorPointer(context, style, node, "%s", messageWithArgs);
-#if !PLATFORM(WIN_OS)
- free(str);
-#endif
+ free(messageWithArgs);
}
-inline void xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char* msg, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
-
-inline void xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char* msg, ...)
-{
- va_list args;
- va_start(args, msg);
-#if PLATFORM(WIN_OS)
- char str[1024];
- vsnprintf(str, sizeof(str) - 1, msg, args);
-#else
- char* str;
- vasprintf(&str, msg, args);
-#endif
- va_end(args);
-
- softLink_xsltTransformError(ctxt, style, node, "%s", str);
-
-#if !PLATFORM(WIN_OS)
- free(str);
-#endif
-}
+#define xsltTransformError xsltTransformErrorTrampoline
#endif