summaryrefslogtreecommitdiffstats
path: root/WebCore/xml
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/xml')
-rw-r--r--WebCore/xml/XMLHttpRequest.cpp395
-rw-r--r--WebCore/xml/XMLHttpRequest.h23
-rw-r--r--WebCore/xml/XMLHttpRequest.idl3
-rw-r--r--WebCore/xml/XMLHttpRequestException.idl3
-rw-r--r--WebCore/xml/XMLHttpRequestProgressEvent.idl3
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.cpp6
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.h2
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.idl3
-rw-r--r--WebCore/xml/XPathExpression.cpp4
-rw-r--r--WebCore/xml/XPathFunctions.cpp16
-rw-r--r--WebCore/xml/XPathNodeSet.cpp2
-rw-r--r--WebCore/xml/XPathResult.cpp4
-rw-r--r--WebCore/xml/XPathResult.h8
-rw-r--r--WebCore/xml/XPathStep.cpp8
14 files changed, 131 insertions, 349 deletions
diff --git a/WebCore/xml/XMLHttpRequest.cpp b/WebCore/xml/XMLHttpRequest.cpp
index f16755a..dd3f361 100644
--- a/WebCore/xml/XMLHttpRequest.cpp
+++ b/WebCore/xml/XMLHttpRequest.cpp
@@ -23,6 +23,8 @@
#include "XMLHttpRequest.h"
#include "CString.h"
+#include "CrossOriginAccessControl.h"
+#include "CrossOriginPreflightResultCache.h"
#include "DOMImplementation.h"
#include "Document.h"
#include "Event.h"
@@ -31,23 +33,17 @@
#include "EventNames.h"
#include "File.h"
#include "HTTPParsers.h"
-#include "KURL.h"
-#include "KURLHash.h"
#include "ResourceError.h"
#include "ResourceRequest.h"
-#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
#include "Settings.h"
-#include "SystemTime.h"
#include "TextResourceDecoder.h"
#include "ThreadableLoader.h"
#include "XMLHttpRequestException.h"
#include "XMLHttpRequestProgressEvent.h"
#include "XMLHttpRequestUpload.h"
#include "markup.h"
-#include <wtf/CurrentTime.h>
-#include <wtf/Noncopyable.h>
#include <wtf/StdLibExtras.h>
-#include <wtf/Threading.h>
#if USE(JSC)
#include "JSDOMWindow.h"
@@ -55,14 +51,11 @@
namespace WebCore {
-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()
@@ -71,76 +64,26 @@ XMLHttpRequestStaticData::XMLHttpRequestStaticData()
{
m_forbiddenRequestHeaders.add("accept-charset");
m_forbiddenRequestHeaders.add("accept-encoding");
+ m_forbiddenRequestHeaders.add("access-control-request-headers");
+ m_forbiddenRequestHeaders.add("access-control-request-method");
+ m_forbiddenRequestHeaders.add("authorization");
m_forbiddenRequestHeaders.add("connection");
m_forbiddenRequestHeaders.add("content-length");
m_forbiddenRequestHeaders.add("content-transfer-encoding");
+ m_forbiddenRequestHeaders.add("cookie");
+ m_forbiddenRequestHeaders.add("cookie2");
m_forbiddenRequestHeaders.add("date");
m_forbiddenRequestHeaders.add("expect");
m_forbiddenRequestHeaders.add("host");
m_forbiddenRequestHeaders.add("keep-alive");
+ m_forbiddenRequestHeaders.add("origin");
m_forbiddenRequestHeaders.add("referer");
m_forbiddenRequestHeaders.add("te");
m_forbiddenRequestHeaders.add("trailer");
m_forbiddenRequestHeaders.add("transfer-encoding");
m_forbiddenRequestHeaders.add("upgrade");
+ m_forbiddenRequestHeaders.add("user-agent");
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)
- {
- }
-
- 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;
- HashSet<String> m_methods;
- HeadersSet m_headers;
-};
-
-class PreflightResultCache : Noncopyable {
-public:
- static PreflightResultCache& shared();
-
- void appendEntry(const String& origin, const KURL&, PreflightResultCacheItem*);
- bool canSkipPreflight(const String& origin, const KURL&, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders);
-
-private:
- PreflightResultCache() { }
-
- typedef HashMap<std::pair<String, KURL>, PreflightResultCacheItem*> PreflightResultHashMap;
-
- PreflightResultHashMap m_preflightHashMap;
- Mutex m_mutex;
-};
-
-static bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name)
-{
- return equalIgnoringCase(name, "accept") || equalIgnoringCase(name, "accept-language") || equalIgnoringCase(name, "content-type");
}
// Determines if a string is a valid token, as defined by
@@ -177,131 +120,6 @@ 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()
@@ -330,6 +148,7 @@ XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext* context)
, m_inPreflight(false)
, m_receivedLength(0)
, m_lastSendLineNumber(0)
+ , m_exceptionCode(0)
{
initializeXMLHttpRequestStaticData();
}
@@ -379,7 +198,7 @@ Document* XMLHttpRequest::responseXML() const
m_responseXML = document()->implementation()->createDocument(0);
m_responseXML->open();
m_responseXML->setURL(m_url);
- // FIXME: set Last-Modified and cookies (currently, those are only available for HTMLDocuments).
+ // FIXME: Set Last-Modified.
m_responseXML->write(String(m_responseText));
m_responseXML->finishParsing();
m_responseXML->close();
@@ -629,19 +448,28 @@ void XMLHttpRequest::send(File* body, ExceptionCode& ec)
void XMLHttpRequest::createRequest(ExceptionCode& ec)
{
+ // Upload event listeners should be disallowed for simple cross-origin requests, because POSTing to an URL that does not
+ // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. If a listener exists
+ // when creating the request, it will force preflight.
+ // Also, only async requests support upload progress events.
+ m_uploadEventsAllowed = false;
if (m_async) {
dispatchLoadStartEvent();
- if (m_requestEntityBody && m_upload)
+ if (m_requestEntityBody && m_upload) {
+ m_uploadEventsAllowed = m_upload->hasListeners();
m_upload->dispatchLoadStartEvent();
+ }
}
m_sameOriginRequest = scriptExecutionContext()->securityOrigin()->canRequest(m_url);
if (!m_sameOriginRequest) {
- makeCrossSiteAccessRequest(ec);
+ makeCrossOriginAccessRequest(ec);
return;
}
+ m_uploadEventsAllowed = true;
+
makeSameOriginRequest(ec);
}
@@ -654,6 +482,7 @@ void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec)
if (m_requestEntityBody) {
ASSERT(m_method != "GET");
+ ASSERT(m_method != "HEAD");
request.setHTTPBody(m_requestEntityBody.release());
}
@@ -666,33 +495,19 @@ void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec)
loadRequestSynchronously(request, ec);
}
-bool XMLHttpRequest::isSimpleCrossSiteAccessRequest() const
-{
- if (m_method != "GET" && m_method != "POST")
- return false;
-
- HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
- for (HTTPHeaderMap::const_iterator it = m_requestHeaders.begin(); it != end; ++it) {
- if (!isOnAccessControlSimpleRequestHeaderWhitelist(it->first))
- return false;
- }
-
- return true;
-}
-
-void XMLHttpRequest::makeCrossSiteAccessRequest(ExceptionCode& ec)
+void XMLHttpRequest::makeCrossOriginAccessRequest(ExceptionCode& ec)
{
ASSERT(!m_sameOriginRequest);
- if (isSimpleCrossSiteAccessRequest())
- makeSimpleCrossSiteAccessRequest(ec);
+ if (!m_uploadEventsAllowed && isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders))
+ makeSimpleCrossOriginAccessRequest(ec);
else
- makeCrossSiteAccessRequestWithPreflight(ec);
+ makeCrossOriginAccessRequestWithPreflight(ec);
}
-void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec)
+void XMLHttpRequest::makeSimpleCrossOriginAccessRequest(ExceptionCode& ec)
{
- ASSERT(isSimpleCrossSiteAccessRequest());
+ ASSERT(isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders));
KURL url = m_url;
url.setUser(String());
@@ -706,20 +521,26 @@ void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec)
if (m_requestHeaders.size() > 0)
request.addHTTPHeaderFields(m_requestHeaders);
+ if (m_requestEntityBody) {
+ ASSERT(m_method != "GET");
+ ASSERT(m_method != "HEAD");
+ request.setHTTPBody(m_requestEntityBody.release());
+ }
+
if (m_async)
loadRequestAsynchronously(request);
else
loadRequestSynchronously(request, ec);
}
-void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec)
+void XMLHttpRequest::makeCrossOriginAccessRequestWithPreflight(ExceptionCode& ec)
{
String origin = scriptExecutionContext()->securityOrigin()->toString();
KURL url = m_url;
url.setUser(String());
url.setPass(String());
- if (!PreflightResultCache::shared().canSkipPreflight(origin, url, m_includeCredentials, m_method, m_requestHeaders)) {
+ if (!CrossOriginPreflightResultCache::shared().canSkipPreflight(origin, url, m_includeCredentials, m_method, m_requestHeaders)) {
m_inPreflight = true;
ResourceRequest preflightRequest(url);
preflightRequest.setHTTPMethod("OPTIONS");
@@ -744,6 +565,7 @@ void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec)
}
if (m_async) {
+ m_uploadEventsAllowed = true;
loadRequestAsynchronously(preflightRequest);
return;
}
@@ -766,10 +588,12 @@ void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec)
if (m_requestEntityBody) {
ASSERT(m_method != "GET");
+ ASSERT(m_method != "HEAD");
request.setHTTPBody(m_requestEntityBody.release());
}
if (m_async) {
+ m_uploadEventsAllowed = true;
loadRequestAsynchronously(request);
return;
}
@@ -798,43 +622,30 @@ void XMLHttpRequest::handleAsynchronousPreflightResult()
if (m_requestEntityBody) {
ASSERT(m_method != "GET");
+ ASSERT(m_method != "HEAD");
request.setHTTPBody(m_requestEntityBody.release());
}
+ m_uploadEventsAllowed = true;
loadRequestAsynchronously(request);
}
void XMLHttpRequest::loadRequestSynchronously(ResourceRequest& request, ExceptionCode& ec)
{
ASSERT(!m_async);
- Vector<char> data;
- ResourceError error;
- ResourceResponse response;
- 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(identifier, data, response, ec);
- return;
- }
-
- if (error.isCancellation()) {
- abortError();
- ec = XMLHttpRequestException::ABORT_ERR;
- return;
- }
-
- networkError();
- ec = XMLHttpRequestException::NETWORK_ERR;
+ m_exceptionCode = 0;
+ ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this);
+ if (!m_exceptionCode && m_error)
+ m_exceptionCode = XMLHttpRequestException::NETWORK_ERR;
+ ec = m_exceptionCode;
}
-
void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request)
{
ASSERT(m_async);
+ m_exceptionCode = 0;
// SubresourceLoader::create can return null here, for example if we're no longer attached to a page.
// This is true while running onunload handlers.
// FIXME: We need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>.
@@ -842,7 +653,11 @@ void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request)
// 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>.
LoadCallbacks callbacks = m_inPreflight ? DoNotSendLoadCallbacks : SendLoadCallbacks;
- ContentSniff contentSniff = request.url().isLocalFile() ? SniffContent : DoNotSniffContent;
+ ContentSniff contentSniff = request.url().isLocalFile() ? SniffContent : DoNotSniffContent;
+
+ if (m_upload)
+ request.setReportUploadProgress(true);
+
m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, callbacks, contentSniff);
if (m_loader) {
@@ -876,7 +691,7 @@ void XMLHttpRequest::abort()
dispatchAbortEvent();
if (!m_uploadComplete) {
m_uploadComplete = true;
- if (m_upload)
+ if (m_upload && m_uploadEventsAllowed)
m_upload->dispatchAbortEvent();
}
}
@@ -931,9 +746,10 @@ void XMLHttpRequest::networkError()
dispatchErrorEvent();
if (!m_uploadComplete) {
m_uploadComplete = true;
- if (m_upload)
+ if (m_upload && m_uploadEventsAllowed)
m_upload->dispatchErrorEvent();
}
+ internalAbort();
}
void XMLHttpRequest::abortError()
@@ -942,7 +758,7 @@ void XMLHttpRequest::abortError()
dispatchAbortEvent();
if (!m_uploadComplete) {
m_uploadComplete = true;
- if (m_upload)
+ if (m_upload && m_uploadEventsAllowed)
m_upload->dispatchAbortEvent();
}
}
@@ -1081,11 +897,6 @@ String XMLHttpRequest::getResponseHeader(const AtomicString& name, ExceptionCode
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);
@@ -1122,54 +933,36 @@ int XMLHttpRequest::status(ExceptionCode& ec) const
String XMLHttpRequest::statusText(ExceptionCode& ec) const
{
- // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=3547> XMLHttpRequest.statusText returns always "OK".
- if (m_response.httpStatusCode())
- return "OK";
+ if (!m_response.httpStatusText().isNull())
+ return m_response.httpStatusText();
if (m_state == OPENED) {
- // See comments in getStatus() above.
+ // See comments in status() above.
ec = INVALID_STATE_ERR;
}
return String();
}
-void XMLHttpRequest::processSyncLoadResults(unsigned long identifier, const Vector<char>& data, const ResourceResponse& response, ExceptionCode& ec)
-{
- if (m_sameOriginRequest && !scriptExecutionContext()->securityOrigin()->canRequest(response.url())) {
- abort();
- return;
- }
-
- didReceiveResponse(response);
- changeState(HEADERS_RECEIVED);
-
- const char* bytes = static_cast<const char*>(data.data());
- int len = static_cast<int>(data.size());
- didReceiveData(bytes, len);
-
- didFinishLoading(identifier);
- if (m_error)
- ec = XMLHttpRequestException::NETWORK_ERR;
-}
-
-void XMLHttpRequest::didFail()
+void XMLHttpRequest::didFail(const ResourceError& error)
{
// If we are already in an error state, for instance we called abort(), bail out early.
if (m_error)
return;
- internalAbort();
+ if (error.isCancellation()) {
+ m_exceptionCode = XMLHttpRequestException::ABORT_ERR;
+ abortError();
+ return;
+ }
+
+ m_exceptionCode = XMLHttpRequestException::NETWORK_ERR;
networkError();
}
-void XMLHttpRequest::didGetCancelled()
+void XMLHttpRequest::didFailRedirectCheck()
{
- // If we are already in an error state, for instance we called abort(), bail out early.
- if (m_error)
- return;
-
- abortError();
+ networkError();
}
void XMLHttpRequest::didFinishLoading(unsigned long identifier)
@@ -1219,31 +1012,14 @@ void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long lon
if (!m_upload)
return;
- m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
+ if (m_uploadEventsAllowed)
+ m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
m_uploadComplete = true;
- m_upload->dispatchLoadEvent();
- }
-}
-
-bool XMLHttpRequest::accessControlCheck(const ResourceResponse& response)
-{
- const String& accessControlOriginString = response.httpHeaderField("Access-Control-Origin");
- if (accessControlOriginString == "*" && !m_includeCredentials)
- return true;
-
- RefPtr<SecurityOrigin> accessControlOrigin = SecurityOrigin::createFromString(accessControlOriginString);
- if (!accessControlOrigin->isSameSchemeHostPort(scriptExecutionContext()->securityOrigin()))
- return false;
-
- if (m_includeCredentials) {
- const String& accessControlCredentialsString = response.httpHeaderField("Access-Control-Credentials");
- if (accessControlCredentialsString != "true")
- return false;
+ if (m_uploadEventsAllowed)
+ m_upload->dispatchLoadEvent();
}
-
- return true;
}
void XMLHttpRequest::didReceiveResponse(const ResourceResponse& response)
@@ -1254,7 +1030,7 @@ void XMLHttpRequest::didReceiveResponse(const ResourceResponse& response)
}
if (!m_sameOriginRequest) {
- if (!accessControlCheck(response)) {
+ if (!passesAccessControlCheck(response, m_includeCredentials, scriptExecutionContext()->securityOrigin())) {
networkError();
return;
}
@@ -1271,20 +1047,20 @@ void XMLHttpRequest::didReceiveResponsePreflight(const ResourceResponse& respons
ASSERT(m_inPreflight);
ASSERT(!m_sameOriginRequest);
- if (!accessControlCheck(response)) {
+ if (!passesAccessControlCheck(response, m_includeCredentials, scriptExecutionContext()->securityOrigin())) {
networkError();
return;
}
- OwnPtr<PreflightResultCacheItem> preflightResult(new PreflightResultCacheItem(m_includeCredentials));
+ OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult(new CrossOriginPreflightResultCacheItem(m_includeCredentials));
if (!preflightResult->parse(response)
- || !preflightResult->allowsCrossSiteMethod(m_method)
- || !preflightResult->allowsCrossSiteHeaders(m_requestHeaders)) {
+ || !preflightResult->allowsCrossOriginMethod(m_method)
+ || !preflightResult->allowsCrossOriginHeaders(m_requestHeaders)) {
networkError();
return;
}
- PreflightResultCache::shared().appendEntry(scriptExecutionContext()->securityOrigin()->toString(), m_url, preflightResult.release());
+ CrossOriginPreflightResultCache::shared().appendEntry(scriptExecutionContext()->securityOrigin()->toString(), m_url, preflightResult.release());
}
void XMLHttpRequest::didReceiveAuthenticationCancellation(const ResourceResponse& failureResponse)
@@ -1294,7 +1070,7 @@ void XMLHttpRequest::didReceiveAuthenticationCancellation(const ResourceResponse
void XMLHttpRequest::didReceiveData(const char* data, int len)
{
- if (m_inPreflight)
+ if (m_inPreflight || m_error)
return;
if (m_state < HEADERS_RECEIVED)
@@ -1304,13 +1080,16 @@ void XMLHttpRequest::didReceiveData(const char* data, int len)
if (!m_responseEncoding.isEmpty())
m_decoder = TextResourceDecoder::create("text/plain", m_responseEncoding);
// allow TextResourceDecoder to look inside the m_response if it's XML or HTML
- else if (responseIsXML())
+ else if (responseIsXML()) {
m_decoder = TextResourceDecoder::create("application/xml");
- else if (responseMIMEType() == "text/html")
+ // Don't stop on encoding errors, unlike it is done for other kinds of XML resources. This matches the behavior of previous WebKit versions, Firefox and Opera.
+ m_decoder->useLenientXMLDecoding();
+ } else if (responseMIMEType() == "text/html")
m_decoder = TextResourceDecoder::create("text/html", "UTF-8");
else
m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
}
+
if (!len)
return;
diff --git a/WebCore/xml/XMLHttpRequest.h b/WebCore/xml/XMLHttpRequest.h
index d7c0d36..544866a 100644
--- a/WebCore/xml/XMLHttpRequest.h
+++ b/WebCore/xml/XMLHttpRequest.h
@@ -34,7 +34,7 @@ namespace WebCore {
class Document;
class File;
-class ResourceRequest;
+struct ResourceRequest;
class TextResourceDecoder;
class ThreadableLoader;
@@ -129,15 +129,14 @@ private:
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 didFail(const ResourceError&);
+ virtual void didFailRedirectCheck();
virtual void didReceiveAuthenticationCancellation(const ResourceResponse&);
// Special versions for the preflight
void didReceiveResponsePreflight(const ResourceResponse&);
void didFinishLoadingPreflight();
- void processSyncLoadResults(unsigned long identifier, const Vector<char>& data, const ResourceResponse&, ExceptionCode&);
void updateAndDispatchOnProgress(unsigned int len);
String responseMIMEType() const;
@@ -159,21 +158,15 @@ private:
void createRequest(ExceptionCode&);
void makeSameOriginRequest(ExceptionCode&);
- void makeCrossSiteAccessRequest(ExceptionCode&);
+ void makeCrossOriginAccessRequest(ExceptionCode&);
- void makeSimpleCrossSiteAccessRequest(ExceptionCode&);
- void makeCrossSiteAccessRequestWithPreflight(ExceptionCode&);
+ void makeSimpleCrossOriginAccessRequest(ExceptionCode&);
+ void makeCrossOriginAccessRequestWithPreflight(ExceptionCode&);
void handleAsynchronousPreflightResult();
void loadRequestSynchronously(ResourceRequest&, ExceptionCode&);
void loadRequestAsynchronously(ResourceRequest&);
- bool isOnAccessControlResponseHeaderWhitelist(const String&) const;
-
- bool isSimpleCrossSiteAccessRequest() const;
- String accessControlOrigin() const;
- bool accessControlCheck(const ResourceResponse&);
-
void genericError();
void networkError();
void abortError();
@@ -202,7 +195,7 @@ private:
RefPtr<FormData> m_requestEntityBody;
String m_mimeTypeOverride;
bool m_async;
- bool m_includeCredentials;
+ bool m_includeCredentials; // FIXME: Currently, setting this flag is not implemented, so it is always false.
RefPtr<ThreadableLoader> m_loader;
State m_state;
@@ -224,6 +217,7 @@ private:
bool m_error;
+ bool m_uploadEventsAllowed;
bool m_uploadComplete;
bool m_sameOriginRequest;
@@ -235,6 +229,7 @@ private:
unsigned m_lastSendLineNumber;
String m_lastSendURL;
+ ExceptionCode m_exceptionCode;
};
} // namespace WebCore
diff --git a/WebCore/xml/XMLHttpRequest.idl b/WebCore/xml/XMLHttpRequest.idl
index 315d95c..3187160 100644
--- a/WebCore/xml/XMLHttpRequest.idl
+++ b/WebCore/xml/XMLHttpRequest.idl
@@ -29,7 +29,8 @@
module xml {
interface [
- CustomMarkFunction
+ CustomMarkFunction,
+ NoStaticTables
] XMLHttpRequest {
// From XMLHttpRequestEventTarget
// event handler attributes
diff --git a/WebCore/xml/XMLHttpRequestException.idl b/WebCore/xml/XMLHttpRequestException.idl
index 2feb574..706beb2 100644
--- a/WebCore/xml/XMLHttpRequestException.idl
+++ b/WebCore/xml/XMLHttpRequestException.idl
@@ -29,7 +29,8 @@
module xml {
interface [
- GenerateConstructor
+ GenerateConstructor,
+ NoStaticTables
] XMLHttpRequestException {
readonly attribute unsigned short code;
diff --git a/WebCore/xml/XMLHttpRequestProgressEvent.idl b/WebCore/xml/XMLHttpRequestProgressEvent.idl
index 6de9690..549308b 100644
--- a/WebCore/xml/XMLHttpRequestProgressEvent.idl
+++ b/WebCore/xml/XMLHttpRequestProgressEvent.idl
@@ -26,7 +26,8 @@
module events {
interface [
- GenerateConstructor
+ GenerateConstructor,
+ NoStaticTables
// We should also inherit from LSProgressEvent when the idl is added.
] XMLHttpRequestProgressEvent : ProgressEvent {
readonly attribute unsigned long position;
diff --git a/WebCore/xml/XMLHttpRequestUpload.cpp b/WebCore/xml/XMLHttpRequestUpload.cpp
index a58c271..d8a76d5 100644
--- a/WebCore/xml/XMLHttpRequestUpload.cpp
+++ b/WebCore/xml/XMLHttpRequestUpload.cpp
@@ -30,7 +30,6 @@
#include "Event.h"
#include "EventException.h"
#include "EventNames.h"
-#include "Frame.h"
#include "XMLHttpRequest.h"
#include "XMLHttpRequestProgressEvent.h"
#include <wtf/Assertions.h>
@@ -42,6 +41,11 @@ XMLHttpRequestUpload::XMLHttpRequestUpload(XMLHttpRequest* xmlHttpRequest)
{
}
+bool XMLHttpRequestUpload::hasListeners() const
+{
+ return m_onAbortListener || m_onErrorListener || m_onLoadListener || m_onLoadStartListener || m_onProgressListener || !m_eventListeners.isEmpty();
+}
+
ScriptExecutionContext* XMLHttpRequestUpload::scriptExecutionContext() const
{
XMLHttpRequest* xmlHttpRequest = associatedXMLHttpRequest();
diff --git a/WebCore/xml/XMLHttpRequestUpload.h b/WebCore/xml/XMLHttpRequestUpload.h
index 93fa7f9..b4f40e0 100644
--- a/WebCore/xml/XMLHttpRequestUpload.h
+++ b/WebCore/xml/XMLHttpRequestUpload.h
@@ -48,6 +48,8 @@ namespace WebCore {
return adoptRef(new XMLHttpRequestUpload(xmlHttpRequest));
}
+ bool hasListeners() const;
+
virtual XMLHttpRequestUpload* toXMLHttpRequestUpload() { return this; }
XMLHttpRequest* associatedXMLHttpRequest() const { return m_xmlHttpRequest; }
diff --git a/WebCore/xml/XMLHttpRequestUpload.idl b/WebCore/xml/XMLHttpRequestUpload.idl
index c066710..3172f68 100644
--- a/WebCore/xml/XMLHttpRequestUpload.idl
+++ b/WebCore/xml/XMLHttpRequestUpload.idl
@@ -30,7 +30,8 @@ module xml {
interface [
GenerateConstructor,
- CustomMarkFunction
+ CustomMarkFunction,
+ NoStaticTables
] XMLHttpRequestUpload {
// From XMLHttpRequestEventTarget
// event handler attributes
diff --git a/WebCore/xml/XPathExpression.cpp b/WebCore/xml/XPathExpression.cpp
index 446a7ad..ecec79e 100644
--- a/WebCore/xml/XPathExpression.cpp
+++ b/WebCore/xml/XPathExpression.cpp
@@ -67,9 +67,7 @@ PassRefPtr<XPathResult> XPathExpression::evaluate(Node* contextNode, unsigned sh
return 0;
}
- EventTargetNode* eventTarget = contextNode->ownerDocument()
- ? contextNode->ownerDocument()
- : static_cast<EventTargetNode*>(contextNode);
+ Node* eventTarget = contextNode->ownerDocument() ? contextNode->ownerDocument() : contextNode;
EvaluationContext& evaluationContext = Expression::evaluationContext();
evaluationContext.node = contextNode;
diff --git a/WebCore/xml/XPathFunctions.cpp b/WebCore/xml/XPathFunctions.cpp
index 841b436..3abd603 100644
--- a/WebCore/xml/XPathFunctions.cpp
+++ b/WebCore/xml/XPathFunctions.cpp
@@ -534,30 +534,30 @@ Value FunLang::evaluate() const
{
String lang = arg(0)->evaluate().toString();
- RefPtr<Node> langNode = 0;
+ Attribute* languageAttribute = 0;
Node* node = evaluationContext().node.get();
while (node) {
NamedAttrMap* attrs = node->attributes();
if (attrs)
- langNode = attrs->getNamedItemNS(XMLNames::xmlNamespaceURI, "lang");
- if (langNode)
+ languageAttribute = attrs->getAttributeItem(XMLNames::langAttr);
+ if (languageAttribute)
break;
node = node->parentNode();
}
- if (!langNode)
+ if (!languageAttribute)
return false;
- String langNodeValue = langNode->nodeValue();
+ String langValue = languageAttribute->value();
while (true) {
- if (equalIgnoringCase(langNodeValue, lang))
+ if (equalIgnoringCase(langValue, lang))
return true;
// Remove suffixes one by one.
- int index = langNodeValue.reverseFind('-');
+ int index = langValue.reverseFind('-');
if (index == -1)
break;
- langNodeValue = langNodeValue.left(index);
+ langValue = langValue.left(index);
}
return false;
diff --git a/WebCore/xml/XPathNodeSet.cpp b/WebCore/xml/XPathNodeSet.cpp
index e29c096..ba9423e 100644
--- a/WebCore/xml/XPathNodeSet.cpp
+++ b/WebCore/xml/XPathNodeSet.cpp
@@ -162,7 +162,7 @@ void NodeSet::sort() const
// It is not possible to just assign the result to m_nodes, because some nodes may get dereferenced and destroyed.
Vector<RefPtr<Node> > sortedNodes;
- sortedNodes.reserveCapacity(nodeCount);
+ sortedNodes.reserveInitialCapacity(nodeCount);
for (unsigned i = 0; i < nodeCount; ++i)
sortedNodes.append(parentMatrix[i][0]);
diff --git a/WebCore/xml/XPathResult.cpp b/WebCore/xml/XPathResult.cpp
index 285350e..a1c8a08 100644
--- a/WebCore/xml/XPathResult.cpp
+++ b/WebCore/xml/XPathResult.cpp
@@ -31,7 +31,7 @@
#include "EventListener.h"
#include "EventNames.h"
-#include "EventTargetNode.h"
+#include "Node.h"
#include "ExceptionCode.h"
#include "XPathEvaluator.h"
#include "XPathException.h"
@@ -50,7 +50,7 @@ private:
XPathResult* m_result;
};
-XPathResult::XPathResult(EventTargetNode* eventTarget, const Value& value)
+XPathResult::XPathResult(Node* eventTarget, const Value& value)
: m_value(value)
, m_eventTarget(eventTarget)
{
diff --git a/WebCore/xml/XPathResult.h b/WebCore/xml/XPathResult.h
index ecd5cac..03accc6 100644
--- a/WebCore/xml/XPathResult.h
+++ b/WebCore/xml/XPathResult.h
@@ -37,7 +37,7 @@ namespace WebCore {
typedef int ExceptionCode;
class EventListener;
- class EventTargetNode;
+ class Node;
class Node;
class String;
@@ -56,7 +56,7 @@ namespace WebCore {
FIRST_ORDERED_NODE_TYPE = 9
};
- static PassRefPtr<XPathResult> create(EventTargetNode* eventTarget, const XPath::Value& value) { return adoptRef(new XPathResult(eventTarget, value)); }
+ static PassRefPtr<XPathResult> create(Node* eventTarget, const XPath::Value& value) { return adoptRef(new XPathResult(eventTarget, value)); }
~XPathResult();
void convertTo(unsigned short type, ExceptionCode&);
@@ -76,14 +76,14 @@ namespace WebCore {
void invalidateIteratorState();
private:
- XPathResult(EventTargetNode*, const XPath::Value&);
+ XPathResult(Node*, const XPath::Value&);
XPath::Value m_value;
unsigned m_nodeSetPosition;
XPath::NodeSet m_nodeSet; // FIXME: why duplicate the node set stored in m_value?
unsigned short m_resultType;
bool m_invalidIteratorState;
- RefPtr<EventTargetNode> m_eventTarget;
+ RefPtr<Node> m_eventTarget;
RefPtr<EventListener> m_eventListener;
};
diff --git a/WebCore/xml/XPathStep.cpp b/WebCore/xml/XPathStep.cpp
index abdcba5..ae8d9c4 100644
--- a/WebCore/xml/XPathStep.cpp
+++ b/WebCore/xml/XPathStep.cpp
@@ -191,10 +191,10 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const
if (!attrs)
return;
- for (unsigned long i = 0; i < attrs->length(); ++i) {
- RefPtr<Node> n = attrs->item(i);
- if (nodeMatches(n.get()))
- nodes.append(n.release());
+ for (unsigned i = 0; i < attrs->length(); ++i) {
+ RefPtr<Attr> attr = attrs->attributeItem(i)->createAttrIfNeeded(static_cast<Element*>(context));
+ if (nodeMatches(attr.get()))
+ nodes.append(attr.release());
}
return;
}