diff options
Diffstat (limited to 'WebCore/xml')
-rw-r--r-- | WebCore/xml/XMLHttpRequest.cpp | 395 | ||||
-rw-r--r-- | WebCore/xml/XMLHttpRequest.h | 23 | ||||
-rw-r--r-- | WebCore/xml/XMLHttpRequest.idl | 3 | ||||
-rw-r--r-- | WebCore/xml/XMLHttpRequestException.idl | 3 | ||||
-rw-r--r-- | WebCore/xml/XMLHttpRequestProgressEvent.idl | 3 | ||||
-rw-r--r-- | WebCore/xml/XMLHttpRequestUpload.cpp | 6 | ||||
-rw-r--r-- | WebCore/xml/XMLHttpRequestUpload.h | 2 | ||||
-rw-r--r-- | WebCore/xml/XMLHttpRequestUpload.idl | 3 | ||||
-rw-r--r-- | WebCore/xml/XPathExpression.cpp | 4 | ||||
-rw-r--r-- | WebCore/xml/XPathFunctions.cpp | 16 | ||||
-rw-r--r-- | WebCore/xml/XPathNodeSet.cpp | 2 | ||||
-rw-r--r-- | WebCore/xml/XPathResult.cpp | 4 | ||||
-rw-r--r-- | WebCore/xml/XPathResult.h | 8 | ||||
-rw-r--r-- | WebCore/xml/XPathStep.cpp | 8 |
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; } |