summaryrefslogtreecommitdiffstats
path: root/WebCore/xml
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
commit1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch)
tree4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /WebCore/xml
parent9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff)
downloadexternal_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'WebCore/xml')
-rw-r--r--WebCore/xml/DOMParser.cpp5
-rw-r--r--WebCore/xml/DOMParser.h8
-rw-r--r--WebCore/xml/NativeXPathNSResolver.h7
-rw-r--r--WebCore/xml/XMLHttpRequest.cpp1156
-rw-r--r--WebCore/xml/XMLHttpRequest.h183
-rw-r--r--WebCore/xml/XMLHttpRequest.idl99
-rw-r--r--WebCore/xml/XMLHttpRequestException.h16
-rw-r--r--WebCore/xml/XMLHttpRequestException.idl1
-rw-r--r--WebCore/xml/XMLHttpRequestProgressEvent.h61
-rw-r--r--WebCore/xml/XMLHttpRequestProgressEvent.idl36
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.cpp144
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.h110
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.idl54
-rw-r--r--WebCore/xml/XMLSerializer.h6
-rw-r--r--WebCore/xml/XPathEvaluator.cpp2
-rw-r--r--WebCore/xml/XPathEvaluator.h7
-rw-r--r--WebCore/xml/XPathException.h16
-rw-r--r--WebCore/xml/XPathExpression.cpp4
-rw-r--r--WebCore/xml/XPathExpression.h6
-rw-r--r--WebCore/xml/XPathExpression.idl5
-rw-r--r--WebCore/xml/XPathExpressionNode.h3
-rw-r--r--WebCore/xml/XPathFunctions.cpp6
-rw-r--r--WebCore/xml/XPathGrammar.y2
-rw-r--r--WebCore/xml/XPathNSResolver.h3
-rw-r--r--WebCore/xml/XPathParser.cpp12
-rw-r--r--WebCore/xml/XPathResult.cpp12
-rw-r--r--WebCore/xml/XPathResult.h4
-rw-r--r--WebCore/xml/XPathUtil.cpp34
-rw-r--r--WebCore/xml/XPathValue.cpp2
-rw-r--r--WebCore/xml/XPathValue.h30
-rw-r--r--WebCore/xml/XSLImportRule.cpp21
-rw-r--r--WebCore/xml/XSLImportRule.h30
-rw-r--r--WebCore/xml/XSLStyleSheet.cpp30
-rw-r--r--WebCore/xml/XSLStyleSheet.h27
-rw-r--r--WebCore/xml/XSLTProcessor.cpp71
-rw-r--r--WebCore/xml/XSLTProcessor.h32
-rw-r--r--WebCore/xml/XSLTProcessor.idl52
-rw-r--r--WebCore/xml/XSLTUnicodeSort.cpp84
-rw-r--r--WebCore/xml/XSLTUnicodeSort.h2
-rw-r--r--WebCore/xml/xmlattrs.in3
40 files changed, 1796 insertions, 590 deletions
diff --git a/WebCore/xml/DOMParser.cpp b/WebCore/xml/DOMParser.cpp
index 8be4d14..448dcb1 100644
--- a/WebCore/xml/DOMParser.cpp
+++ b/WebCore/xml/DOMParser.cpp
@@ -1,6 +1,5 @@
/*
- * This file is part of the KDE libraries
- * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,7 +29,7 @@ PassRefPtr<Document> DOMParser::parseFromString(const String& str, const String&
if (!DOMImplementation::isXMLMIMEType(contentType))
return 0;
- RefPtr<Document> doc = DOMImplementation::instance()->createDocument(contentType, 0, false);
+ RefPtr<Document> doc = DOMImplementation::createDocument(contentType, 0, false);
doc->open();
doc->write(str);
diff --git a/WebCore/xml/DOMParser.h b/WebCore/xml/DOMParser.h
index 2097a6e..5036d22 100644
--- a/WebCore/xml/DOMParser.h
+++ b/WebCore/xml/DOMParser.h
@@ -1,5 +1,4 @@
/*
- * This file is part of the KDE libraries
* Copyright (C) 2003, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -24,12 +23,19 @@
#include "Document.h"
namespace WebCore {
+
class String;
class DOMParser : public RefCounted<DOMParser> {
public:
+ static PassRefPtr<DOMParser> create() { return adoptRef(new DOMParser); }
+
PassRefPtr<Document> parseFromString(const String& str, const String& contentType);
+
+ private:
+ DOMParser() { }
};
+
}
#endif // XMLSerializer.h
diff --git a/WebCore/xml/NativeXPathNSResolver.h b/WebCore/xml/NativeXPathNSResolver.h
index c3070d8..212b929 100644
--- a/WebCore/xml/NativeXPathNSResolver.h
+++ b/WebCore/xml/NativeXPathNSResolver.h
@@ -29,21 +29,20 @@
#if ENABLE(XPATH)
#include "XPathNSResolver.h"
-#include <wtf/Forward.h>
+#include "Node.h"
#include <wtf/RefPtr.h>
namespace WebCore {
- class Node;
-
class NativeXPathNSResolver : public XPathNSResolver {
public:
- NativeXPathNSResolver(PassRefPtr<Node>);
+ static PassRefPtr<NativeXPathNSResolver> create(PassRefPtr<Node> node) { return adoptRef(new NativeXPathNSResolver(node)); }
virtual ~NativeXPathNSResolver();
virtual String lookupNamespaceURI(const String& prefix);
private:
+ NativeXPathNSResolver(PassRefPtr<Node>);
RefPtr<Node> m_node;
};
diff --git a/WebCore/xml/XMLHttpRequest.cpp b/WebCore/xml/XMLHttpRequest.cpp
index 7413f72..67aba0b 100644
--- a/WebCore/xml/XMLHttpRequest.cpp
+++ b/WebCore/xml/XMLHttpRequest.cpp
@@ -1,8 +1,7 @@
/*
- * This file is part of the KDE libraries
- * Copyright (C) 2004, 2006 Apple Computer, Inc.
+ * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
- * Copyright (C) 2007 Julien Chaffraix <julien.chaffraix@gmail.com>
+ * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,78 +22,75 @@
#include "XMLHttpRequest.h"
#include "CString.h"
-#include "Cache.h"
+#include "Console.h"
#include "DOMImplementation.h"
+#include "DOMWindow.h"
#include "Event.h"
#include "EventException.h"
#include "EventListener.h"
#include "EventNames.h"
-#include "ExceptionCode.h"
-#include "FormData.h"
+#include "File.h"
#include "Frame.h"
#include "FrameLoader.h"
-#include "HTMLDocument.h"
#include "HTTPParsers.h"
+#include "InspectorController.h"
+#include "JSDOMBinding.h"
+#include "JSDOMWindow.h"
+#include "KURL.h"
+#include "KURLHash.h"
#include "Page.h"
-#include "PlatformString.h"
-#include "RegularExpression.h"
-#include "ResourceHandle.h"
-#include "ResourceRequest.h"
#include "Settings.h"
#include "SubresourceLoader.h"
-#include "TextEncoding.h"
+#include "SystemTime.h"
#include "TextResourceDecoder.h"
#include "XMLHttpRequestException.h"
-#include "kjs_binding.h"
-#include <kjs/protect.h>
-#include <wtf/Vector.h>
+#include "XMLHttpRequestProgressEvent.h"
+#include "XMLHttpRequestUpload.h"
+#include "markup.h"
+#include <runtime/JSLock.h>
namespace WebCore {
-using namespace EventNames;
+struct PreflightResultCacheItem {
+ PreflightResultCacheItem(unsigned expiryDelta, bool credentials, HashSet<String>* methods, HashSet<String, CaseFoldingHash>* headers)
+ : m_absoluteExpiryTime(currentTime() + expiryDelta)
+ , m_credentials(credentials)
+ , m_methods(methods)
+ , m_headers(headers)
+ {
+ }
-typedef HashSet<XMLHttpRequest*> RequestsSet;
+ // 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;
+};
-static HashMap<Document*, RequestsSet*>& requestsByDocument()
-{
- static HashMap<Document*, RequestsSet*> map;
- return map;
-}
+typedef HashMap<std::pair<String, KURL>, PreflightResultCacheItem*> PreflightResultCache;
-static void addToRequestsByDocument(Document* doc, XMLHttpRequest* req)
+static PreflightResultCache& preflightResultCache()
{
- ASSERT(doc);
- ASSERT(req);
-
- RequestsSet* requests = requestsByDocument().get(doc);
- if (!requests) {
- requests = new RequestsSet;
- requestsByDocument().set(doc, requests);
- }
-
- ASSERT(!requests->contains(req));
- requests->add(req);
+ static PreflightResultCache cache;
+ return cache;
}
-static void removeFromRequestsByDocument(Document* doc, XMLHttpRequest* req)
+static void appendPreflightResultCacheEntry(String origin, KURL url, unsigned expiryDelta,
+ bool credentials, HashSet<String>* methods, HashSet<String, CaseFoldingHash>* headers)
{
- ASSERT(doc);
- ASSERT(req);
+ ASSERT(!preflightResultCache().contains(std::make_pair(origin, url)));
- RequestsSet* requests = requestsByDocument().get(doc);
- ASSERT(requests);
- ASSERT(requests->contains(req));
- requests->remove(req);
- if (requests->isEmpty()) {
- requestsByDocument().remove(doc);
- delete requests;
- }
+ PreflightResultCacheItem* item = new PreflightResultCacheItem(expiryDelta, credentials, methods, headers);
+ preflightResultCache().set(std::make_pair(origin, url), item);
}
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");
@@ -114,7 +110,28 @@ static bool isSafeRequestHeader(const String& name)
forbiddenHeaders.add("via");
}
- return !forbiddenHeaders.contains(name) && !name.startsWith(proxyString, false);
+ return !forbiddenHeaders.contains(name) && !name.startsWith(proxyString, false) &&
+ !name.startsWith(secString, false);
+}
+
+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
@@ -145,20 +162,50 @@ static bool isValidHeaderValue(const String& name)
return !name.contains('\r') && !name.contains('\n');
}
-
-XMLHttpRequestState XMLHttpRequest::getReadyState() const
+
+XMLHttpRequest::XMLHttpRequest(Document* doc)
+ : ActiveDOMObject(doc, 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)
+ , m_uploadComplete(false)
+ , m_sameOriginRequest(true)
+ , m_inPreflight(false)
+ , m_receivedLength(0)
+ , m_lastSendLineNumber(0)
+{
+ ASSERT(document());
+}
+
+XMLHttpRequest::~XMLHttpRequest()
+{
+ if (m_upload)
+ m_upload->disconnectXMLHttpRequest();
+}
+
+Document* XMLHttpRequest::document() const
+{
+ ASSERT(scriptExecutionContext()->isDocument());
+ return static_cast<Document*>(scriptExecutionContext());
+}
+
+XMLHttpRequest::State XMLHttpRequest::readyState() const
{
return m_state;
}
-const KJS::UString& XMLHttpRequest::getResponseText(ExceptionCode& ec) const
+const JSC::UString& XMLHttpRequest::responseText() const
{
return m_responseText;
}
-Document* XMLHttpRequest::getResponseXML(ExceptionCode& ec) const
+Document* XMLHttpRequest::responseXML() const
{
- if (m_state != Loaded)
+ if (m_state != DONE)
return 0;
if (!m_createdDocument) {
@@ -166,9 +213,9 @@ Document* XMLHttpRequest::getResponseXML(ExceptionCode& ec) const
// The W3C spec requires this.
m_responseXML = 0;
} else {
- m_responseXML = m_doc->implementation()->createDocument(0);
+ m_responseXML = document()->implementation()->createDocument(0);
m_responseXML->open();
- m_responseXML->setURL(m_url.deprecatedString());
+ m_responseXML->setURL(m_url);
// FIXME: set Last-Modified and cookies (currently, those are only available for HTMLDocuments).
m_responseXML->write(String(m_responseText));
m_responseXML->finishParsing();
@@ -183,33 +230,20 @@ Document* XMLHttpRequest::getResponseXML(ExceptionCode& ec) const
return m_responseXML.get();
}
-EventListener* XMLHttpRequest::onReadyStateChangeListener() const
-{
- return m_onReadyStateChangeListener.get();
-}
-
-void XMLHttpRequest::setOnReadyStateChangeListener(EventListener* eventListener)
-{
- m_onReadyStateChangeListener = eventListener;
-}
-
-EventListener* XMLHttpRequest::onLoadListener() const
-{
- return m_onLoadListener.get();
-}
-
-void XMLHttpRequest::setOnLoadListener(EventListener* eventListener)
+XMLHttpRequestUpload* XMLHttpRequest::upload()
{
- m_onLoadListener = eventListener;
+ if (!m_upload)
+ m_upload = XMLHttpRequestUpload::create(this);
+ return m_upload.get();
}
void XMLHttpRequest::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool)
{
- EventListenersMap::iterator iter = m_eventListeners.find(eventType.impl());
+ EventListenersMap::iterator iter = m_eventListeners.find(eventType);
if (iter == m_eventListeners.end()) {
ListenerVector listeners;
listeners.append(eventListener);
- m_eventListeners.add(eventType.impl(), listeners);
+ m_eventListeners.add(eventType, listeners);
} else {
ListenerVector& listeners = iter->second;
for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter)
@@ -217,13 +251,13 @@ void XMLHttpRequest::addEventListener(const AtomicString& eventType, PassRefPtr<
return;
listeners.append(eventListener);
- m_eventListeners.add(eventType.impl(), listeners);
+ m_eventListeners.add(eventType, listeners);
}
}
void XMLHttpRequest::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool)
{
- EventListenersMap::iterator iter = m_eventListeners.find(eventType.impl());
+ EventListenersMap::iterator iter = m_eventListeners.find(eventType);
if (iter == m_eventListeners.end())
return;
@@ -235,7 +269,7 @@ void XMLHttpRequest::removeEventListener(const AtomicString& eventType, EventLis
}
}
-bool XMLHttpRequest::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec, bool /*tempEvent*/)
+bool XMLHttpRequest::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec)
{
// FIXME: check for other error conditions enumerated in the spec.
if (evt->type().isEmpty()) {
@@ -243,7 +277,7 @@ bool XMLHttpRequest::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec, boo
return true;
}
- ListenerVector listenersCopy = m_eventListeners.get(evt->type().impl());
+ ListenerVector listenersCopy = m_eventListeners.get(evt->type());
for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) {
evt->setTarget(this);
evt->setCurrentTarget(this);
@@ -253,25 +287,7 @@ bool XMLHttpRequest::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec, boo
return !evt->defaultPrevented();
}
-XMLHttpRequest::XMLHttpRequest(Document* d)
- : m_doc(d)
- , m_async(true)
- , m_state(Uninitialized)
- , m_responseText("")
- , m_createdDocument(false)
- , m_aborted(false)
-{
- ASSERT(m_doc);
- addToRequestsByDocument(m_doc, this);
-}
-
-XMLHttpRequest::~XMLHttpRequest()
-{
- if (m_doc)
- removeFromRequestsByDocument(m_doc, this);
-}
-
-void XMLHttpRequest::changeState(XMLHttpRequestState newState)
+void XMLHttpRequest::changeState(State newState)
{
if (m_state != newState) {
m_state = newState;
@@ -281,73 +297,29 @@ void XMLHttpRequest::changeState(XMLHttpRequestState newState)
void XMLHttpRequest::callReadyStateChangeListener()
{
- if (!m_doc || !m_doc->frame())
+ if (!document() || !document()->frame())
return;
- RefPtr<Event> evt = new Event(readystatechangeEvent, false, false);
- if (m_onReadyStateChangeListener) {
- evt->setTarget(this);
- evt->setCurrentTarget(this);
- m_onReadyStateChangeListener->handleEvent(evt.get(), false);
- }
-
- ExceptionCode ec = 0;
- dispatchEvent(evt.release(), ec, false);
- ASSERT(!ec);
-
- if (m_state == Loaded) {
- evt = new Event(loadEvent, false, false);
- if (m_onLoadListener) {
- evt->setTarget(this);
- evt->setCurrentTarget(this);
- m_onLoadListener->handleEvent(evt.get(), false);
- }
-
- dispatchEvent(evt, ec, false);
- ASSERT(!ec);
- }
-}
-
-bool XMLHttpRequest::urlMatchesDocumentDomain(const KURL& url) const
-{
- // a local file can load anything
- if (m_doc->isAllowedToLoadLocalResources())
-#ifdef ANDROID_FILE_SECURITY
- if (FrameLoader::shouldTreatURLAsLocal(url.string()))
-#endif
- return true;
-
- // but a remote document can only load from the same port on the server
- KURL documentURL = m_doc->url();
- if (documentURL.protocol().lower() == url.protocol().lower()
- && documentURL.host().lower() == url.host().lower()
- && documentURL.port() == url.port())
- return true;
+ dispatchReadyStateChangeEvent();
- return false;
+ if (m_state == DONE)
+ dispatchLoadEvent();
}
void XMLHttpRequest::open(const String& method, const KURL& url, bool async, ExceptionCode& ec)
{
- abort();
- m_aborted = false;
+ internalAbort();
+ State previousState = m_state;
+ m_state = UNSENT;
+ m_error = false;
+
+ m_uploadComplete = false;
// clear stuff from possible previous load
- m_requestHeaders.clear();
- m_response = ResourceResponse();
- {
- KJS::JSLock lock;
- m_responseText = "";
- }
- m_createdDocument = false;
- m_responseXML = 0;
+ clearResponse();
+ clearRequest();
- ASSERT(m_state == Uninitialized);
-
- if (!urlMatchesDocumentDomain(url)) {
- ec = XMLHttpRequestException::PERMISSION_DENIED;
- return;
- }
+ ASSERT(m_state == UNSENT);
if (!isValidToken(method)) {
ec = SYNTAX_ERR;
@@ -358,7 +330,7 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, Exc
String methodUpper(method.upper());
if (methodUpper == "TRACE" || methodUpper == "TRACK" || methodUpper == "CONNECT") {
- ec = XMLHttpRequestException::PERMISSION_DENIED;
+ ec = SECURITY_ERR;
return;
}
@@ -368,19 +340,26 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, Exc
|| methodUpper == "INDEX" || methodUpper == "LOCK" || methodUpper == "M-POST" || methodUpper == "MKCOL" || methodUpper == "MOVE"
|| methodUpper == "OPTIONS" || methodUpper == "POST" || methodUpper == "PROPFIND" || methodUpper == "PROPPATCH" || methodUpper == "PUT"
|| methodUpper == "UNLOCK")
- m_method = methodUpper.deprecatedString();
+ m_method = methodUpper;
else
- m_method = method.deprecatedString();
+ m_method = method;
m_async = async;
- changeState(Open);
+ ASSERT(!m_loader);
+
+ // Check previous state to avoid dispatching readyState event
+ // when calling open several times in a row.
+ if (previousState != OPENED)
+ changeState(OPENED);
+ else
+ m_state = OPENED;
}
void XMLHttpRequest::open(const String& method, const KURL& url, bool async, const String& user, ExceptionCode& ec)
{
KURL urlWithCredentials(url);
- urlWithCredentials.setUser(user.deprecatedString());
+ urlWithCredentials.setUser(user);
open(method, urlWithCredentials, async, ec);
}
@@ -388,105 +367,395 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, con
void XMLHttpRequest::open(const String& method, const KURL& url, bool async, const String& user, const String& password, ExceptionCode& ec)
{
KURL urlWithCredentials(url);
- urlWithCredentials.setUser(user.deprecatedString());
- urlWithCredentials.setPass(password.deprecatedString());
+ urlWithCredentials.setUser(user);
+ urlWithCredentials.setPass(password);
open(method, urlWithCredentials, async, ec);
}
-void XMLHttpRequest::send(const String& body, ExceptionCode& ec)
+bool XMLHttpRequest::initSend(ExceptionCode& ec)
{
- if (!m_doc)
- return;
+ if (!document())
+ return false;
- if (m_state != Open) {
+ if (m_state != OPENED || m_loader) {
ec = INVALID_STATE_ERR;
- return;
+ return false;
}
-
- // FIXME: Should this abort or raise an exception instead if we already have a m_loader going?
- if (m_loader)
+
+ m_error = false;
+ return true;
+}
+
+void XMLHttpRequest::send(ExceptionCode& ec)
+{
+ send(String(), ec);
+}
+
+void XMLHttpRequest::send(Document* document, ExceptionCode& ec)
+{
+ ASSERT(document);
+
+ if (!initSend(ec))
return;
- m_aborted = false;
+ if (m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
+ String contentType = getRequestHeader("Content-Type");
+ if (contentType.isEmpty()) {
+#if ENABLE(DASHBOARD_SUPPORT)
+ Settings* settings = document->settings();
+ if (settings && settings->usesDashboardBackwardCompatibilityMode())
+ setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
+ else
+#endif
+ // FIXME: this should include the charset used for encoding.
+ setRequestHeaderInternal("Content-Type", "application/xml");
+ }
- ResourceRequest request(m_url);
- request.setHTTPMethod(m_method);
-
- if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && (m_url.protocol().lower() == "http" || m_url.protocol().lower() == "https")) {
+ // FIXME: According to XMLHttpRequest Level 2, this should use the Document.innerHTML algorithm
+ // from the HTML5 specification to serialize the document.
+ String body = createMarkup(document);
+
+ // FIXME: this should use value of document.inputEncoding to determine the encoding to use.
+ TextEncoding encoding = UTF8Encoding();
+ m_requestEntityBody = FormData::create(encoding.encode(body.characters(), body.length(), EntitiesForUnencodables));
+ if (m_upload)
+ m_requestEntityBody->setAlwaysStream(true);
+ }
+
+ createRequest(ec);
+}
+
+void XMLHttpRequest::send(const String& body, ExceptionCode& ec)
+{
+ if (!initSend(ec))
+ return;
+
+ if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
String contentType = getRequestHeader("Content-Type");
if (contentType.isEmpty()) {
- ExceptionCode ec = 0;
- Settings* settings = m_doc->settings();
+#if ENABLE(DASHBOARD_SUPPORT)
+ Settings* settings = document()->settings();
if (settings && settings->usesDashboardBackwardCompatibilityMode())
- setRequestHeader("Content-Type", "application/x-www-form-urlencoded", ec);
+ setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
else
- setRequestHeader("Content-Type", "application/xml", ec);
- ASSERT(ec == 0);
+#endif
+ setRequestHeaderInternal("Content-Type", "application/xml");
}
- // FIXME: must use xmlEncoding for documents.
- String charset = "UTF-8";
-
- TextEncoding m_encoding(charset);
- if (!m_encoding.isValid()) // FIXME: report an error?
- m_encoding = UTF8Encoding();
+ m_requestEntityBody = FormData::create(UTF8Encoding().encode(body.characters(), body.length(), EntitiesForUnencodables));
+ if (m_upload)
+ m_requestEntityBody->setAlwaysStream(true);
+ }
+
+ createRequest(ec);
+}
- request.setHTTPBody(PassRefPtr<FormData>(new FormData(m_encoding.encode(body.characters(), body.length()))));
+void XMLHttpRequest::send(File* body, ExceptionCode& ec)
+{
+ if (!initSend(ec))
+ return;
+
+ if (m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
+ // FIXME: Should we set a Content-Type if one is not set.
+ // FIXME: add support for uploading bundles.
+ m_requestEntityBody = FormData::create();
+ m_requestEntityBody->appendFile(body->path(), false);
}
+ createRequest(ec);
+}
+
+void XMLHttpRequest::createRequest(ExceptionCode& ec)
+{
+ if (m_async) {
+ dispatchLoadStartEvent();
+ if (m_requestEntityBody && m_upload)
+ m_upload->dispatchLoadStartEvent();
+ }
+
+ m_sameOriginRequest = document()->securityOrigin()->canRequest(m_url);
+
+ if (!m_sameOriginRequest) {
+ makeCrossSiteAccessRequest(ec);
+ return;
+ }
+
+ makeSameOriginRequest(ec);
+}
+
+void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec)
+{
+ ASSERT(m_sameOriginRequest);
+
+ ResourceRequest request(m_url);
+ request.setHTTPMethod(m_method);
+
+ if (m_requestEntityBody) {
+ ASSERT(m_method != "GET");
+ request.setHTTPBody(m_requestEntityBody.release());
+ }
+
+ if (m_requestHeaders.size() > 0)
+ request.addHTTPHeaderFields(m_requestHeaders);
+
+ if (m_async)
+ loadRequestAsynchronously(request);
+ else
+ 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)
+{
+ ASSERT(!m_sameOriginRequest);
+
+ if (isSimpleCrossSiteAccessRequest())
+ makeSimpleCrossSiteAccessRequest(ec);
+ else
+ makeCrossSiteAccessRequestWithPreflight(ec);
+}
+
+void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec)
+{
+ ASSERT(isSimpleCrossSiteAccessRequest());
+
+ KURL url = m_url;
+ url.setUser(String());
+ url.setPass(String());
+
+ ResourceRequest request(url);
+ request.setHTTPMethod(m_method);
+ request.setAllowHTTPCookies(m_includeCredentials);
+ request.setHTTPOrigin(document()->securityOrigin()->toString());
+
if (m_requestHeaders.size() > 0)
request.addHTTPHeaderFields(m_requestHeaders);
- if (!m_async) {
- Vector<char> data;
- ResourceError error;
- ResourceResponse response;
+ if (m_async)
+ loadRequestAsynchronously(request);
+ else
+ 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;
+}
- {
- // avoid deadlock in case the loader wants to use JS on a background thread
- KJS::JSLock::DropAllLocks dropLocks;
- if (m_doc->frame())
- m_doc->frame()->loader()->loadResourceSynchronously(request, error, response, data);
+void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec)
+{
+ String origin = document()->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);
}
+ }
- 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);
- else
- ec = XMLHttpRequestException::NETWORK_ERR;
+ if (!skipPreflight) {
+ m_inPreflight = true;
+ ResourceRequest preflightRequest(url);
+ preflightRequest.setHTTPMethod("OPTIONS");
+ preflightRequest.setHTTPHeaderField("Origin", origin);
+ preflightRequest.setHTTPHeaderField("Access-Control-Request-Method", m_method);
+
+ if (m_requestHeaders.size() > 0) {
+ Vector<UChar> headerBuffer;
+ HTTPHeaderMap::const_iterator it = m_requestHeaders.begin();
+ append(headerBuffer, it->first);
+ ++it;
+
+ HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
+ for (; it != end; ++it) {
+ headerBuffer.append(',');
+ headerBuffer.append(' ');
+ append(headerBuffer, it->first);
+ }
+
+ preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", String::adopt(headerBuffer));
+ preflightRequest.addHTTPHeaderFields(m_requestHeaders);
+ }
+
+ if (m_async) {
+ loadRequestAsynchronously(preflightRequest);
+ return;
+ }
+
+ loadRequestSynchronously(preflightRequest, ec);
+ m_inPreflight = false;
+
+ if (ec)
+ return;
+ }
+
+ // Send the actual request.
+ ResourceRequest request(url);
+ request.setHTTPMethod(m_method);
+ request.setAllowHTTPCookies(m_includeCredentials);
+ request.setHTTPHeaderField("Origin", origin);
+
+ if (m_requestHeaders.size() > 0)
+ request.addHTTPHeaderFields(m_requestHeaders);
+
+ if (m_requestEntityBody) {
+ ASSERT(m_method != "GET");
+ request.setHTTPBody(m_requestEntityBody.release());
+ }
+
+ if (m_async) {
+ loadRequestAsynchronously(request);
+ return;
+ }
+
+ loadRequestSynchronously(request, ec);
+}
+
+void XMLHttpRequest::handleAsynchronousPreflightResult()
+{
+ ASSERT(m_inPreflight);
+ ASSERT(m_async);
+
+ m_inPreflight = false;
+
+ KURL url = m_url;
+ url.setUser(String());
+ url.setPass(String());
+
+ ResourceRequest request(url);
+ request.setHTTPMethod(m_method);
+ request.setAllowHTTPCookies(m_includeCredentials);
+ request.setHTTPOrigin(document()->securityOrigin()->toString());
+
+ if (m_requestHeaders.size() > 0)
+ request.addHTTPHeaderFields(m_requestHeaders);
+ if (m_requestEntityBody) {
+ ASSERT(m_method != "GET");
+ request.setHTTPBody(m_requestEntityBody.release());
+ }
+
+ loadRequestAsynchronously(request);
+}
+
+void XMLHttpRequest::loadRequestSynchronously(ResourceRequest& request, ExceptionCode& ec)
+{
+ ASSERT(!m_async);
+ Vector<char> data;
+ ResourceError error;
+ ResourceResponse response;
+
+ if (document()->frame())
+ m_identifier = document()->frame()->loader()->loadResourceSynchronously(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);
+ return;
+ }
+
+ if (error.isCancellation()) {
+ abortError();
+ ec = XMLHttpRequestException::ABORT_ERR;
return;
}
+ networkError();
+ ec = XMLHttpRequestException::NETWORK_ERR;
+}
+
+
+void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request)
+{
+ ASSERT(m_async);
// 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>.
// 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>.
- m_loader = SubresourceLoader::create(m_doc->frame(), this, request, false, true, request.url().isLocalFile());
+ bool sendResourceLoadCallbacks = !m_inPreflight;
+ m_loader = SubresourceLoader::create(document()->frame(), this, request, false, sendResourceLoadCallbacks, request.url().isLocalFile());
if (m_loader) {
// Neither this object nor the JavaScript wrapper should be deleted while
// a request is in progress because we need to keep the listeners alive,
// and they are referenced by the JavaScript wrapper.
- ref();
-
- KJS::JSLock lock;
- KJS::gcProtectNullTolerant(KJS::ScriptInterpreter::getDOMObject(this));
+ setPendingActivity(this);
}
}
void XMLHttpRequest::abort()
{
- bool hadLoader = m_loader;
+ bool sendFlag = m_loader;
+
+ internalAbort();
- m_aborted = true;
+ // Clear headers as required by the spec
+ m_requestHeaders.clear();
+ if ((m_state <= OPENED && !sendFlag) || m_state == DONE)
+ m_state = UNSENT;
+ else {
+ ASSERT(!m_loader);
+ changeState(DONE);
+ m_state = UNSENT;
+ }
+
+ dispatchAbortEvent();
+ if (!m_uploadComplete) {
+ m_uploadComplete = true;
+ if (m_upload)
+ m_upload->dispatchAbortEvent();
+ }
+}
+
+void XMLHttpRequest::internalAbort()
+{
+ bool hadLoader = m_loader;
+
+ m_error = true;
+
+ // FIXME: when we add the support for multi-part XHR, we will have to think be careful with this initialization.
+ m_receivedLength = 0;
+
if (hadLoader) {
m_loader->cancel();
m_loader = 0;
@@ -496,42 +765,87 @@ void XMLHttpRequest::abort()
if (hadLoader)
dropProtection();
+}
+
+void XMLHttpRequest::clearResponse()
+{
+ m_response = ResourceResponse();
+ {
+ JSC::JSLock lock(false);
+ m_responseText = "";
+ }
+ m_createdDocument = false;
+ m_responseXML = 0;
+}
+
+void XMLHttpRequest::clearRequest()
+{
+ m_requestHeaders.clear();
+ m_requestEntityBody = 0;
+}
+
+void XMLHttpRequest::genericError()
+{
+ clearResponse();
+ clearRequest();
+ m_error = true;
- m_state = Uninitialized;
+ // The spec says we should "Synchronously switch the state to DONE." and then "Synchronously dispatch a readystatechange event on the object"
+ // but this does not match Firefox.
+}
+
+void XMLHttpRequest::networkError()
+{
+ genericError();
+ dispatchErrorEvent();
+ if (!m_uploadComplete) {
+ m_uploadComplete = true;
+ if (m_upload)
+ m_upload->dispatchErrorEvent();
+ }
+}
+
+void XMLHttpRequest::abortError()
+{
+ genericError();
+ dispatchAbortEvent();
+ if (!m_uploadComplete) {
+ m_uploadComplete = true;
+ if (m_upload)
+ m_upload->dispatchAbortEvent();
+ }
}
void XMLHttpRequest::dropProtection()
{
- {
- KJS::JSLock lock;
- KJS::JSValue* wrapper = KJS::ScriptInterpreter::getDOMObject(this);
- KJS::gcUnprotectNullTolerant(wrapper);
-
- // 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
- // out. But it is protected from GC while loading, so this
- // can't be recouped until the load is done, so only
- // report the extra cost at that point.
-
- if (wrapper)
- KJS::Collector::reportExtraMemoryCost(m_responseText.size() * 2);
+ // 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
+ // out. But it is protected from GC while loading, so this
+ // 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);
}
- deref();
+ unsetPendingActivity(this);
}
-void XMLHttpRequest::overrideMIMEType(const String& override)
+void XMLHttpRequest::overrideMimeType(const String& override)
{
m_mimeTypeOverride = override;
}
void XMLHttpRequest::setRequestHeader(const String& name, const String& value, ExceptionCode& ec)
{
- if (m_state != Open) {
- Settings* settings = m_doc ? m_doc->settings() : 0;
+ if (m_state != OPENED || m_loader) {
+#if ENABLE(DASHBOARD_SUPPORT)
+ Settings* settings = document() ? document()->settings() : 0;
if (settings && settings->usesDashboardBackwardCompatibilityMode())
return;
+#endif
ec = INVALID_STATE_ERR;
return;
@@ -541,21 +855,22 @@ void XMLHttpRequest::setRequestHeader(const String& name, const String& value, E
ec = SYNTAX_ERR;
return;
}
-
+
// A privileged script (e.g. a Dashboard widget) can set any headers.
- if (!m_doc->isAllowedToLoadLocalResources() && !isSafeRequestHeader(name)) {
- if (m_doc && m_doc->frame() && m_doc->frame()->page())
- m_doc->frame()->page()->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, "Refused to set unsafe header " + name, 1, String());
+ 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());
return;
}
- if (!m_requestHeaders.contains(name)) {
- m_requestHeaders.set(name, value);
- return;
- }
-
- String oldValue = m_requestHeaders.get(name);
- m_requestHeaders.set(name, oldValue + ", " + value);
+ setRequestHeaderInternal(name, value);
+}
+
+void XMLHttpRequest::setRequestHeaderInternal(const String& 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
@@ -565,7 +880,7 @@ String XMLHttpRequest::getRequestHeader(const String& name) const
String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const
{
- if (m_state < Receiving) {
+ if (m_state < LOADING) {
ec = INVALID_STATE_ERR;
return "";
}
@@ -575,6 +890,9 @@ String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const
HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it!= end; ++it) {
+ if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->first))
+ continue;
+
stringBuilder.append(it->first.characters(), it->first.length());
stringBuilder.append(separator.characters(), separator.length());
stringBuilder.append(it->second.characters(), it->second.length());
@@ -587,7 +905,7 @@ String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const
String XMLHttpRequest::getResponseHeader(const String& name, ExceptionCode& ec) const
{
- if (m_state < Receiving) {
+ if (m_state < LOADING) {
ec = INVALID_STATE_ERR;
return "";
}
@@ -595,6 +913,9 @@ String XMLHttpRequest::getResponseHeader(const String& name, ExceptionCode& ec)
if (!isValidToken(name))
return "";
+ if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name))
+ return "";
+
return m_response.httpHeaderField(name);
}
@@ -618,102 +939,251 @@ bool XMLHttpRequest::responseIsXML() const
return DOMImplementation::isXMLMIMEType(responseMIMEType());
}
-int XMLHttpRequest::getStatus(ExceptionCode& ec) const
+int XMLHttpRequest::status(ExceptionCode& ec) const
{
- if (m_state == Uninitialized)
- return 0;
-
- if (m_response.httpStatusCode() == 0) {
- if (m_state != Receiving && m_state != Loaded)
- // status MUST be available in these states, but we don't get any headers from non-HTTP requests
- ec = INVALID_STATE_ERR;
+ if (m_response.httpStatusCode())
+ return m_response.httpStatusCode();
+
+ if (m_state == OPENED) {
+ // Firefox only raises an exception in this state; we match it.
+ // Note the case of local file requests, where we have no HTTP response code! Firefox never raises an exception for those, but we match HTTP case for consistency.
+ ec = INVALID_STATE_ERR;
}
- return m_response.httpStatusCode();
+ return 0;
}
-String XMLHttpRequest::getStatusText(ExceptionCode& ec) const
+String XMLHttpRequest::statusText(ExceptionCode& ec) const
{
- if (m_state == Uninitialized)
- return "";
-
- if (m_response.httpStatusCode() == 0) {
- if (m_state != Receiving && m_state != Loaded)
- // statusText MUST be available in these states, but we don't get any headers from non-HTTP requests
- ec = INVALID_STATE_ERR;
- return String();
+ // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=3547> XMLHttpRequest.statusText returns always "OK".
+ if (m_response.httpStatusCode())
+ return "OK";
+
+ if (m_state == OPENED) {
+ // See comments in getStatus() above.
+ ec = INVALID_STATE_ERR;
}
- // FIXME: should try to preserve status text in response
- return "OK";
+ return String();
}
-void XMLHttpRequest::processSyncLoadResults(const Vector<char>& data, const ResourceResponse& response)
+void XMLHttpRequest::processSyncLoadResults(const Vector<char>& data, const ResourceResponse& response, ExceptionCode& ec)
{
- if (!urlMatchesDocumentDomain(response.url())) {
+ if (m_sameOriginRequest && !document()->securityOrigin()->canRequest(response.url())) {
abort();
return;
}
-
+
didReceiveResponse(0, response);
- changeState(Sent);
- if (m_aborted)
- return;
+ changeState(HEADERS_RECEIVED);
const char* bytes = static_cast<const char*>(data.data());
int len = static_cast<int>(data.size());
-
didReceiveData(0, bytes, len);
- if (m_aborted)
- return;
didFinishLoading(0);
+ if (m_error)
+ ec = XMLHttpRequestException::NETWORK_ERR;
}
-void XMLHttpRequest::didFail(SubresourceLoader* loader, const ResourceError&)
+void XMLHttpRequest::didFail(SubresourceLoader* loader, const ResourceError& error)
{
- didFinishLoading(loader);
+ // If we are already in an error state, for instance we called abort(), bail out early.
+ if (m_error)
+ return;
+
+ if (error.isCancellation()) {
+ abortError();
+ return;
+ }
+
+ networkError();
+ return;
}
void XMLHttpRequest::didFinishLoading(SubresourceLoader* loader)
{
- if (m_aborted)
+ if (m_error)
return;
-
+
+ if (m_inPreflight) {
+ didFinishLoadingPreflight(loader);
+ return;
+ }
+
ASSERT(loader == m_loader);
- if (m_state < Sent)
- changeState(Sent);
+ if (m_state < HEADERS_RECEIVED)
+ changeState(HEADERS_RECEIVED);
{
- KJS::JSLock lock;
+ JSC::JSLock lock(false);
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);
+ }
+ }
+
bool hadLoader = m_loader;
m_loader = 0;
- changeState(Loaded);
+ changeState(DONE);
m_decoder = 0;
if (hadLoader)
dropProtection();
}
+void XMLHttpRequest::didFinishLoadingPreflight(SubresourceLoader* loader)
+{
+ ASSERT(m_inPreflight);
+ ASSERT(!m_sameOriginRequest);
+
+ // FIXME: this can probably be moved to didReceiveResponsePreflight.
+ if (m_async)
+ handleAsynchronousPreflightResult();
+
+ if (m_loader)
+ unsetPendingActivity(this);
+}
+
void XMLHttpRequest::willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
- if (!urlMatchesDocumentDomain(request.url()))
- abort();
+ // 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::didReceiveResponse(SubresourceLoader*, const ResourceResponse& response)
+void XMLHttpRequest::didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
+ if (!m_upload)
+ return;
+
+ 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;
+
+ KURL accessControlOriginURL(accessControlOriginString);
+ if (!accessControlOriginURL.isValid())
+ return false;
+
+ RefPtr<SecurityOrigin> accessControlOrigin = SecurityOrigin::create(accessControlOriginURL);
+ if (!accessControlOrigin->isSameSchemeHostPort(document()->securityOrigin()))
+ return false;
+
+ if (m_includeCredentials) {
+ const String& accessControlCredentialsString = response.httpHeaderField("Access-Control-Credentials");
+ if (accessControlCredentialsString != "true")
+ return false;
+ }
+
+ return true;
+}
+
+void XMLHttpRequest::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
+{
+ if (m_inPreflight) {
+ didReceiveResponsePreflight(loader, response);
+ return;
+ }
+
+ if (!m_sameOriginRequest) {
+ if (!accessControlCheck(response)) {
+ networkError();
+ return;
+ }
+ }
+
m_response = response;
- m_encoding = extractCharsetFromMediaType(m_mimeTypeOverride);
- if (m_encoding.isEmpty())
- m_encoding = response.textEncodingName();
+ m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
+ if (m_responseEncoding.isEmpty())
+ 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)
+{
+ ASSERT(m_inPreflight);
+ ASSERT(!m_sameOriginRequest);
+
+ if (!accessControlCheck(response)) {
+ networkError();
+ 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())) {
+ 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());
}
void XMLHttpRequest::receivedCancellation(SubresourceLoader*, const AuthenticationChallenge& challenge)
@@ -723,19 +1193,22 @@ void XMLHttpRequest::receivedCancellation(SubresourceLoader*, const Authenticati
void XMLHttpRequest::didReceiveData(SubresourceLoader*, const char* data, int len)
{
- if (m_state < Sent)
- changeState(Sent);
+ if (m_inPreflight)
+ return;
+
+ if (m_state < HEADERS_RECEIVED)
+ changeState(HEADERS_RECEIVED);
if (!m_decoder) {
- if (!m_encoding.isEmpty())
- m_decoder = new TextResourceDecoder("text/plain", m_encoding);
+ 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())
- m_decoder = new TextResourceDecoder("application/xml");
+ m_decoder = TextResourceDecoder::create("application/xml");
else if (responseMIMEType() == "text/html")
- m_decoder = new TextResourceDecoder("text/html", "UTF-8");
+ m_decoder = TextResourceDecoder::create("text/html", "UTF-8");
else
- m_decoder = new TextResourceDecoder("text/plain", "UTF-8");
+ m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
}
if (len == 0)
return;
@@ -746,42 +1219,99 @@ void XMLHttpRequest::didReceiveData(SubresourceLoader*, const char* data, int le
String decoded = m_decoder->decode(data, len);
{
- KJS::JSLock lock;
+ JSC::JSLock lock(false);
m_responseText += decoded;
}
- if (!m_aborted) {
- if (m_state != Receiving)
- changeState(Receiving);
+ if (!m_error) {
+ updateAndDispatchOnProgress(len);
+
+ if (m_state != LOADING)
+ changeState(LOADING);
else
// Firefox calls readyStateChanged every time it receives data, 4449442
callReadyStateChangeListener();
}
}
-void XMLHttpRequest::cancelRequests(Document* m_doc)
+void XMLHttpRequest::updateAndDispatchOnProgress(unsigned int len)
{
- RequestsSet* requests = requestsByDocument().get(m_doc);
- if (!requests)
- return;
- RequestsSet copy = *requests;
- RequestsSet::const_iterator end = copy.end();
- for (RequestsSet::const_iterator it = copy.begin(); it != end; ++it)
- (*it)->abort();
+ long long expectedLength = m_response.expectedContentLength();
+ m_receivedLength += len;
+
+ // FIXME: the spec requires that we dispatch the event according to the least
+ // frequent method between every 350ms (+/-200ms) and for every byte received.
+ dispatchProgressEvent(expectedLength);
}
-void XMLHttpRequest::detachRequests(Document* m_doc)
+void XMLHttpRequest::dispatchReadyStateChangeEvent()
{
- RequestsSet* requests = requestsByDocument().get(m_doc);
- if (!requests)
- return;
- requestsByDocument().remove(m_doc);
- RequestsSet::const_iterator end = requests->end();
- for (RequestsSet::const_iterator it = requests->begin(); it != end; ++it) {
- (*it)->m_doc = 0;
- (*it)->abort();
+ RefPtr<Event> evt = Event::create(eventNames().readystatechangeEvent, false, false);
+ if (m_onReadyStateChangeListener) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ m_onReadyStateChangeListener->handleEvent(evt.get(), false);
}
- delete requests;
+
+ ExceptionCode ec = 0;
+ dispatchEvent(evt.release(), ec);
+ ASSERT(!ec);
+}
+
+void XMLHttpRequest::dispatchXMLHttpRequestProgressEvent(EventListener* listener, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+{
+ RefPtr<XMLHttpRequestProgressEvent> evt = XMLHttpRequestProgressEvent::create(type, lengthComputable, loaded, total);
+ if (listener) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ listener->handleEvent(evt.get(), false);
+ }
+
+ ExceptionCode ec = 0;
+ dispatchEvent(evt.release(), ec);
+ ASSERT(!ec);
+}
+
+void XMLHttpRequest::dispatchAbortEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onAbortListener.get(), eventNames().abortEvent, false, 0, 0);
+}
+
+void XMLHttpRequest::dispatchErrorEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onErrorListener.get(), eventNames().errorEvent, false, 0, 0);
+}
+
+void XMLHttpRequest::dispatchLoadEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onLoadListener.get(), eventNames().loadEvent, false, 0, 0);
+}
+
+void XMLHttpRequest::dispatchLoadStartEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onLoadStartListener.get(), eventNames().loadstartEvent, false, 0, 0);
+}
+
+void XMLHttpRequest::dispatchProgressEvent(long long expectedLength)
+{
+ dispatchXMLHttpRequestProgressEvent(m_onProgressListener.get(), eventNames().progressEvent, expectedLength && m_receivedLength <= expectedLength,
+ static_cast<unsigned>(m_receivedLength), static_cast<unsigned>(expectedLength));
+}
+
+void XMLHttpRequest::stop()
+{
+ internalAbort();
+}
+
+void XMLHttpRequest::contextDestroyed()
+{
+ ActiveDOMObject::contextDestroyed();
+ internalAbort();
+}
+
+ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const
+{
+ return ActiveDOMObject::scriptExecutionContext();
}
-} // end namespace
+} // namespace WebCore
diff --git a/WebCore/xml/XMLHttpRequest.h b/WebCore/xml/XMLHttpRequest.h
index 6a22c31..6962ab1 100644
--- a/WebCore/xml/XMLHttpRequest.h
+++ b/WebCore/xml/XMLHttpRequest.h
@@ -1,7 +1,5 @@
-// -*- c-basic-offset: 2 -*-
/*
- * This file is part of the KDE libraries
- * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2005, 2006 Alexey Proskuryakov <ap@nypop.com>
*
* This library is free software; you can redistribute it and/or
@@ -22,136 +20,211 @@
#ifndef XMLHttpRequest_h
#define XMLHttpRequest_h
+#include "ActiveDOMObject.h"
+#include "AtomicStringHash.h"
+#include "EventListener.h"
#include "EventTarget.h"
-#include "HTTPHeaderMap.h"
-#include "KURL.h"
-#include "PlatformString.h"
+#include "FormData.h"
#include "ResourceResponse.h"
-#include "StringHash.h"
#include "SubresourceLoaderClient.h"
-#include <kjs/ustring.h>
-
-#include <wtf/HashMap.h>
-#include <wtf/Vector.h>
+#include <wtf/OwnPtr.h>
namespace WebCore {
-class TextResourceDecoder;
class Document;
-class Event;
-class EventListener;
-class String;
-
-typedef int ExceptionCode;
-
-// these exact numeric values are important because JS expects them
-enum XMLHttpRequestState {
- Uninitialized = 0, // The initial value.
- Open = 1, // The open() method has been successfully called.
- Sent = 2, // The user agent successfully completed the request, but no data has yet been received.
- Receiving = 3, // Immediately before receiving the message body (if any). All HTTP headers have been received.
- Loaded = 4 // The data transfer has been completed.
-};
+class File;
+class TextResourceDecoder;
-class XMLHttpRequest : public RefCounted<XMLHttpRequest>, public EventTarget, private SubresourceLoaderClient {
+class XMLHttpRequest : public RefCounted<XMLHttpRequest>, public EventTarget, private SubresourceLoaderClient, public ActiveDOMObject {
public:
- XMLHttpRequest(Document*);
+ static PassRefPtr<XMLHttpRequest> create(Document* document) { return adoptRef(new XMLHttpRequest(document)); }
~XMLHttpRequest();
+ // These exact numeric values are important because JS expects them.
+ enum State {
+ UNSENT = 0,
+ OPENED = 1,
+ HEADERS_RECEIVED = 2,
+ LOADING = 3,
+ DONE = 4
+ };
+
virtual XMLHttpRequest* toXMLHttpRequest() { return this; }
- static void detachRequests(Document*);
- static void cancelRequests(Document*);
+ virtual void contextDestroyed();
+ virtual void stop();
+
+ virtual ScriptExecutionContext* scriptExecutionContext() const;
- String getStatusText(ExceptionCode&) const;
- int getStatus(ExceptionCode&) const;
- XMLHttpRequestState getReadyState() const;
+ String statusText(ExceptionCode&) const;
+ int status(ExceptionCode&) const;
+ State readyState() const;
void open(const String& method, const KURL&, bool async, ExceptionCode&);
void open(const String& method, const KURL&, bool async, const String& user, ExceptionCode&);
void open(const String& method, const KURL&, bool async, const String& user, const String& password, ExceptionCode&);
- void send(const String& body, ExceptionCode&);
+ void send(ExceptionCode&);
+ void send(Document*, ExceptionCode&);
+ void send(const String&, ExceptionCode&);
+ void send(File*, ExceptionCode&);
void abort();
void setRequestHeader(const String& name, const String& value, ExceptionCode&);
- void overrideMIMEType(const String& override);
+ void overrideMimeType(const String& override);
String getAllResponseHeaders(ExceptionCode&) const;
String getResponseHeader(const String& name, ExceptionCode&) const;
- const KJS::UString& getResponseText(ExceptionCode&) const;
- Document* getResponseXML(ExceptionCode&) const;
+ const JSC::UString& responseText() const;
+ Document* responseXML() const;
+ void setLastSendLineNumber(unsigned lineNumber) { m_lastSendLineNumber = lineNumber; }
+ void setLastSendURL(JSC::UString url) { m_lastSendURL = url; }
- void setOnReadyStateChangeListener(EventListener*);
- EventListener* onReadyStateChangeListener() const;
- void setOnLoadListener(EventListener*);
- EventListener* onLoadListener() const;
+ XMLHttpRequestUpload* upload();
+ XMLHttpRequestUpload* optionalUpload() const { return m_upload.get(); }
+
+ void setOnreadystatechange(PassRefPtr<EventListener> eventListener) { m_onReadyStateChangeListener = eventListener; }
+ EventListener* onreadystatechange() const { return m_onReadyStateChangeListener.get(); }
+
+ void setOnabort(PassRefPtr<EventListener> eventListener) { m_onAbortListener = eventListener; }
+ EventListener* onabort() const { return m_onAbortListener.get(); }
+
+ void setOnerror(PassRefPtr<EventListener> eventListener) { m_onErrorListener = eventListener; }
+ EventListener* onerror() const { return m_onErrorListener.get(); }
+
+ void setOnload(PassRefPtr<EventListener> eventListener) { m_onLoadListener = eventListener; }
+ EventListener* onload() const { return m_onLoadListener.get(); }
+
+ void setOnloadstart(PassRefPtr<EventListener> eventListener) { m_onLoadStartListener = eventListener; }
+ EventListener* onloadstart() const { return m_onLoadStartListener.get(); }
+
+ void setOnprogress(PassRefPtr<EventListener> eventListener) { m_onProgressListener = eventListener; }
+ EventListener* onprogress() const { return m_onProgressListener.get(); }
typedef Vector<RefPtr<EventListener> > ListenerVector;
- typedef HashMap<AtomicStringImpl*, ListenerVector> EventListenersMap;
+ typedef HashMap<AtomicString, ListenerVector> EventListenersMap;
// useCapture is not used, even for add/remove pairing (for Firefox compatibility).
virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
- virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&, bool tempEvent = false);
+ virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&);
EventListenersMap& eventListeners() { return m_eventListeners; }
- Document* document() const { return m_doc; }
-
using RefCounted<XMLHttpRequest>::ref;
using RefCounted<XMLHttpRequest>::deref;
private:
+ XMLHttpRequest(Document*);
+
virtual void refEventTarget() { ref(); }
virtual void derefEventTarget() { deref(); }
- bool urlMatchesDocumentDomain(const KURL&) const;
+ 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&);
- void processSyncLoadResults(const Vector<char>& data, const ResourceResponse&);
+ // Special versions for the preflight
+ void didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse&);
+ void didFinishLoadingPreflight(SubresourceLoader*);
+
+ void processSyncLoadResults(const Vector<char>& data, const ResourceResponse&, ExceptionCode&);
+ void updateAndDispatchOnProgress(unsigned int len);
String responseMIMEType() const;
bool responseIsXML() const;
+ bool initSend(ExceptionCode&);
+
String getRequestHeader(const String& name) const;
+ void setRequestHeaderInternal(const String& name, const String& value);
- void changeState(XMLHttpRequestState newState);
+ void changeState(State newState);
void callReadyStateChangeListener();
void dropProtection();
+ void internalAbort();
+ void clearResponse();
+ void clearRequest();
+
+ void createRequest(ExceptionCode&);
+
+ void makeSameOriginRequest(ExceptionCode&);
+ void makeCrossSiteAccessRequest(ExceptionCode&);
+
+ void makeSimpleCrossSiteAccessRequest(ExceptionCode&);
+ void makeCrossSiteAccessRequestWithPreflight(ExceptionCode&);
+ void handleAsynchronousPreflightResult();
+
+ void loadRequestSynchronously(ResourceRequest&, ExceptionCode&);
+ void loadRequestAsynchronously(ResourceRequest&);
- Document* m_doc;
+ bool isSimpleCrossSiteAccessRequest() const;
+ String accessControlOrigin() const;
+ bool accessControlCheck(const ResourceResponse&);
+
+ void genericError();
+ void networkError();
+ void abortError();
+
+ void dispatchReadyStateChangeEvent();
+ void dispatchXMLHttpRequestProgressEvent(EventListener* listener, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total);
+ void dispatchAbortEvent();
+ void dispatchErrorEvent();
+ void dispatchLoadEvent();
+ void dispatchLoadStartEvent();
+ void dispatchProgressEvent(long long expectedLength);
RefPtr<EventListener> m_onReadyStateChangeListener;
+ RefPtr<EventListener> m_onAbortListener;
+ RefPtr<EventListener> m_onErrorListener;
RefPtr<EventListener> m_onLoadListener;
+ RefPtr<EventListener> m_onLoadStartListener;
+ RefPtr<EventListener> m_onProgressListener;
EventListenersMap m_eventListeners;
+ RefPtr<XMLHttpRequestUpload> m_upload;
+
KURL m_url;
- DeprecatedString m_method;
+ String m_method;
HTTPHeaderMap m_requestHeaders;
+ RefPtr<FormData> m_requestEntityBody;
String m_mimeTypeOverride;
bool m_async;
+ bool m_includeCredentials;
RefPtr<SubresourceLoader> m_loader;
- XMLHttpRequestState m_state;
+ State m_state;
ResourceResponse m_response;
- String m_encoding;
+ String m_responseEncoding;
RefPtr<TextResourceDecoder> m_decoder;
+ unsigned long m_identifier;
- // Unlike most strings in the DOM, we keep this as a KJS::UString, not a WebCore::String.
+ // Unlike most strings in the DOM, we keep this as a JSC::UString, 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.
- KJS::UString m_responseText;
+ JSC::UString m_responseText;
mutable bool m_createdDocument;
mutable RefPtr<Document> m_responseXML;
- bool m_aborted;
+ bool m_error;
+
+ bool m_uploadComplete;
+
+ bool m_sameOriginRequest;
+ bool m_allowAccess;
+ bool m_inPreflight;
+
+ // Used for onprogress tracking
+ long long m_receivedLength;
+
+ unsigned m_lastSendLineNumber;
+ JSC::UString m_lastSendURL;
};
} // namespace WebCore
diff --git a/WebCore/xml/XMLHttpRequest.idl b/WebCore/xml/XMLHttpRequest.idl
new file mode 100644
index 0000000..fa6b9ca
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequest.idl
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module xml {
+
+ interface [
+ CustomMarkFunction
+ ] XMLHttpRequest {
+ // From XMLHttpRequestEventTarget
+ // event handler attributes
+ attribute EventListener onabort;
+ attribute EventListener onerror;
+ attribute EventListener onload;
+ attribute EventListener onloadstart;
+ attribute EventListener onprogress;
+
+ // event handler attributes
+ attribute EventListener onreadystatechange;
+
+ // state
+ const unsigned short UNSENT = 0;
+ const unsigned short OPENED = 1;
+ const unsigned short HEADERS_RECEIVED = 2;
+ const unsigned short LOADING = 3;
+ const unsigned short DONE = 4;
+
+ readonly attribute unsigned short readyState;
+
+ // request
+ // void open(in DOMString method, in DOMString url);
+ // void open(in DOMString method, in DOMString url, in boolean async);
+ // void open(in DOMString method, in DOMString url, in boolean async, in DOMString user);
+ [Custom] void open(in DOMString method, in DOMString url, in boolean async, in DOMString user, in DOMString password)
+ raises(DOMException);
+
+ [Custom] void setRequestHeader(in DOMString header, in DOMString value)
+ raises(DOMException);
+
+ // void send();
+ // void send(in DOMString data);
+ [Custom] void send(in Document data)
+ raises(DOMException);
+
+ void abort();
+
+ readonly attribute XMLHttpRequestUpload upload;
+
+ // response
+ [ConvertNullStringTo=Undefined] DOMString getAllResponseHeaders()
+ raises(DOMException);
+ [Custom, ConvertNullStringTo=Null] DOMString getResponseHeader(in DOMString header)
+ raises(DOMException);
+ readonly attribute [ConvertNullStringTo=Null] DOMString responseText;
+ readonly attribute Document responseXML;
+ readonly attribute unsigned short status
+ getter raises(DOMException);
+ readonly attribute DOMString statusText
+ getter raises(DOMException);
+
+ // Extension
+ [Custom] void overrideMimeType(in DOMString override);
+
+ // EventTarget interface
+ [Custom] void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ [Custom] void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ boolean dispatchEvent(in Event evt)
+ raises(EventException);
+ };
+
+}
diff --git a/WebCore/xml/XMLHttpRequestException.h b/WebCore/xml/XMLHttpRequestException.h
index 1540d4b..737cab0 100644
--- a/WebCore/xml/XMLHttpRequestException.h
+++ b/WebCore/xml/XMLHttpRequestException.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,18 +35,24 @@ namespace WebCore {
class XMLHttpRequestException : public ExceptionBase {
public:
- XMLHttpRequestException(const ExceptionCodeDescription& description)
- : ExceptionBase(description)
+ static PassRefPtr<XMLHttpRequestException> create(const ExceptionCodeDescription& description)
{
+ return adoptRef(new XMLHttpRequestException(description));
}
static const int XMLHttpRequestExceptionOffset = 500;
static const int XMLHttpRequestExceptionMax = 699;
enum XMLHttpRequestExceptionCode {
- PERMISSION_DENIED = XMLHttpRequestExceptionOffset, // Use SECURITY_ERR when that's in DOM Core, http://bugs.webkit.org/show_bug.cgi?id=12182
- NETWORK_ERR = XMLHttpRequestExceptionOffset + 101
+ NETWORK_ERR = XMLHttpRequestExceptionOffset + 101,
+ ABORT_ERR
};
+
+ private:
+ XMLHttpRequestException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
};
} // namespace WebCore
diff --git a/WebCore/xml/XMLHttpRequestException.idl b/WebCore/xml/XMLHttpRequestException.idl
index e6aa182..2feb574 100644
--- a/WebCore/xml/XMLHttpRequestException.idl
+++ b/WebCore/xml/XMLHttpRequestException.idl
@@ -43,6 +43,7 @@ module xml {
// XMLHttpRequestExceptionCode
const unsigned short NETWORK_ERR = 101;
+ const unsigned short ABORT_ERR = 102;
};
}
diff --git a/WebCore/xml/XMLHttpRequestProgressEvent.h b/WebCore/xml/XMLHttpRequestProgressEvent.h
new file mode 100644
index 0000000..02bfdea
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestProgressEvent.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Julien Chaffraix <jchaffraix@webkit.org>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XMLHttpRequestProgressEvent_h
+#define XMLHttpRequestProgressEvent_h
+
+#include "ProgressEvent.h"
+
+namespace WebCore {
+
+ class XMLHttpRequestProgressEvent : public ProgressEvent {
+ public:
+ static PassRefPtr<XMLHttpRequestProgressEvent> create()
+ {
+ return adoptRef(new XMLHttpRequestProgressEvent);
+ }
+ static PassRefPtr<XMLHttpRequestProgressEvent> create(const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+ {
+ return adoptRef(new XMLHttpRequestProgressEvent(type, lengthComputable, loaded, total));
+ }
+
+ virtual bool isXMLHttpRequestProgressEvent() const { return true; }
+
+ // Those 2 methods are to be compatible with Firefox and are only a wrapper on top of the real implementation.
+ unsigned position() const { return loaded(); }
+ unsigned totalSize() const { return total(); }
+
+ private:
+ XMLHttpRequestProgressEvent() { }
+ XMLHttpRequestProgressEvent(const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+ : ProgressEvent(type, lengthComputable, loaded, total)
+ {
+ }
+ };
+
+} // namespace WebCore
+
+#endif // XMLHttpRequestProgressEvent_h
diff --git a/WebCore/xml/XMLHttpRequestProgressEvent.idl b/WebCore/xml/XMLHttpRequestProgressEvent.idl
new file mode 100644
index 0000000..6de9690
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestProgressEvent.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module events {
+
+ interface [
+ GenerateConstructor
+ // We should also inherit from LSProgressEvent when the idl is added.
+ ] XMLHttpRequestProgressEvent : ProgressEvent {
+ readonly attribute unsigned long position;
+ readonly attribute unsigned long totalSize;
+ };
+
+}
diff --git a/WebCore/xml/XMLHttpRequestUpload.cpp b/WebCore/xml/XMLHttpRequestUpload.cpp
new file mode 100644
index 0000000..cef1798
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestUpload.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XMLHttpRequestUpload.h"
+
+#include "AtomicString.h"
+#include "Event.h"
+#include "EventException.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "XMLHttpRequest.h"
+#include "XMLHttpRequestProgressEvent.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+XMLHttpRequestUpload::XMLHttpRequestUpload(XMLHttpRequest* xmlHttpRequest)
+ : m_xmlHttpRequest(xmlHttpRequest)
+{
+}
+
+ScriptExecutionContext* XMLHttpRequestUpload::scriptExecutionContext() const
+{
+ XMLHttpRequest* xmlHttpRequest = associatedXMLHttpRequest();
+ if (!xmlHttpRequest)
+ return 0;
+ return xmlHttpRequest->scriptExecutionContext();
+}
+
+void XMLHttpRequestUpload::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool)
+{
+ EventListenersMap::iterator iter = m_eventListeners.find(eventType);
+ if (iter == m_eventListeners.end()) {
+ ListenerVector listeners;
+ listeners.append(eventListener);
+ m_eventListeners.add(eventType, listeners);
+ } else {
+ ListenerVector& listeners = iter->second;
+ for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) {
+ if (*listenerIter == eventListener)
+ return;
+ }
+
+ listeners.append(eventListener);
+ m_eventListeners.add(eventType, listeners);
+ }
+}
+
+void XMLHttpRequestUpload::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool)
+{
+ EventListenersMap::iterator iter = m_eventListeners.find(eventType);
+ if (iter == m_eventListeners.end())
+ return;
+
+ ListenerVector& listeners = iter->second;
+ for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) {
+ if (*listenerIter == eventListener) {
+ listeners.remove(listenerIter - listeners.begin());
+ return;
+ }
+ }
+}
+
+bool XMLHttpRequestUpload::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec)
+{
+ // FIXME: check for other error conditions enumerated in the spec.
+ if (evt->type().isEmpty()) {
+ ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
+ return true;
+ }
+
+ ListenerVector listenersCopy = m_eventListeners.get(evt->type());
+ for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ listenerIter->get()->handleEvent(evt.get(), false);
+ }
+
+ return !evt->defaultPrevented();
+}
+
+void XMLHttpRequestUpload::dispatchXMLHttpRequestProgressEvent(EventListener* listener, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+{
+ RefPtr<XMLHttpRequestProgressEvent> evt = XMLHttpRequestProgressEvent::create(type, lengthComputable, loaded, total);
+ if (listener) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ listener->handleEvent(evt.get(), false);
+ }
+
+ ExceptionCode ec = 0;
+ dispatchEvent(evt.release(), ec);
+ ASSERT(!ec);
+}
+
+void XMLHttpRequestUpload::dispatchAbortEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onAbortListener.get(), eventNames().abortEvent, false, 0, 0);
+}
+
+void XMLHttpRequestUpload::dispatchErrorEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onErrorListener.get(), eventNames().errorEvent, false, 0, 0);
+}
+
+void XMLHttpRequestUpload::dispatchLoadEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onLoadListener.get(), eventNames().loadEvent, false, 0, 0);
+}
+
+void XMLHttpRequestUpload::dispatchLoadStartEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onLoadStartListener.get(), eventNames().loadstartEvent, false, 0, 0);
+}
+
+void XMLHttpRequestUpload::dispatchProgressEvent(long long bytesSent, long long totalBytesToBeSent)
+{
+ dispatchXMLHttpRequestProgressEvent(m_onProgressListener.get(), eventNames().progressEvent, true, static_cast<unsigned>(bytesSent), static_cast<unsigned>(totalBytesToBeSent));
+}
+
+} // namespace WebCore
diff --git a/WebCore/xml/XMLHttpRequestUpload.h b/WebCore/xml/XMLHttpRequestUpload.h
new file mode 100644
index 0000000..93fa7f9
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestUpload.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XMLHttpRequestUpload_h
+#define XMLHttpRequestUpload_h
+
+#include "AtomicStringHash.h"
+#include "EventListener.h"
+#include "EventTarget.h"
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class AtomicStringImpl;
+ class ScriptExecutionContext;
+ class XMLHttpRequest;
+
+ class XMLHttpRequestUpload : public RefCounted<XMLHttpRequestUpload>, public EventTarget {
+ public:
+ static PassRefPtr<XMLHttpRequestUpload> create(XMLHttpRequest* xmlHttpRequest)
+ {
+ return adoptRef(new XMLHttpRequestUpload(xmlHttpRequest));
+ }
+
+ virtual XMLHttpRequestUpload* toXMLHttpRequestUpload() { return this; }
+
+ XMLHttpRequest* associatedXMLHttpRequest() const { return m_xmlHttpRequest; }
+ void disconnectXMLHttpRequest() { m_xmlHttpRequest = 0; }
+
+ ScriptExecutionContext* scriptExecutionContext() const;
+
+ void dispatchAbortEvent();
+ void dispatchErrorEvent();
+ void dispatchLoadEvent();
+ void dispatchLoadStartEvent();
+ void dispatchProgressEvent(long long bytesSent, long long totalBytesToBeSent);
+
+ void setOnabort(PassRefPtr<EventListener> eventListener) { m_onAbortListener = eventListener; }
+ EventListener* onabort() const { return m_onAbortListener.get(); }
+
+ void setOnerror(PassRefPtr<EventListener> eventListener) { m_onErrorListener = eventListener; }
+ EventListener* onerror() const { return m_onErrorListener.get(); }
+
+ void setOnload(PassRefPtr<EventListener> eventListener) { m_onLoadListener = eventListener; }
+ EventListener* onload() const { return m_onLoadListener.get(); }
+
+ void setOnloadstart(PassRefPtr<EventListener> eventListener) { m_onLoadStartListener = eventListener; }
+ EventListener* onloadstart() const { return m_onLoadStartListener.get(); }
+
+ void setOnprogress(PassRefPtr<EventListener> eventListener) { m_onProgressListener = eventListener; }
+ EventListener* onprogress() const { return m_onProgressListener.get(); }
+
+ typedef Vector<RefPtr<EventListener> > ListenerVector;
+ typedef HashMap<AtomicString, ListenerVector> EventListenersMap;
+
+ virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+ virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
+ virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&);
+ EventListenersMap& eventListeners() { return m_eventListeners; }
+
+ using RefCounted<XMLHttpRequestUpload>::ref;
+ using RefCounted<XMLHttpRequestUpload>::deref;
+
+ private:
+ XMLHttpRequestUpload(XMLHttpRequest*);
+
+ void dispatchXMLHttpRequestProgressEvent(EventListener*, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total);
+
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+
+ RefPtr<EventListener> m_onAbortListener;
+ RefPtr<EventListener> m_onErrorListener;
+ RefPtr<EventListener> m_onLoadListener;
+ RefPtr<EventListener> m_onLoadStartListener;
+ RefPtr<EventListener> m_onProgressListener;
+ EventListenersMap m_eventListeners;
+
+ XMLHttpRequest* m_xmlHttpRequest;
+ };
+
+} // namespace WebCore
+
+#endif // XMLHttpRequestUpload_h
diff --git a/WebCore/xml/XMLHttpRequestUpload.idl b/WebCore/xml/XMLHttpRequestUpload.idl
new file mode 100644
index 0000000..c066710
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestUpload.idl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module xml {
+
+ interface [
+ GenerateConstructor,
+ CustomMarkFunction
+ ] XMLHttpRequestUpload {
+ // From XMLHttpRequestEventTarget
+ // event handler attributes
+ attribute EventListener onabort;
+ attribute EventListener onerror;
+ attribute EventListener onload;
+ attribute EventListener onloadstart;
+ attribute EventListener onprogress;
+
+ // EventTarget interface
+ [Custom] void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ [Custom] void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ boolean dispatchEvent(in Event evt)
+ raises(EventException);
+ };
+
+}
diff --git a/WebCore/xml/XMLSerializer.h b/WebCore/xml/XMLSerializer.h
index 34f1a05..33e94b7 100644
--- a/WebCore/xml/XMLSerializer.h
+++ b/WebCore/xml/XMLSerializer.h
@@ -1,5 +1,4 @@
/*
- * This file is part of the KDE libraries
* Copyright (C) 2003, 2006 Apple Computer, Inc.
* Copyright (C) 2006 Samuel Weinig (sam@webkit.org)
*
@@ -32,7 +31,12 @@ namespace WebCore {
class XMLSerializer : public RefCounted<XMLSerializer> {
public:
+ static PassRefPtr<XMLSerializer> create() { return adoptRef(new XMLSerializer); }
+
String serializeToString(Node*, ExceptionCode&);
+
+ private:
+ XMLSerializer() { }
};
} // namespace WebCore
diff --git a/WebCore/xml/XPathEvaluator.cpp b/WebCore/xml/XPathEvaluator.cpp
index 1707012..8fb203f 100644
--- a/WebCore/xml/XPathEvaluator.cpp
+++ b/WebCore/xml/XPathEvaluator.cpp
@@ -49,7 +49,7 @@ PassRefPtr<XPathExpression> XPathEvaluator::createExpression(const String& expre
PassRefPtr<XPathNSResolver> XPathEvaluator::createNSResolver(Node* nodeResolver)
{
- return new NativeXPathNSResolver(nodeResolver);
+ return NativeXPathNSResolver::create(nodeResolver);
}
PassRefPtr<XPathResult> XPathEvaluator::evaluate(const String& expression,
diff --git a/WebCore/xml/XPathEvaluator.h b/WebCore/xml/XPathEvaluator.h
index 03dc7db..c8e456e 100644
--- a/WebCore/xml/XPathEvaluator.h
+++ b/WebCore/xml/XPathEvaluator.h
@@ -30,7 +30,7 @@
#if ENABLE(XPATH)
#include <wtf/RefCounted.h>
-#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
namespace WebCore {
@@ -44,10 +44,15 @@ namespace WebCore {
class XPathEvaluator : public RefCounted<XPathEvaluator> {
public:
+ static PassRefPtr<XPathEvaluator> create() { return adoptRef(new XPathEvaluator); }
+
PassRefPtr<XPathExpression> createExpression(const String& expression, XPathNSResolver*, ExceptionCode&);
PassRefPtr<XPathNSResolver> createNSResolver(Node* nodeResolver);
PassRefPtr<XPathResult> evaluate(const String& expression, Node* contextNode,
XPathNSResolver*, unsigned short type, XPathResult*, ExceptionCode&);
+
+ private:
+ XPathEvaluator() { }
};
}
diff --git a/WebCore/xml/XPathException.h b/WebCore/xml/XPathException.h
index aa3585c..45ad628 100644
--- a/WebCore/xml/XPathException.h
+++ b/WebCore/xml/XPathException.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,17 +29,17 @@
#ifndef XPathException_h
#define XPathException_h
-#if ENABLE(XPATH)
-
#include "ExceptionBase.h"
+#if ENABLE(XPATH)
+
namespace WebCore {
class XPathException : public ExceptionBase {
public:
- XPathException(const ExceptionCodeDescription& description)
- : ExceptionBase(description)
+ static PassRefPtr<XPathException> create(const ExceptionCodeDescription& description)
{
+ return adoptRef(new XPathException(description));
}
static const int XPathExceptionOffset = 400;
@@ -49,6 +49,12 @@ namespace WebCore {
INVALID_EXPRESSION_ERR = XPathExceptionOffset + 51,
TYPE_ERR
};
+
+ private:
+ XPathException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
};
} // namespace WebCore
diff --git a/WebCore/xml/XPathExpression.cpp b/WebCore/xml/XPathExpression.cpp
index 38369f8..446a7ad 100644
--- a/WebCore/xml/XPathExpression.cpp
+++ b/WebCore/xml/XPathExpression.cpp
@@ -45,7 +45,7 @@ using namespace XPath;
PassRefPtr<XPathExpression> XPathExpression::createExpression(const String& expression, XPathNSResolver* resolver, ExceptionCode& ec)
{
- RefPtr<XPathExpression> expr = new XPathExpression;
+ RefPtr<XPathExpression> expr = XPathExpression::create();
Parser parser;
expr->m_topExpression = parser.parseStatement(expression, resolver, ec);
@@ -75,7 +75,7 @@ PassRefPtr<XPathResult> XPathExpression::evaluate(Node* contextNode, unsigned sh
evaluationContext.node = contextNode;
evaluationContext.size = 1;
evaluationContext.position = 1;
- RefPtr<XPathResult> result = new XPathResult(eventTarget, m_topExpression->evaluate());
+ RefPtr<XPathResult> result = XPathResult::create(eventTarget, m_topExpression->evaluate());
evaluationContext.node = 0; // Do not hold a reference to the context node, as this may prevent the whole document from being destroyed in time.
if (type != XPathResult::ANY_TYPE) {
diff --git a/WebCore/xml/XPathExpression.h b/WebCore/xml/XPathExpression.h
index 430e3c9..a2b75d7 100644
--- a/WebCore/xml/XPathExpression.h
+++ b/WebCore/xml/XPathExpression.h
@@ -30,7 +30,7 @@
#if ENABLE(XPATH)
#include <wtf/RefCounted.h>
-#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
namespace WebCore {
@@ -47,11 +47,15 @@ namespace WebCore {
class XPathExpression : public RefCounted<XPathExpression> {
public:
+ static PassRefPtr<XPathExpression> create() { return adoptRef(new XPathExpression); }
~XPathExpression();
+
static PassRefPtr<XPathExpression> createExpression(const String& expression, XPathNSResolver*, ExceptionCode&);
PassRefPtr<XPathResult> evaluate(Node* contextNode, unsigned short type, XPathResult*, ExceptionCode&);
private:
+ XPathExpression() { }
+
XPath::Expression* m_topExpression;
};
diff --git a/WebCore/xml/XPathExpression.idl b/WebCore/xml/XPathExpression.idl
index 1afe888..c1fc15e 100644
--- a/WebCore/xml/XPathExpression.idl
+++ b/WebCore/xml/XPathExpression.idl
@@ -21,7 +21,10 @@
module xpath {
- interface [Conditional=XPATH] XPathExpression {
+ interface [
+ Conditional=XPATH,
+ GenerateConstructor
+ ] XPathExpression {
[OldStyleObjC] XPathResult evaluate(in Node contextNode,
in unsigned short type,
in XPathResult inResult)
diff --git a/WebCore/xml/XPathExpressionNode.h b/WebCore/xml/XPathExpressionNode.h
index 6a483f1..9c5f79b 100644
--- a/WebCore/xml/XPathExpressionNode.h
+++ b/WebCore/xml/XPathExpressionNode.h
@@ -30,13 +30,12 @@
#if ENABLE(XPATH)
#include "StringHash.h"
+#include "Node.h"
#include <wtf/HashMap.h>
#include <wtf/Vector.h>
namespace WebCore {
- class Node;
-
namespace XPath {
class Value;
diff --git a/WebCore/xml/XPathFunctions.cpp b/WebCore/xml/XPathFunctions.cpp
index 9e12d28..841b436 100644
--- a/WebCore/xml/XPathFunctions.cpp
+++ b/WebCore/xml/XPathFunctions.cpp
@@ -326,7 +326,7 @@ Value FunLocalName::evaluate() const
if (!node)
node = evaluationContext().node.get();
- return node->localName().domString();
+ return node->localName().string();
}
Value FunNamespaceURI::evaluate() const
@@ -345,7 +345,7 @@ Value FunNamespaceURI::evaluate() const
if (!node)
node = evaluationContext().node.get();
- return node->namespaceURI().domString();
+ return node->namespaceURI().string();
}
Value FunName::evaluate() const
@@ -365,7 +365,7 @@ Value FunName::evaluate() const
node = evaluationContext().node.get();
const AtomicString& prefix = node->prefix();
- return prefix.isEmpty() ? node->localName().domString() : prefix + ":" + node->localName();
+ return prefix.isEmpty() ? node->localName().string() : prefix + ":" + node->localName();
}
Value FunCount::evaluate() const
diff --git a/WebCore/xml/XPathGrammar.y b/WebCore/xml/XPathGrammar.y
index 68c6c6e..50a69c2 100644
--- a/WebCore/xml/XPathGrammar.y
+++ b/WebCore/xml/XPathGrammar.y
@@ -82,7 +82,7 @@ void xpathyyerror(const char* str) { }
%token <str> VARIABLEREFERENCE NUMBER
%token DOTDOT SLASHSLASH
%token <str> NAMETEST
-%token ERROR
+%token XPATH_ERROR
%type <locationPath> LocationPath
%type <locationPath> AbsoluteLocationPath
diff --git a/WebCore/xml/XPathNSResolver.h b/WebCore/xml/XPathNSResolver.h
index b6120c1..04b5f80 100644
--- a/WebCore/xml/XPathNSResolver.h
+++ b/WebCore/xml/XPathNSResolver.h
@@ -39,6 +39,9 @@ namespace WebCore {
public:
virtual ~XPathNSResolver();
virtual String lookupNamespaceURI(const String& prefix) = 0;
+
+ protected:
+ XPathNSResolver() { }
};
}
diff --git a/WebCore/xml/XPathParser.cpp b/WebCore/xml/XPathParser.cpp
index 75d2285..77c3011 100644
--- a/WebCore/xml/XPathParser.cpp
+++ b/WebCore/xml/XPathParser.cpp
@@ -202,7 +202,7 @@ Token Parser::lexString()
}
// Ouch, went off the end -- report error.
- return Token(ERROR);
+ return Token(XPATH_ERROR);
}
Token Parser::lexNumber()
@@ -306,7 +306,7 @@ Token Parser::nextTokenInternal()
case '!':
if (peekAheadHelper() == '=')
return makeTokenAndAdvance(EQOP, EqTestOp::OP_NE, 2);
- return Token(ERROR);
+ return Token(XPATH_ERROR);
case '<':
if (peekAheadHelper() == '=')
return makeTokenAndAdvance(RELOP, EqTestOp::OP_LE, 2);
@@ -324,14 +324,14 @@ Token Parser::nextTokenInternal()
m_nextPos++;
String name;
if (!lexQName(name))
- return Token(ERROR);
+ return Token(XPATH_ERROR);
return Token(VARIABLEREFERENCE, name);
}
}
String name;
if (!lexNCName(name))
- return Token(ERROR);
+ return Token(XPATH_ERROR);
skipWS();
// If we're in an operator context, check for any operator names
@@ -358,7 +358,7 @@ Token Parser::nextTokenInternal()
if (isAxisName(name, axis))
return Token(AXISNAME, axis);
// Ugh, :: is only valid in axis names -> error
- return Token(ERROR);
+ return Token(XPATH_ERROR);
}
// Seems like this is a fully qualified qname, or perhaps the * modified one from NameTest
@@ -371,7 +371,7 @@ Token Parser::nextTokenInternal()
// Make a full qname.
String n2;
if (!lexNCName(n2))
- return Token(ERROR);
+ return Token(XPATH_ERROR);
name = name + ":" + n2;
}
diff --git a/WebCore/xml/XPathResult.cpp b/WebCore/xml/XPathResult.cpp
index e7c4db3..285350e 100644
--- a/WebCore/xml/XPathResult.cpp
+++ b/WebCore/xml/XPathResult.cpp
@@ -42,9 +42,11 @@ using namespace XPath;
class InvalidatingEventListener : public EventListener {
public:
- InvalidatingEventListener(XPathResult* result) : m_result(result) { }
+ static PassRefPtr<InvalidatingEventListener> create(XPathResult* result) { return adoptRef(new InvalidatingEventListener(result)); }
virtual void handleEvent(Event*, bool) { m_result->invalidateIteratorState(); }
+
private:
+ InvalidatingEventListener(XPathResult* result) : m_result(result) { }
XPathResult* m_result;
};
@@ -52,8 +54,8 @@ XPathResult::XPathResult(EventTargetNode* eventTarget, const Value& value)
: m_value(value)
, m_eventTarget(eventTarget)
{
- m_eventListener = new InvalidatingEventListener(this);
- m_eventTarget->addEventListener(EventNames::DOMSubtreeModifiedEvent, m_eventListener, false);
+ m_eventListener = InvalidatingEventListener::create(this);
+ m_eventTarget->addEventListener(eventNames().DOMSubtreeModifiedEvent, m_eventListener, false);
switch (m_value.type()) {
case Value::BooleanValue:
m_resultType = BOOLEAN_TYPE;
@@ -77,7 +79,7 @@ XPathResult::XPathResult(EventTargetNode* eventTarget, const Value& value)
XPathResult::~XPathResult()
{
if (m_eventTarget)
- m_eventTarget->removeEventListener(EventNames::DOMSubtreeModifiedEvent, m_eventListener.get(), false);
+ m_eventTarget->removeEventListener(eventNames().DOMSubtreeModifiedEvent, m_eventListener.get(), false);
}
void XPathResult::convertTo(unsigned short type, ExceptionCode& ec)
@@ -179,7 +181,7 @@ void XPathResult::invalidateIteratorState()
ASSERT(m_eventTarget);
ASSERT(m_eventListener);
- m_eventTarget->removeEventListener(EventNames::DOMSubtreeModifiedEvent, m_eventListener.get(), false);
+ m_eventTarget->removeEventListener(eventNames().DOMSubtreeModifiedEvent, m_eventListener.get(), false);
m_eventTarget = 0;
}
diff --git a/WebCore/xml/XPathResult.h b/WebCore/xml/XPathResult.h
index 356992d..ecd5cac 100644
--- a/WebCore/xml/XPathResult.h
+++ b/WebCore/xml/XPathResult.h
@@ -56,7 +56,7 @@ namespace WebCore {
FIRST_ORDERED_NODE_TYPE = 9
};
- XPathResult(EventTargetNode*, const XPath::Value&);
+ static PassRefPtr<XPathResult> create(EventTargetNode* eventTarget, const XPath::Value& value) { return adoptRef(new XPathResult(eventTarget, value)); }
~XPathResult();
void convertTo(unsigned short type, ExceptionCode&);
@@ -76,6 +76,8 @@ namespace WebCore {
void invalidateIteratorState();
private:
+ XPathResult(EventTargetNode*, const XPath::Value&);
+
XPath::Value m_value;
unsigned m_nodeSetPosition;
XPath::NodeSet m_nodeSet; // FIXME: why duplicate the node set stored in m_value?
diff --git a/WebCore/xml/XPathUtil.cpp b/WebCore/xml/XPathUtil.cpp
index a7cd21f..ab4b1d4 100644
--- a/WebCore/xml/XPathUtil.cpp
+++ b/WebCore/xml/XPathUtil.cpp
@@ -29,7 +29,7 @@
#if ENABLE(XPATH)
-#include "Node.h"
+#include "ContainerNode.h"
namespace WebCore {
namespace XPath {
@@ -66,16 +66,28 @@ String stringValue(Node* node)
bool isValidContextNode(Node* node)
{
- return node && (
- node->nodeType() == Node::ELEMENT_NODE ||
- node->nodeType() == Node::ATTRIBUTE_NODE ||
- node->nodeType() == Node::TEXT_NODE ||
- node->nodeType() == Node::CDATA_SECTION_NODE ||
- node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE ||
- node->nodeType() == Node::COMMENT_NODE ||
- node->nodeType() == Node::DOCUMENT_NODE ||
- node->nodeType() == Node::XPATH_NAMESPACE_NODE) &&
- !(node->nodeType() == Node::TEXT_NODE && node->parentNode() && node->parentNode()->isAttributeNode());
+ if (!node)
+ return false;
+ switch (node->nodeType()) {
+ case Node::ATTRIBUTE_NODE:
+ case Node::CDATA_SECTION_NODE:
+ case Node::COMMENT_NODE:
+ case Node::DOCUMENT_NODE:
+ case Node::ELEMENT_NODE:
+ case Node::PROCESSING_INSTRUCTION_NODE:
+ case Node::XPATH_NAMESPACE_NODE:
+ return true;
+ case Node::DOCUMENT_FRAGMENT_NODE:
+ case Node::DOCUMENT_TYPE_NODE:
+ case Node::ENTITY_NODE:
+ case Node::ENTITY_REFERENCE_NODE:
+ case Node::NOTATION_NODE:
+ return false;
+ case Node::TEXT_NODE:
+ return !(node->parentNode() && node->parentNode()->isAttributeNode());
+ }
+ ASSERT_NOT_REACHED();
+ return false;
}
}
diff --git a/WebCore/xml/XPathValue.cpp b/WebCore/xml/XPathValue.cpp
index b21942f..b3cad38 100644
--- a/WebCore/xml/XPathValue.cpp
+++ b/WebCore/xml/XPathValue.cpp
@@ -55,7 +55,7 @@ const NodeSet& Value::toNodeSet() const
NodeSet& Value::modifiableNodeSet()
{
if (!m_data)
- m_data = new ValueData;
+ m_data = ValueData::create();
m_type = NodeSetValue;
return m_data->m_nodeSet;
diff --git a/WebCore/xml/XPathValue.h b/WebCore/xml/XPathValue.h
index b2ad0d6..a0cd24d 100644
--- a/WebCore/xml/XPathValue.h
+++ b/WebCore/xml/XPathValue.h
@@ -37,13 +37,18 @@ namespace WebCore {
namespace XPath {
class ValueData : public RefCounted<ValueData> {
- public:
- ValueData() {}
- ValueData(const NodeSet& nodeSet) : m_nodeSet(nodeSet) {}
- ValueData(const String& string) : m_string(string) {}
+ public:
+ static PassRefPtr<ValueData> create() { return adoptRef(new ValueData); }
+ static PassRefPtr<ValueData> create(const NodeSet& nodeSet) { return adoptRef(new ValueData(nodeSet)); }
+ static PassRefPtr<ValueData> create(const String& string) { return adoptRef(new ValueData(string)); }
NodeSet m_nodeSet;
String m_string;
+
+ private:
+ ValueData() { }
+ ValueData(const NodeSet& nodeSet) : m_nodeSet(nodeSet) { }
+ ValueData(const String& string) : m_string(string) { }
};
// Copying Value objects makes their data partially shared, so care has to be taken when dealing with copies.
@@ -51,20 +56,20 @@ namespace WebCore {
public:
enum Type { NodeSetValue, BooleanValue, NumberValue, StringValue };
- Value(unsigned value) : m_type(NumberValue), m_number(value) {}
- Value(unsigned long value) : m_type(NumberValue), m_number(value) {}
- Value(double value) : m_type(NumberValue), m_number(value) {}
+ Value(unsigned value) : m_type(NumberValue), m_bool(false), m_number(value) {}
+ Value(unsigned long value) : m_type(NumberValue), m_bool(false), m_number(value) {}
+ Value(double value) : m_type(NumberValue), m_bool(false), m_number(value) {}
- Value(const char* value) : m_type(StringValue), m_data(new ValueData(value)) {}
- Value(const String& value) : m_type(StringValue), m_data(new ValueData(value)) {}
- Value(const NodeSet& value) : m_type(NodeSetValue), m_data(new ValueData(value)) {}
- Value(Node* value) : m_type(NodeSetValue), m_data(new ValueData) { m_data->m_nodeSet.append(value); }
+ Value(const char* value) : m_type(StringValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
+ Value(const String& value) : m_type(StringValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
+ Value(const NodeSet& value) : m_type(NodeSetValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
+ Value(Node* value) : m_type(NodeSetValue), m_bool(false), m_number(0), m_data(ValueData::create()) { m_data->m_nodeSet.append(value); }
// This is needed to safely implement constructing from bool - with normal function overloading, any pointer type would match.
template<typename T> Value(T);
static const struct AdoptTag {} adopt;
- Value(NodeSet& value, const AdoptTag&) : m_type(NodeSetValue), m_data(new ValueData) { value.swap(m_data->m_nodeSet); }
+ Value(NodeSet& value, const AdoptTag&) : m_type(NodeSetValue), m_bool(false), m_number(0), m_data(ValueData::create()) { value.swap(m_data->m_nodeSet); }
Type type() const { return m_type; }
@@ -90,6 +95,7 @@ namespace WebCore {
inline Value::Value(bool value)
: m_type(BooleanValue)
, m_bool(value)
+ , m_number(0)
{
}
}
diff --git a/WebCore/xml/XSLImportRule.cpp b/WebCore/xml/XSLImportRule.cpp
index bfdec20..2efafa3 100644
--- a/WebCore/xml/XSLImportRule.cpp
+++ b/WebCore/xml/XSLImportRule.cpp
@@ -1,7 +1,7 @@
-/**
+/*
* This file is part of the XSL implementation.
*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -30,7 +30,7 @@
namespace WebCore {
-XSLImportRule::XSLImportRule(StyleBase* parent, const String& href)
+XSLImportRule::XSLImportRule(XSLStyleSheet* parent, const String& href)
: StyleBase(parent)
, m_strHref(href)
, m_cachedSheet(0)
@@ -44,7 +44,7 @@ XSLImportRule::~XSLImportRule()
m_styleSheet->setParent(0);
if (m_cachedSheet)
- m_cachedSheet->deref(this);
+ m_cachedSheet->removeClient(this);
}
XSLStyleSheet* XSLImportRule::parentStyleSheet() const
@@ -57,7 +57,7 @@ void XSLImportRule::setXSLStyleSheet(const String& url, const String& sheet)
if (m_styleSheet)
m_styleSheet->setParent(0);
- m_styleSheet = new XSLStyleSheet(this, url);
+ m_styleSheet = XSLStyleSheet::create(this, url);
XSLStyleSheet* parent = parentStyleSheet();
if (parent)
@@ -66,7 +66,8 @@ void XSLImportRule::setXSLStyleSheet(const String& url, const String& sheet)
m_styleSheet->parseString(sheet);
m_loading = false;
- checkLoaded();
+ if (parent)
+ parent->checkLoaded();
}
bool XSLImportRule::isLoading()
@@ -88,19 +89,19 @@ void XSLImportRule::loadSheet()
XSLStyleSheet* parentSheet = parentStyleSheet();
if (!parentSheet->href().isNull())
// use parent styleheet's URL as the base URL
- absHref = KURL(parentSheet->href().deprecatedString(), m_strHref.deprecatedString()).string();
+ absHref = KURL(KURL(parentSheet->href()), m_strHref).string();
// Check for a cycle in our import chain. If we encounter a stylesheet
// in our parent chain with the same URL, then just bail.
- for (parent = static_cast<StyleBase*>(this)->parent(); parent; parent = parent->parent()) {
- if (absHref == parent->baseURL())
+ for (parent = this->parent(); parent; parent = parent->parent()) {
+ if (parent->isXSLStyleSheet() && absHref == static_cast<XSLStyleSheet*>(parent)->href())
return;
}
m_cachedSheet = docLoader->requestXSLStyleSheet(absHref);
if (m_cachedSheet) {
- m_cachedSheet->ref(this);
+ m_cachedSheet->addClient(this);
// If the imported sheet is in the cache, then setXSLStyleSheet gets called,
// and the sheet even gets parsed (via parseString). In this case we have
diff --git a/WebCore/xml/XSLImportRule.h b/WebCore/xml/XSLImportRule.h
index e4bbc4b..fc7a7f8 100644
--- a/WebCore/xml/XSLImportRule.h
+++ b/WebCore/xml/XSLImportRule.h
@@ -1,7 +1,7 @@
/*
* This file is part of the XSL implementation.
*
- * Copyright (C) 2004, 2006 Apple Computer, Inc.
+ * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,6 +26,7 @@
#if ENABLE(XSLT)
#include "CachedResourceClient.h"
+#include "CachedResourceHandle.h"
#include "StyleBase.h"
#include "XSLStyleSheet.h"
@@ -33,27 +34,34 @@ namespace WebCore {
class CachedXSLStyleSheet;
-class XSLImportRule : public CachedResourceClient, public StyleBase {
+class XSLImportRule : public StyleBase, private CachedResourceClient {
public:
- XSLImportRule(StyleBase* parent, const String& href);
+ static PassRefPtr<XSLImportRule> create(XSLStyleSheet* parentSheet, const String& href)
+ {
+ return adoptRef(new XSLImportRule(parentSheet, href));
+ }
+
virtual ~XSLImportRule();
- String href() const { return m_strHref; }
+ const String& href() const { return m_strHref; }
XSLStyleSheet* styleSheet() const { return m_styleSheet.get(); }
-
- virtual bool isImportRule() { return true; }
+
XSLStyleSheet* parentStyleSheet() const;
+
+ bool isLoading();
+ void loadSheet();
+private:
+ XSLImportRule(XSLStyleSheet* parentSheet, const String& href);
+
+ virtual bool isImportRule() { return true; }
+
// from CachedResourceClient
virtual void setXSLStyleSheet(const String& url, const String& sheet);
- bool isLoading();
- void loadSheet();
-
-protected:
String m_strHref;
RefPtr<XSLStyleSheet> m_styleSheet;
- CachedXSLStyleSheet* m_cachedSheet;
+ CachedResourceHandle<CachedXSLStyleSheet> m_cachedSheet;
bool m_loading;
};
diff --git a/WebCore/xml/XSLStyleSheet.cpp b/WebCore/xml/XSLStyleSheet.cpp
index 22a0464..9443652 100644
--- a/WebCore/xml/XSLStyleSheet.cpp
+++ b/WebCore/xml/XSLStyleSheet.cpp
@@ -1,7 +1,7 @@
-/**
+/*
* This file is part of the XSL implementation.
*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -25,11 +25,13 @@
#if ENABLE(XSLT)
#include "CString.h"
+#include "Console.h"
+#include "DOMWindow.h"
#include "DocLoader.h"
#include "Document.h"
+#include "Frame.h"
#include "loader.h"
#include "Node.h"
-#include "Page.h"
#include "XMLTokenizer.h"
#include "XSLImportRule.h"
#include "XSLTProcessor.h"
@@ -97,8 +99,8 @@ void XSLStyleSheet::checkLoaded()
return;
if (parent())
parent()->checkLoaded();
- if (m_parentNode)
- m_parentNode->sheetLoaded();
+ if (ownerNode())
+ ownerNode()->sheetLoaded();
}
xmlDocPtr XSLStyleSheet::document()
@@ -139,10 +141,11 @@ bool XSLStyleSheet::parseString(const String& string, bool strict)
xmlFreeDoc(m_stylesheetDoc);
m_stylesheetDocTaken = false;
- Chrome* chrome = 0;
- if (Page* page = ownerDocument()->page())
- chrome = page->chrome();
- xmlSetStructuredErrorFunc(chrome, XSLTProcessor::parseErrorFunc);
+ Console* console = 0;
+ if (Frame* frame = ownerDocument()->frame())
+ console = frame->domWindow()->console();
+ xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc);
+ xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc);
m_stylesheetDoc = xmlReadMemory(reinterpret_cast<const char*>(string.characters()), string.length() * sizeof(UChar),
href().utf8().data(),
@@ -151,6 +154,7 @@ bool XSLStyleSheet::parseString(const String& string, bool strict)
loadChildSheets();
xmlSetStructuredErrorFunc(0, 0);
+ xmlSetGenericErrorFunc(0, 0);
setLoaderForLibXMLCallbacks(0);
return m_stylesheetDoc;
@@ -190,7 +194,7 @@ void XSLStyleSheet::loadChildSheets()
}
if (IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "import")) {
xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE);
- loadChildSheet(DeprecatedString::fromUtf8((const char*)uriRef));
+ loadChildSheet(String::fromUTF8((const char*)uriRef));
xmlFree(uriRef);
} else
break;
@@ -201,7 +205,7 @@ void XSLStyleSheet::loadChildSheets()
while (curr) {
if (curr->type == XML_ELEMENT_NODE && IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "include")) {
xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE);
- loadChildSheet(DeprecatedString::fromUtf8((const char*)uriRef));
+ loadChildSheet(String::fromUTF8((const char*)uriRef));
xmlFree(uriRef);
}
curr = curr->next;
@@ -209,9 +213,9 @@ void XSLStyleSheet::loadChildSheets()
}
}
-void XSLStyleSheet::loadChildSheet(const DeprecatedString& href)
+void XSLStyleSheet::loadChildSheet(const String& href)
{
- RefPtr<XSLImportRule> childRule = new XSLImportRule(this, href);
+ RefPtr<XSLImportRule> childRule = XSLImportRule::create(this, href);
append(childRule);
childRule->loadSheet();
}
diff --git a/WebCore/xml/XSLStyleSheet.h b/WebCore/xml/XSLStyleSheet.h
index 43c7bed..8946529 100644
--- a/WebCore/xml/XSLStyleSheet.h
+++ b/WebCore/xml/XSLStyleSheet.h
@@ -1,7 +1,7 @@
/*
* This file is part of the XSL implementation.
*
- * Copyright (C) 2004, 2006 Apple Computer, Inc.
+ * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -28,6 +28,7 @@
#include "StyleSheet.h"
#include <libxml/parser.h>
#include <libxslt/transform.h>
+#include <wtf/PassRefPtr.h>
namespace WebCore {
@@ -37,9 +38,20 @@ class XSLImportRule;
class XSLStyleSheet : public StyleSheet {
public:
- XSLStyleSheet(Node* parentNode, const String& href = String(), bool embedded = false);
- XSLStyleSheet(XSLImportRule* parentImport, const String& href = String());
- ~XSLStyleSheet();
+ static PassRefPtr<XSLStyleSheet> create(XSLImportRule* parentImport, const String& href)
+ {
+ return adoptRef(new XSLStyleSheet(parentImport, href));
+ }
+ static PassRefPtr<XSLStyleSheet> create(Node* parentNode, const String& href)
+ {
+ return adoptRef(new XSLStyleSheet(parentNode, href, false));
+ }
+ static PassRefPtr<XSLStyleSheet> createEmbedded(Node* parentNode, const String& href)
+ {
+ return adoptRef(new XSLStyleSheet(parentNode, href, true));
+ }
+
+ virtual ~XSLStyleSheet();
virtual bool isXSLStyleSheet() const { return true; }
@@ -51,7 +63,7 @@ public:
virtual void checkLoaded();
void loadChildSheets();
- void loadChildSheet(const DeprecatedString& href);
+ void loadChildSheet(const String& href);
xsltStylesheetPtr compileStyleSheet();
@@ -69,7 +81,10 @@ public:
void markAsProcessed();
bool processed() const { return m_processed; }
-protected:
+private:
+ XSLStyleSheet(Node* parentNode, const String& href, bool embedded);
+ XSLStyleSheet(XSLImportRule* parentImport, const String& href);
+
Document* m_ownerDocument;
xmlDocPtr m_stylesheetDoc;
bool m_embedded;
diff --git a/WebCore/xml/XSLTProcessor.cpp b/WebCore/xml/XSLTProcessor.cpp
index 07efe75..ab554c4 100644
--- a/WebCore/xml/XSLTProcessor.cpp
+++ b/WebCore/xml/XSLTProcessor.cpp
@@ -1,7 +1,7 @@
-/**
+/*
* This file is part of the XSL implementation.
*
- * Copyright (C) 2004, 2005, 2006, 2007 Apple, Inc.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple, Inc. All rights reserved.
* Copyright (C) 2005, 2006 Alexey Proskuryakov <ap@webkit.org>
*
* This library is free software; you can redistribute it and/or
@@ -27,8 +27,9 @@
#include "XSLTProcessor.h"
#include "CString.h"
-#include "Cache.h"
+#include "Console.h"
#include "DOMImplementation.h"
+#include "DOMWindow.h"
#include "DocLoader.h"
#include "DocumentFragment.h"
#include "Frame.h"
@@ -37,6 +38,7 @@
#include "HTMLDocument.h"
#include "HTMLTokenizer.h"
#include "Page.h"
+#include "ResourceError.h"
#include "ResourceHandle.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
@@ -72,10 +74,15 @@ SOFT_LINK(libxslt, xsltNextImport, xsltStylesheetPtr, (xsltStylesheetPtr style),
namespace WebCore {
+void XSLTProcessor::genericErrorFunc(void* userData, const char* msg, ...)
+{
+ // It would be nice to do something with this error message.
+}
+
void XSLTProcessor::parseErrorFunc(void* userData, xmlError* error)
{
- Chrome* chrome = static_cast<Chrome*>(userData);
- if (!chrome)
+ Console* console = static_cast<Console*>(userData);
+ if (!console)
return;
MessageLevel level;
@@ -93,7 +100,7 @@ void XSLTProcessor::parseErrorFunc(void* userData, xmlError* error)
break;
}
- chrome->addMessageToConsole(XMLMessageSource, level, error->message, error->line, error->file);
+ console->addMessage(XMLMessageSource, level, error->message, error->line, error->file);
}
// FIXME: There seems to be no way to control the ctxt pointer for loading here, thus we have globals.
@@ -112,26 +119,35 @@ static xmlDocPtr docLoaderFunc(const xmlChar* uri,
case XSLT_LOAD_DOCUMENT: {
xsltTransformContextPtr context = (xsltTransformContextPtr)ctxt;
xmlChar* base = xmlNodeGetBase(context->document->doc, context->node);
- KURL url((const char*)base, (const char*)uri);
+ KURL url(KURL(reinterpret_cast<const char*>(base)), reinterpret_cast<const char*>(uri));
xmlFree(base);
ResourceError error;
ResourceResponse response;
Vector<char> data;
- if (globalDocLoader->frame())
+ bool requestAllowed = globalDocLoader->frame() && globalDocLoader->doc()->securityOrigin()->canRequest(url);
+ if (requestAllowed) {
globalDocLoader->frame()->loader()->loadResourceSynchronously(url, error, response, data);
-
- Chrome* chrome = 0;
- if (Page* page = globalProcessor->xslStylesheet()->ownerDocument()->page())
- chrome = page->chrome();
- xmlSetStructuredErrorFunc(chrome, XSLTProcessor::parseErrorFunc);
-
+ requestAllowed = globalDocLoader->doc()->securityOrigin()->canRequest(response.url());
+ }
+ if (!requestAllowed) {
+ data.clear();
+ globalDocLoader->printAccessDeniedMessage(url);
+ }
+
+ Console* console = 0;
+ if (Frame* frame = globalProcessor->xslStylesheet()->ownerDocument()->frame())
+ console = frame->domWindow()->console();
+ xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc);
+ xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc);
+
// We don't specify an encoding here. Neither Gecko nor WinIE respects
// the encoding specified in the HTTP headers.
xmlDocPtr doc = xmlReadMemory(data.data(), data.size(), (const char*)uri, 0, options);
xmlSetStructuredErrorFunc(0, 0);
+ xmlSetGenericErrorFunc(0, 0);
return doc;
}
@@ -230,7 +246,7 @@ static void freeXsltParamArray(const char** params)
}
-RefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourceString,
+PassRefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourceString,
const String& sourceEncoding, const String& sourceMIMEType, Node* sourceNode, Frame* frame)
{
RefPtr<Document> ownerDocument = sourceNode->document();
@@ -253,25 +269,22 @@ RefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourceStr
frame->setDocument(result);
}
- result->open();
- if (sourceIsDocument) {
+ if (sourceIsDocument)
result->setURL(ownerDocument->url());
- result->setBaseURL(ownerDocument->baseURL());
- }
- result->determineParseMode(documentSource); // Make sure we parse in the correct mode.
+ result->open();
- RefPtr<TextResourceDecoder> decoder = new TextResourceDecoder(sourceMIMEType);
+ RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create(sourceMIMEType);
decoder->setEncoding(sourceEncoding.isEmpty() ? UTF8Encoding() : TextEncoding(sourceEncoding), TextResourceDecoder::EncodingFromXMLHeader);
- result->setDecoder(decoder.get());
+ result->setDecoder(decoder.release());
result->write(documentSource);
result->finishParsing();
result->close();
- return result;
+ return result.release();
}
-static inline RefPtr<DocumentFragment> createFragmentFromSource(String sourceString, String sourceMIMEType, Node* sourceNode, Document* outputDoc)
+static inline RefPtr<DocumentFragment> createFragmentFromSource(const String& sourceString, const String& sourceMIMEType, Node* sourceNode, Document* outputDoc)
{
RefPtr<DocumentFragment> fragment = new DocumentFragment(outputDoc);
@@ -293,7 +306,8 @@ static inline RefPtr<DocumentFragment> createFragmentFromSource(String sourceStr
static xsltStylesheetPtr xsltStylesheetPointer(RefPtr<XSLStyleSheet>& cachedStylesheet, Node* stylesheetRootNode)
{
if (!cachedStylesheet && stylesheetRootNode) {
- cachedStylesheet = new XSLStyleSheet(stylesheetRootNode->parent() ? stylesheetRootNode->parent() : stylesheetRootNode, stylesheetRootNode->document()->url());
+ cachedStylesheet = XSLStyleSheet::create(stylesheetRootNode->parent() ? stylesheetRootNode->parent() : stylesheetRootNode,
+ stylesheetRootNode->document()->url().string());
cachedStylesheet->parseString(createMarkup(stylesheetRootNode));
}
@@ -312,7 +326,8 @@ static inline xmlDocPtr xmlDocPtrFromNode(Node* sourceNode, bool& shouldDelete)
if (sourceIsDocument)
sourceDoc = (xmlDocPtr)ownerDocument->transformSource();
if (!sourceDoc) {
- sourceDoc = (xmlDocPtr)xmlDocPtrForString(ownerDocument->docLoader(), createMarkup(sourceNode), sourceIsDocument ? ownerDocument->url() : DeprecatedString());
+ sourceDoc = (xmlDocPtr)xmlDocPtrForString(ownerDocument->docLoader(), createMarkup(sourceNode),
+ sourceIsDocument ? ownerDocument->url().string() : String());
shouldDelete = (sourceDoc != 0);
}
return sourceDoc;
@@ -396,7 +411,7 @@ bool XSLTProcessor::transformToString(Node* sourceNode, String& mimeType, String
return success;
}
-RefPtr<Document> XSLTProcessor::transformToDocument(Node* sourceNode)
+PassRefPtr<Document> XSLTProcessor::transformToDocument(Node* sourceNode)
{
String resultMIMEType;
String resultString;
@@ -406,7 +421,7 @@ RefPtr<Document> XSLTProcessor::transformToDocument(Node* sourceNode)
return createDocumentFromSource(resultString, resultEncoding, resultMIMEType, sourceNode, 0);
}
-RefPtr<DocumentFragment> XSLTProcessor::transformToFragment(Node* sourceNode, Document* outputDoc)
+PassRefPtr<DocumentFragment> XSLTProcessor::transformToFragment(Node* sourceNode, Document* outputDoc)
{
String resultMIMEType;
String resultString;
diff --git a/WebCore/xml/XSLTProcessor.h b/WebCore/xml/XSLTProcessor.h
index 3a92a59..9ee2aad 100644
--- a/WebCore/xml/XSLTProcessor.h
+++ b/WebCore/xml/XSLTProcessor.h
@@ -1,7 +1,7 @@
/*
* This file is part of the XSL implementation.
*
- * Copyright (C) 2004, 2007 Apple, Inc.
+ * Copyright (C) 2004, 2007, 2008 Apple, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -25,53 +25,53 @@
#if ENABLE(XSLT)
+#include "Node.h"
#include "StringHash.h"
#include "XSLStyleSheet.h"
-#include <wtf/HashMap.h>
#include <libxml/parserInternals.h>
#include <libxslt/documents.h>
+#include <wtf/HashMap.h>
namespace WebCore {
class Frame;
-class Node;
class Document;
class DocumentFragment;
-class XSLTProcessor : public RefCounted<XSLTProcessor>
-{
+class XSLTProcessor : public RefCounted<XSLTProcessor> {
public:
- void setXSLStylesheet(XSLStyleSheet* styleSheet) { m_stylesheet = styleSheet; }
+ static PassRefPtr<XSLTProcessor> create() { return adoptRef(new XSLTProcessor); }
+
+ void setXSLStyleSheet(PassRefPtr<XSLStyleSheet> styleSheet) { m_stylesheet = styleSheet; }
bool transformToString(Node* source, String& resultMIMEType, String& resultString, String& resultEncoding);
- RefPtr<Document> createDocumentFromSource(const String& source, const String& sourceEncoding, const String& sourceMIMEType, Node* sourceNode, Frame* frame);
+ PassRefPtr<Document> createDocumentFromSource(const String& source, const String& sourceEncoding, const String& sourceMIMEType, Node* sourceNode, Frame* frame);
// DOM methods
- void importStylesheet(Node* style) { m_stylesheetRootNode = style; }
- RefPtr<DocumentFragment> transformToFragment(Node* source, Document* ouputDoc);
- RefPtr<Document> transformToDocument(Node* source);
+ void importStylesheet(PassRefPtr<Node> style) { m_stylesheetRootNode = style; }
+ PassRefPtr<DocumentFragment> transformToFragment(Node* source, Document* ouputDoc);
+ PassRefPtr<Document> transformToDocument(Node* source);
void setParameter(const String& namespaceURI, const String& localName, const String& value);
String getParameter(const String& namespaceURI, const String& localName) const;
void removeParameter(const String& namespaceURI, const String& localName);
void clearParameters() { m_parameters.clear(); }
- void reset() { m_stylesheet = NULL; m_stylesheetRootNode = NULL; m_parameters.clear(); }
+ void reset() { m_stylesheet.clear(); m_stylesheetRootNode.clear(); m_parameters.clear(); }
static void parseErrorFunc(void* userData, xmlError*);
-
+ static void genericErrorFunc(void* userData, const char* msg, ...);
+
public:
// Only for libXSLT callbacks
XSLStyleSheet* xslStylesheet() const { return m_stylesheet.get(); }
-
+
typedef HashMap<String, String> ParameterMap;
private:
- // Convert a libxml doc ptr to a KHTML DOM Document
- RefPtr<Document> documentFromXMLDocPtr(xmlDocPtr resultDoc, xsltStylesheetPtr sheet, Document* ownerDocument, bool sourceIsDocument);
+ XSLTProcessor() { }
RefPtr<XSLStyleSheet> m_stylesheet;
RefPtr<Node> m_stylesheetRootNode;
-
ParameterMap m_parameters;
};
diff --git a/WebCore/xml/XSLTProcessor.idl b/WebCore/xml/XSLTProcessor.idl
new file mode 100644
index 0000000..0a6ff93
--- /dev/null
+++ b/WebCore/xml/XSLTProcessor.idl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module xml {
+
+ // Eventually we should implement XSLTException:
+ // http://lxr.mozilla.org/seamonkey/source/content/xsl/public/nsIXSLTException.idl
+ // http://bugs.webkit.org/show_bug.cgi?id=5446
+
+ interface [
+ Conditional=XSLT
+ ] XSLTProcessor {
+
+ [Custom] void importStylesheet(in Node stylesheet);
+ [Custom] DocumentFragment transformToFragment(in Node source, in Document docVal);
+ [Custom] Document transformToDocument(in Node source);
+
+ [Custom] void setParameter(in DOMString namespaceURI, in DOMString localName, in DOMString value);
+ [Custom, ConvertNullStringTo=Undefined] DOMString getParameter(in DOMString namespaceURI, in DOMString localName);
+ [Custom] void removeParameter(in DOMString namespaceURI, in DOMString localName);
+ void clearParameters();
+
+ void reset();
+
+ };
+
+}
diff --git a/WebCore/xml/XSLTUnicodeSort.cpp b/WebCore/xml/XSLTUnicodeSort.cpp
index e1ecdc4..ed66112 100644
--- a/WebCore/xml/XSLTUnicodeSort.cpp
+++ b/WebCore/xml/XSLTUnicodeSort.cpp
@@ -31,15 +31,12 @@
#if ENABLE(XSLT)
+#include "PlatformString.h"
+
#include <libxslt/templates.h>
#include <libxslt/xsltutils.h>
-#if USE(ICU_UNICODE)
-#include <unicode/ucnv.h>
-#include <unicode/ucol.h>
-#include <unicode/ustring.h>
-#define WTF_USE_ICU_COLLATION !UCONFIG_NO_COLLATION
-#endif
+#include <wtf/unicode/Collator.h>
#if PLATFORM(MAC)
#include "SoftLinking.h"
@@ -122,14 +119,6 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
xmlXPathObjectPtr tmp;
int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
-#if USE(ICU_COLLATION)
- UCollator *coll = 0;
- UConverter *conv;
- UErrorCode status;
- UChar *target,*target2;
- int targetlen, target2len;
-#endif
-
if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
(nbsorts >= XSLT_MAX_SORT))
return;
@@ -201,28 +190,12 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
if (results == NULL)
return;
-#if USE(ICU_COLLATION)
- status = U_ZERO_ERROR;
- conv = ucnv_open("UTF8", &status);
- if (U_FAILURE(status))
- xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening converter\n");
-
- if (comp->has_lang)
- coll = ucol_open((const char*)comp->lang, &status);
- if (U_FAILURE(status) || !comp->has_lang) {
- status = U_ZERO_ERROR;
- coll = ucol_open("en", &status);
- }
- if (U_FAILURE(status))
- xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening collator\n");
-
- if (comp->lower_first)
- ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_LOWER_FIRST,&status);
- else
- ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_UPPER_FIRST,&status);
- if (U_FAILURE(status))
- xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error setting collator attribute\n");
-#endif
+ // We are passing a language identifier to a function that expects a locale identifier.
+ // The implementation of Collator should be lenient, and accept both "en-US" and "en_US", for example.
+ // This lets an author to really specify sorting rules, e.g. "de_DE@collation=phonebook", which isn't
+ // possible with language alone.
+ Collator collator(comp->has_lang ? (const char*)comp->lang : "en");
+ collator.setOrderLowerFirst(comp->lower_first);
/* Shell's sort of node-set */
for (incr = len / 2; incr > 0; incr /= 2) {
@@ -253,20 +226,9 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
tst = 1;
else tst = -1;
} else {
-#if USE(ICU_COLLATION)
- targetlen = xmlStrlen(results[j]->stringval) + 1;
- target2len = xmlStrlen(results[j + incr]->stringval) + 1;
- target = (UChar*)xmlMalloc(targetlen * sizeof(UChar));
- target2 = (UChar*)xmlMalloc(target2len * sizeof(UChar));
- targetlen = ucnv_toUChars(conv, target, targetlen, (const char*)results[j]->stringval, -1, &status);
- target2len = ucnv_toUChars(conv, target2, target2len, (const char*)results[j+incr]->stringval, -1, &status);
- tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2));
- xmlFree(target);
- xmlFree(target2);
-#else
- tst = xmlStrcmp(results[j]->stringval,
- results[j + incr]->stringval);
-#endif
+ String str1 = String::fromUTF8((const char*)results[j]->stringval);
+ String str2 = String::fromUTF8((const char*)results[j + incr]->stringval);
+ tst = collator.collate(str1.characters(), str1.length(), str2.characters(), str2.length());
}
if (descending)
tst = -tst;
@@ -319,20 +281,9 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
tst = 1;
else tst = -1;
} else {
-#if USE(ICU_COLLATION)
- targetlen = xmlStrlen(res[j]->stringval) + 1;
- target2len = xmlStrlen(res[j + incr]->stringval) + 1;
- target = (UChar*)xmlMalloc(targetlen * sizeof(UChar));
- target2 = (UChar*)xmlMalloc(target2len * sizeof(UChar));
- targetlen = ucnv_toUChars(conv, target, targetlen, (const char*)res[j]->stringval, -1, &status);
- target2len = ucnv_toUChars(conv, target2, target2len, (const char*)res[j+incr]->stringval, -1, &status);
- tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2));
- xmlFree(target);
- xmlFree(target2);
-#else
- tst = xmlStrcmp(res[j]->stringval,
- res[j + incr]->stringval);
-#endif
+ String str1 = String::fromUTF8((const char*)res[j]->stringval);
+ String str2 = String::fromUTF8((const char*)res[j + incr]->stringval);
+ tst = collator.collate(str1.characters(), str1.length(), str2.characters(), str2.length());
}
if (desc)
tst = -tst;
@@ -376,11 +327,6 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
}
}
-#if USE(ICU_COLLATION)
- ucol_close(coll);
- ucnv_close(conv);
-#endif
-
for (j = 0; j < nbsorts; j++) {
comp = static_cast<xsltStylePreComp*>(sorts[j]->psvi);
if (tempstype[j] == 1) {
diff --git a/WebCore/xml/XSLTUnicodeSort.h b/WebCore/xml/XSLTUnicodeSort.h
index ff5b253..c8d395b 100644
--- a/WebCore/xml/XSLTUnicodeSort.h
+++ b/WebCore/xml/XSLTUnicodeSort.h
@@ -28,8 +28,6 @@
#ifndef XSLTUnicodeSort_h
#define XSLTUnicodeSort_h
-// FIXME: Only works as advertised for ICU with collation support enabled yet, falls back on binary comparison otherwise..
-// We need to make an abstraction for Unicode collation to implement this for other libraries.
#if ENABLE(XSLT)
#include <libxslt/xsltInternals.h>
diff --git a/WebCore/xml/xmlattrs.in b/WebCore/xml/xmlattrs.in
index bfda2f2..6cc47be 100644
--- a/WebCore/xml/xmlattrs.in
+++ b/WebCore/xml/xmlattrs.in
@@ -1,3 +1,6 @@
+namespace="XML"
+namespaceURI="http://www.w3.org/XML/1998/namespace"
+
base
lang
space