diff options
Diffstat (limited to 'WebCore/xml')
34 files changed, 921 insertions, 1002 deletions
diff --git a/WebCore/xml/DOMParser.idl b/WebCore/xml/DOMParser.idl index 9caaa21..90a8b52 100644 --- a/WebCore/xml/DOMParser.idl +++ b/WebCore/xml/DOMParser.idl @@ -18,7 +18,7 @@ */ module xpath { - interface [GenerateConstructor, CanBeConstructed] DOMParser { + interface [CanBeConstructed] DOMParser { Document parseFromString(in DOMString str, in DOMString contentType); }; } diff --git a/WebCore/xml/XMLHttpRequest.cpp b/WebCore/xml/XMLHttpRequest.cpp index 5e20252..32818df 100644 --- a/WebCore/xml/XMLHttpRequest.cpp +++ b/WebCore/xml/XMLHttpRequest.cpp @@ -22,18 +22,18 @@ #include "config.h" #include "XMLHttpRequest.h" +#include "Blob.h" #include "Cache.h" #include "CString.h" #include "CrossOriginAccessControl.h" -#include "CrossOriginPreflightResultCache.h" #include "DOMImplementation.h" #include "Document.h" #include "Event.h" #include "EventException.h" #include "EventListener.h" #include "EventNames.h" -#include "File.h" #include "HTTPParsers.h" +#include "InspectorTimelineAgent.h" #include "ResourceError.h" #include "ResourceRequest.h" #include "SecurityOrigin.h" @@ -45,14 +45,21 @@ #include "XMLHttpRequestUpload.h" #include "markup.h" #include <wtf/StdLibExtras.h> +#include <wtf/RefCountedLeakCounter.h> #if USE(JSC) +#include "JSDOMBinding.h" #include "JSDOMWindow.h" +#include <runtime/Protect.h> #endif namespace WebCore { -struct XMLHttpRequestStaticData { +#ifndef NDEBUG +static WTF::RefCountedLeakCounter xmlHttpRequestCounter("XMLHttpRequest"); +#endif + +struct XMLHttpRequestStaticData : Noncopyable { XMLHttpRequestStaticData(); String m_proxyHeaderPrefix; String m_secHeaderPrefix; @@ -93,25 +100,25 @@ static bool isValidToken(const String& name) unsigned length = name.length(); for (unsigned i = 0; i < length; i++) { UChar c = name[i]; - + if (c >= 127 || c <= 32) return false; - + if (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' || c == '/' || c == '[' || c == ']' || c == '?' || c == '=' || c == '{' || c == '}') return false; } - + return true; } - + static bool isValidHeaderValue(const String& name) { - // FIXME: This should really match name against + // FIXME: This should really match name against // field-value in section 4.2 of RFC 2616. - + return !name.contains('\r') && !name.contains('\n'); } @@ -143,15 +150,18 @@ XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext* context) , m_responseText("") , m_createdDocument(false) , m_error(false) + , m_uploadEventsAllowed(true) , m_uploadComplete(false) , m_sameOriginRequest(true) - , m_inPreflight(false) , m_didTellLoaderAboutRequest(false) , m_receivedLength(0) , m_lastSendLineNumber(0) , m_exceptionCode(0) { initializeXMLHttpRequestStaticData(); +#ifndef NDEBUG + xmlHttpRequestCounter.increment(); +#endif } XMLHttpRequest::~XMLHttpRequest() @@ -162,6 +172,10 @@ XMLHttpRequest::~XMLHttpRequest() } if (m_upload) m_upload->disconnectXMLHttpRequest(); + +#ifndef NDEBUG + xmlHttpRequestCounter.decrement(); +#endif } Document* XMLHttpRequest::document() const @@ -207,7 +221,7 @@ Document* XMLHttpRequest::responseXML() const m_responseXML->write(String(m_responseText)); m_responseXML->finishParsing(); m_responseXML->close(); - + if (!m_responseXML->wellFormed()) m_responseXML = 0; } @@ -224,56 +238,6 @@ XMLHttpRequestUpload* XMLHttpRequest::upload() return m_upload.get(); } -void XMLHttpRequest::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 XMLHttpRequest::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 XMLHttpRequest::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec) -{ - // FIXME: check for other error conditions enumerated in the spec. - if (!evt || 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 XMLHttpRequest::changeState(State newState) { if (m_state != newState) { @@ -287,10 +251,35 @@ void XMLHttpRequest::callReadyStateChangeListener() if (!scriptExecutionContext()) return; - dispatchReadyStateChangeEvent(); +#if ENABLE(INSPECTOR) + InspectorTimelineAgent* timelineAgent = InspectorTimelineAgent::retrieve(scriptExecutionContext()); + bool callTimelineAgentOnReadyStateChange = timelineAgent && hasEventListeners(eventNames().readystatechangeEvent); + if (callTimelineAgentOnReadyStateChange) + timelineAgent->willChangeXHRReadyState(m_url.string(), m_state); +#endif + + dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().readystatechangeEvent)); + +#if ENABLE(INSPECTOR) + if (callTimelineAgentOnReadyStateChange && (timelineAgent = InspectorTimelineAgent::retrieve(scriptExecutionContext()))) + timelineAgent->didChangeXHRReadyState(); +#endif + + if (m_state == DONE && !m_error) { +#if ENABLE(INSPECTOR) + timelineAgent = InspectorTimelineAgent::retrieve(scriptExecutionContext()); + bool callTimelineAgentOnLoad = timelineAgent && hasEventListeners(eventNames().loadEvent); + if (callTimelineAgentOnLoad) + timelineAgent->willLoadXHR(m_url.string()); +#endif + + dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent)); - if (m_state == DONE && !m_error) - dispatchLoadEvent(); +#if ENABLE(INSPECTOR) + if (callTimelineAgentOnLoad && (timelineAgent = InspectorTimelineAgent::retrieve(scriptExecutionContext()))) + timelineAgent->didLoadXHR(); +#endif + } } void XMLHttpRequest::setWithCredentials(bool value, ExceptionCode& ec) @@ -322,10 +311,10 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, Exc ec = SYNTAX_ERR; return; } - + // Method names are case sensitive. But since Firefox uppercases method names it knows, we'll do the same. String methodUpper(method.upper()); - + if (methodUpper == "TRACE" || methodUpper == "TRACK" || methodUpper == "CONNECT") { ec = SECURITY_ERR; return; @@ -335,7 +324,7 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, Exc if (methodUpper == "COPY" || methodUpper == "DELETE" || methodUpper == "GET" || methodUpper == "HEAD" || methodUpper == "INDEX" || methodUpper == "LOCK" || methodUpper == "M-POST" || methodUpper == "MKCOL" || methodUpper == "MOVE" - || methodUpper == "OPTIONS" || methodUpper == "POST" || methodUpper == "PROPFIND" || methodUpper == "PROPPATCH" || methodUpper == "PUT" + || methodUpper == "OPTIONS" || methodUpper == "POST" || methodUpper == "PROPFIND" || methodUpper == "PROPPATCH" || methodUpper == "PUT" || methodUpper == "UNLOCK") m_method = methodUpper; else @@ -357,7 +346,7 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, con { KURL urlWithCredentials(url); urlWithCredentials.setUser(user); - + open(method, urlWithCredentials, async, ec); } @@ -366,7 +355,7 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, con KURL urlWithCredentials(url); urlWithCredentials.setUser(user); urlWithCredentials.setPass(password); - + open(method, urlWithCredentials, async, ec); } @@ -446,7 +435,7 @@ void XMLHttpRequest::send(const String& body, ExceptionCode& ec) createRequest(ec); } -void XMLHttpRequest::send(File* body, ExceptionCode& ec) +void XMLHttpRequest::send(Blob* body, ExceptionCode& ec) { if (!initSend(ec)) return; @@ -463,34 +452,23 @@ void XMLHttpRequest::send(File* body, ExceptionCode& ec) void XMLHttpRequest::createRequest(ExceptionCode& ec) { - // Upload event listeners should be disallowed for simple cross-origin requests, because POSTing to an URL that does not - // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. If a listener exists - // when creating the request, it will force preflight. + // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not + // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. // Also, only async requests support upload progress events. - m_uploadEventsAllowed = false; + bool forcePreflight = false; if (m_async) { - dispatchLoadStartEvent(); + dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); if (m_requestEntityBody && m_upload) { - m_uploadEventsAllowed = m_upload->hasListeners(); - m_upload->dispatchLoadStartEvent(); + forcePreflight = m_upload->hasEventListeners(); + m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); } } m_sameOriginRequest = scriptExecutionContext()->securityOrigin()->canRequest(m_url); - if (!m_sameOriginRequest) { - makeCrossOriginAccessRequest(ec); - return; - } - - m_uploadEventsAllowed = true; - - makeSameOriginRequest(ec); -} - -void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec) -{ - ASSERT(m_sameOriginRequest); + // We also remember whether upload events should be allowed for this request in case the upload listeners are + // added after the request is started. + m_uploadEventsAllowed = !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders); ResourceRequest request(m_url); request.setHTTPMethod(m_method); @@ -504,202 +482,49 @@ void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec) if (m_requestHeaders.size() > 0) request.addHTTPHeaderFields(m_requestHeaders); - if (m_async) - loadRequestAsynchronously(request); - else - loadRequestSynchronously(request, ec); -} - -void XMLHttpRequest::makeCrossOriginAccessRequest(ExceptionCode& ec) -{ - ASSERT(!m_sameOriginRequest); + ThreadableLoaderOptions options; + options.sendLoadCallbacks = true; + options.sniffContent = false; + options.forcePreflight = forcePreflight; + options.allowCredentials = m_sameOriginRequest || m_includeCredentials; + options.crossOriginRequestPolicy = UseAccessControl; - if (!m_uploadEventsAllowed && isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders)) - makeSimpleCrossOriginAccessRequest(ec); - else - makeCrossOriginAccessRequestWithPreflight(ec); -} - -void XMLHttpRequest::makeSimpleCrossOriginAccessRequest(ExceptionCode& ec) -{ - ASSERT(isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders)); - - // Cross-origin requests are only defined for HTTP. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied. - if (!m_url.protocolInHTTPFamily()) { - ec = XMLHttpRequestException::NETWORK_ERR; - networkError(); - return; - } - - KURL url = m_url; - url.setUser(String()); - url.setPass(String()); - - ResourceRequest request(url); - request.setHTTPMethod(m_method); - request.setAllowHTTPCookies(m_includeCredentials); - request.setHTTPOrigin(scriptExecutionContext()->securityOrigin()->toString()); - - if (m_requestHeaders.size() > 0) - request.addHTTPHeaderFields(m_requestHeaders); - - if (m_requestEntityBody) { - ASSERT(m_method != "GET"); - ASSERT(m_method != "HEAD"); - request.setHTTPBody(m_requestEntityBody.release()); - } - - if (m_async) - loadRequestAsynchronously(request); - else - loadRequestSynchronously(request, ec); -} + m_exceptionCode = 0; + m_error = false; -void XMLHttpRequest::makeCrossOriginAccessRequestWithPreflight(ExceptionCode& ec) -{ - String origin = scriptExecutionContext()->securityOrigin()->toString(); - KURL url = m_url; - url.setUser(String()); - url.setPass(String()); - - if (!CrossOriginPreflightResultCache::shared().canSkipPreflight(origin, url, m_includeCredentials, m_method, m_requestHeaders)) { - 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); + if (m_async) { + if (m_upload) + request.setReportUploadProgress(true); + + // ThreadableLoader::create can return null here, for example if we're no longer attached to a page. + // This is true while running onunload handlers. + // FIXME: Maybe 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? + m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); + 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. + setPendingActivity(this); + + // For now we should only balance the nonCached request count for main-thread XHRs and not + // Worker XHRs, as the Cache is not thread-safe. + // This will become irrelevant after https://bugs.webkit.org/show_bug.cgi?id=27165 is resolved. + if (!scriptExecutionContext()->isWorkerContext()) { + ASSERT(isMainThread()); + ASSERT(!m_didTellLoaderAboutRequest); + cache()->loader()->nonCacheRequestInFlight(m_url); + m_didTellLoaderAboutRequest = true; } - - preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", String::adopt(headerBuffer)); - preflightRequest.addHTTPHeaderFields(m_requestHeaders); } + } else + ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options); - if (m_async) { - m_uploadEventsAllowed = true; - 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"); - ASSERT(m_method != "HEAD"); - request.setHTTPBody(m_requestEntityBody.release()); - } - - if (m_async) { - m_uploadEventsAllowed = true; - 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(scriptExecutionContext()->securityOrigin()->toString()); - - if (m_requestHeaders.size() > 0) - request.addHTTPHeaderFields(m_requestHeaders); - - if (m_requestEntityBody) { - ASSERT(m_method != "GET"); - ASSERT(m_method != "HEAD"); - request.setHTTPBody(m_requestEntityBody.release()); - } - - m_uploadEventsAllowed = true; - loadRequestAsynchronously(request); -} - -void XMLHttpRequest::loadRequestSynchronously(ResourceRequest& request, ExceptionCode& ec) -{ - ASSERT(!m_async); - - m_loader = 0; - m_exceptionCode = 0; - StoredCredentials storedCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; - - ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, storedCredentials); if (!m_exceptionCode && m_error) m_exceptionCode = XMLHttpRequestException::NETWORK_ERR; ec = m_exceptionCode; } -void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request) -{ - ASSERT(m_async); - m_exceptionCode = 0; - // SubresourceLoader::create can return null here, for example if we're no longer attached to a page. - // This is true while running onunload handlers. - // FIXME: We need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>. - // FIXME: Maybe create can return null for other reasons too? - LoadCallbacks callbacks = m_inPreflight ? DoNotSendLoadCallbacks : SendLoadCallbacks; - StoredCredentials storedCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; - - if (m_upload) - request.setReportUploadProgress(true); - - m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, callbacks, DoNotSniffContent, storedCredentials, DenyCrossOriginRedirect); - - 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. - setPendingActivity(this); - - // For now we should only balance the nonCached request count for main-thread XHRs and not - // Worker XHRs, as the Cache is not thread-safe. - // This will become irrelevant after https://bugs.webkit.org/show_bug.cgi?id=27165 is resolved. - if (!scriptExecutionContext()->isWorkerContext()) { - ASSERT(isMainThread()); - ASSERT(!m_didTellLoaderAboutRequest); - cache()->loader()->nonCacheRequestInFlight(m_url); - m_didTellLoaderAboutRequest = true; - } - } -} - void XMLHttpRequest::abort() { // internalAbort() calls dropProtection(), which may release the last reference. @@ -709,9 +534,13 @@ void XMLHttpRequest::abort() internalAbort(); + m_responseText = ""; + m_createdDocument = false; + m_responseXML = 0; + // Clear headers as required by the spec m_requestHeaders.clear(); - + if ((m_state <= OPENED && !sendFlag) || m_state == DONE) m_state = UNSENT; else { @@ -720,11 +549,11 @@ void XMLHttpRequest::abort() m_state = UNSENT; } - dispatchAbortEvent(); + dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent)); if (!m_uploadComplete) { m_uploadComplete = true; if (m_upload && m_uploadEventsAllowed) - m_upload->dispatchAbortEvent(); + m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent)); } } @@ -774,11 +603,11 @@ void XMLHttpRequest::genericError() void XMLHttpRequest::networkError() { genericError(); - dispatchErrorEvent(); + dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().errorEvent)); if (!m_uploadComplete) { m_uploadComplete = true; if (m_upload && m_uploadEventsAllowed) - m_upload->dispatchErrorEvent(); + m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().errorEvent)); } internalAbort(); } @@ -786,15 +615,15 @@ void XMLHttpRequest::networkError() void XMLHttpRequest::abortError() { genericError(); - dispatchAbortEvent(); + dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent)); if (!m_uploadComplete) { m_uploadComplete = true; if (m_upload && m_uploadEventsAllowed) - m_upload->dispatchAbortEvent(); + m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent)); } } -void XMLHttpRequest::dropProtection() +void XMLHttpRequest::dropProtection() { #if USE(JSC) // The XHR object itself holds on to the responseText, and @@ -803,10 +632,9 @@ void XMLHttpRequest::dropProtection() // 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 (JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext())) - if (DOMObject* wrapper = getCachedDOMObjectWrapper(*globalObject->globalData(), this)) - JSC::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2); + JSC::JSGlobalData* globalData = scriptExecutionContext()->globalData(); + if (hasCachedDOMObjectWrapper(globalData, this)) + globalData->heap.reportExtraMemoryCost(m_responseText.size() * 2); #endif unsetPendingActivity(this); @@ -854,7 +682,7 @@ void XMLHttpRequest::setRequestHeader(const AtomicString& name, const String& va void XMLHttpRequest::setRequestHeaderInternal(const AtomicString& name, const String& value) { - pair<HTTPHeaderMap::iterator, bool> result = m_requestHeaders.add(name, value); + pair<HTTPHeaderMap::iterator, bool> result = m_requestHeaders.add(name, value); if (!result.second) result.first->second += ", " + value; } @@ -872,7 +700,7 @@ String XMLHttpRequest::getRequestHeader(const AtomicString& name) const String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const { - if (m_state < LOADING) { + if (m_state < HEADERS_RECEIVED) { ec = INVALID_STATE_ERR; return ""; } @@ -906,25 +734,21 @@ String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const String XMLHttpRequest::getResponseHeader(const AtomicString& name, ExceptionCode& ec) const { - if (m_state < LOADING) { + if (m_state < HEADERS_RECEIVED) { ec = INVALID_STATE_ERR; - return ""; + return String(); } - if (!isValidToken(name)) - return ""; - // See comment in getAllResponseHeaders above. if (isSetCookieHeader(name) && !scriptExecutionContext()->securityOrigin()->canLoadLocalResources()) { reportUnsafeUsage(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\""); - return ""; + return String(); } if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name)) { reportUnsafeUsage(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\""); - return ""; + return String(); } - return m_response.httpHeaderField(name); } @@ -939,7 +763,7 @@ String XMLHttpRequest::responseMIMEType() const } if (mimeType.isEmpty()) mimeType = "text/xml"; - + return mimeType; } @@ -981,7 +805,7 @@ void XMLHttpRequest::didFail(const ResourceError& error) cache()->loader()->nonCacheRequestComplete(m_url); m_didTellLoaderAboutRequest = false; } - + // If we are already in an error state, for instance we called abort(), bail out early. if (m_error) return; @@ -1011,11 +835,6 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier) if (m_error) return; - if (m_inPreflight) { - didFinishLoadingPreflight(); - return; - } - if (m_state < HEADERS_RECEIVED) changeState(HEADERS_RECEIVED); @@ -1023,7 +842,9 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier) m_responseText += m_decoder->flush(); scriptExecutionContext()->resourceRetrievedByXMLHttpRequest(identifier, m_responseText); +#if ENABLE(INSPECTOR) scriptExecutionContext()->addMessage(InspectorControllerDestination, JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + m_url + "\".", m_lastSendLineNumber, m_lastSendURL); +#endif bool hadLoader = m_loader; m_loader = 0; @@ -1035,75 +856,29 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier) dropProtection(); } -void XMLHttpRequest::didFinishLoadingPreflight() -{ - 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::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) { if (!m_upload) return; if (m_uploadEventsAllowed) - m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent); + m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, true, static_cast<unsigned>(bytesSent), static_cast<unsigned>(totalBytesToBeSent))); if (bytesSent == totalBytesToBeSent && !m_uploadComplete) { m_uploadComplete = true; if (m_uploadEventsAllowed) - m_upload->dispatchLoadEvent(); + m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent)); } } void XMLHttpRequest::didReceiveResponse(const ResourceResponse& response) { - if (m_inPreflight) { - didReceiveResponsePreflight(response); - return; - } - - if (!m_sameOriginRequest) { - if (!passesAccessControlCheck(response, m_includeCredentials, scriptExecutionContext()->securityOrigin())) { - networkError(); - return; - } - } - m_response = response; m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride); if (m_responseEncoding.isEmpty()) m_responseEncoding = response.textEncodingName(); } -void XMLHttpRequest::didReceiveResponsePreflight(const ResourceResponse& response) -{ - ASSERT(m_inPreflight); - ASSERT(!m_sameOriginRequest); - - if (!passesAccessControlCheck(response, m_includeCredentials, scriptExecutionContext()->securityOrigin())) { - networkError(); - return; - } - - OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult(new CrossOriginPreflightResultCacheItem(m_includeCredentials)); - if (!preflightResult->parse(response) - || !preflightResult->allowsCrossOriginMethod(m_method) - || !preflightResult->allowsCrossOriginHeaders(m_requestHeaders)) { - networkError(); - return; - } - - CrossOriginPreflightResultCache::shared().appendEntry(scriptExecutionContext()->securityOrigin()->toString(), m_url, preflightResult.release()); -} - void XMLHttpRequest::didReceiveAuthenticationCancellation(const ResourceResponse& failureResponse) { m_response = failureResponse; @@ -1111,12 +886,12 @@ void XMLHttpRequest::didReceiveAuthenticationCancellation(const ResourceResponse void XMLHttpRequest::didReceiveData(const char* data, int len) { - if (m_inPreflight || m_error) + if (m_error) return; if (m_state < HEADERS_RECEIVED) changeState(HEADERS_RECEIVED); - + if (!m_decoder) { if (!m_responseEncoding.isEmpty()) m_decoder = TextResourceDecoder::create("text/plain", m_responseEncoding); @@ -1140,7 +915,12 @@ void XMLHttpRequest::didReceiveData(const char* data, int len) m_responseText += m_decoder->decode(data, len); if (!m_error) { - updateAndDispatchOnProgress(len); + 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. + dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, expectedLength && m_receivedLength <= expectedLength, static_cast<unsigned>(m_receivedLength), static_cast<unsigned>(expectedLength))); if (m_state != LOADING) changeState(LOADING); @@ -1150,70 +930,6 @@ void XMLHttpRequest::didReceiveData(const char* data, int len) } } -void XMLHttpRequest::updateAndDispatchOnProgress(unsigned int len) -{ - 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::dispatchReadyStateChangeEvent() -{ - RefPtr<Event> evt = Event::create(eventNames().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); - 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)); -} - bool XMLHttpRequest::canSuspend() const { return !m_loader; @@ -1235,4 +951,14 @@ ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const return ActiveDOMObject::scriptExecutionContext(); } -} // namespace WebCore +EventTargetData* XMLHttpRequest::eventTargetData() +{ + return &m_eventTargetData; +} + +EventTargetData* XMLHttpRequest::ensureEventTargetData() +{ + return &m_eventTargetData; +} + +} // namespace WebCore diff --git a/WebCore/xml/XMLHttpRequest.h b/WebCore/xml/XMLHttpRequest.h index d581d3d..2cea5c6 100644 --- a/WebCore/xml/XMLHttpRequest.h +++ b/WebCore/xml/XMLHttpRequest.h @@ -23,6 +23,7 @@ #include "ActiveDOMObject.h" #include "AtomicStringHash.h" #include "EventListener.h" +#include "EventNames.h" #include "EventTarget.h" #include "FormData.h" #include "ResourceResponse.h" @@ -32,9 +33,9 @@ namespace WebCore { +class Blob; class Document; -class File; -struct ResourceRequest; +class ResourceRequest; class TextResourceDecoder; class ThreadableLoader; @@ -71,7 +72,7 @@ public: void send(ExceptionCode&); void send(Document*, ExceptionCode&); void send(const String&, ExceptionCode&); - void send(File*, ExceptionCode&); + void send(Blob*, ExceptionCode&); void abort(); void setRequestHeader(const AtomicString& name, const String& value, ExceptionCode&); void overrideMimeType(const String& override); @@ -85,41 +86,23 @@ public: 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<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&); - EventListenersMap& eventListeners() { return m_eventListeners; } + DEFINE_ATTRIBUTE_EVENT_LISTENER(readystatechange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); + DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + DEFINE_ATTRIBUTE_EVENT_LISTENER(load); + DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(progress); using RefCounted<XMLHttpRequest>::ref; using RefCounted<XMLHttpRequest>::deref; private: XMLHttpRequest(ScriptExecutionContext*); - + virtual void refEventTarget() { ref(); } virtual void derefEventTarget() { deref(); } + virtual EventTargetData* eventTargetData(); + virtual EventTargetData* ensureEventTargetData(); Document* document() const; @@ -135,12 +118,6 @@ private: virtual void didFailRedirectCheck(); virtual void didReceiveAuthenticationCancellation(const ResourceResponse&); - // Special versions for the preflight - void didReceiveResponsePreflight(const ResourceResponse&); - void didFinishLoadingPreflight(); - - void updateAndDispatchOnProgress(unsigned int len); - String responseMIMEType() const; bool responseIsXML() const; @@ -159,36 +136,10 @@ private: void createRequest(ExceptionCode&); - void makeSameOriginRequest(ExceptionCode&); - void makeCrossOriginAccessRequest(ExceptionCode&); - - void makeSimpleCrossOriginAccessRequest(ExceptionCode&); - void makeCrossOriginAccessRequestWithPreflight(ExceptionCode&); - void handleAsynchronousPreflightResult(); - - void loadRequestSynchronously(ResourceRequest&, ExceptionCode&); - void loadRequestAsynchronously(ResourceRequest&); - 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; @@ -223,16 +174,16 @@ private: bool m_uploadComplete; bool m_sameOriginRequest; - bool m_allowAccess; - bool m_inPreflight; bool m_didTellLoaderAboutRequest; // Used for onprogress tracking long long m_receivedLength; - + unsigned m_lastSendLineNumber; String m_lastSendURL; ExceptionCode m_exceptionCode; + + EventTargetData m_eventTargetData; }; } // namespace WebCore diff --git a/WebCore/xml/XMLHttpRequest.idl b/WebCore/xml/XMLHttpRequest.idl index 79005e2..70cd58a 100644 --- a/WebCore/xml/XMLHttpRequest.idl +++ b/WebCore/xml/XMLHttpRequest.idl @@ -29,7 +29,9 @@ module xml { interface [ + CustomConstructor, CustomMarkFunction, + EventTarget, NoStaticTables ] XMLHttpRequest { // From XMLHttpRequestEventTarget diff --git a/WebCore/xml/XMLHttpRequestException.idl b/WebCore/xml/XMLHttpRequestException.idl index 380e426..7121468 100644 --- a/WebCore/xml/XMLHttpRequestException.idl +++ b/WebCore/xml/XMLHttpRequestException.idl @@ -29,7 +29,6 @@ module xml { interface [ - GenerateConstructor, NoStaticTables ] XMLHttpRequestException { diff --git a/WebCore/xml/XMLHttpRequestProgressEvent.h b/WebCore/xml/XMLHttpRequestProgressEvent.h index 02bfdea..27f3b8c 100644 --- a/WebCore/xml/XMLHttpRequestProgressEvent.h +++ b/WebCore/xml/XMLHttpRequestProgressEvent.h @@ -37,7 +37,7 @@ namespace WebCore { { return adoptRef(new XMLHttpRequestProgressEvent); } - static PassRefPtr<XMLHttpRequestProgressEvent> create(const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total) + static PassRefPtr<XMLHttpRequestProgressEvent> create(const AtomicString& type, bool lengthComputable = false, unsigned loaded = 0, unsigned total = 0) { return adoptRef(new XMLHttpRequestProgressEvent(type, lengthComputable, loaded, total)); } diff --git a/WebCore/xml/XMLHttpRequestProgressEvent.idl b/WebCore/xml/XMLHttpRequestProgressEvent.idl index 549308b..bc5055a 100644 --- a/WebCore/xml/XMLHttpRequestProgressEvent.idl +++ b/WebCore/xml/XMLHttpRequestProgressEvent.idl @@ -26,7 +26,6 @@ module events { interface [ - GenerateConstructor, NoStaticTables // We should also inherit from LSProgressEvent when the idl is added. ] XMLHttpRequestProgressEvent : ProgressEvent { diff --git a/WebCore/xml/XMLHttpRequestUpload.cpp b/WebCore/xml/XMLHttpRequestUpload.cpp index d8a76d5..9d0fafc 100644 --- a/WebCore/xml/XMLHttpRequestUpload.cpp +++ b/WebCore/xml/XMLHttpRequestUpload.cpp @@ -41,11 +41,6 @@ XMLHttpRequestUpload::XMLHttpRequestUpload(XMLHttpRequest* xmlHttpRequest) { } -bool XMLHttpRequestUpload::hasListeners() const -{ - return m_onAbortListener || m_onErrorListener || m_onLoadListener || m_onLoadStartListener || m_onProgressListener || !m_eventListeners.isEmpty(); -} - ScriptExecutionContext* XMLHttpRequestUpload::scriptExecutionContext() const { XMLHttpRequest* xmlHttpRequest = associatedXMLHttpRequest(); @@ -54,95 +49,14 @@ ScriptExecutionContext* XMLHttpRequestUpload::scriptExecutionContext() const 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 || 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() +EventTargetData* XMLHttpRequestUpload::eventTargetData() { - dispatchXMLHttpRequestProgressEvent(m_onLoadStartListener.get(), eventNames().loadstartEvent, false, 0, 0); + return &m_eventTargetData; } -void XMLHttpRequestUpload::dispatchProgressEvent(long long bytesSent, long long totalBytesToBeSent) +EventTargetData* XMLHttpRequestUpload::ensureEventTargetData() { - dispatchXMLHttpRequestProgressEvent(m_onProgressListener.get(), eventNames().progressEvent, true, static_cast<unsigned>(bytesSent), static_cast<unsigned>(totalBytesToBeSent)); + return &m_eventTargetData; } } // namespace WebCore diff --git a/WebCore/xml/XMLHttpRequestUpload.h b/WebCore/xml/XMLHttpRequestUpload.h index b4f40e0..7640643 100644 --- a/WebCore/xml/XMLHttpRequestUpload.h +++ b/WebCore/xml/XMLHttpRequestUpload.h @@ -28,6 +28,7 @@ #include "AtomicStringHash.h" #include "EventListener.h" +#include "EventNames.h" #include "EventTarget.h" #include <wtf/HashMap.h> #include <wtf/RefCounted.h> @@ -48,8 +49,6 @@ namespace WebCore { return adoptRef(new XMLHttpRequestUpload(xmlHttpRequest)); } - bool hasListeners() const; - virtual XMLHttpRequestUpload* toXMLHttpRequestUpload() { return this; } XMLHttpRequest* associatedXMLHttpRequest() const { return m_xmlHttpRequest; } @@ -57,34 +56,11 @@ namespace WebCore { 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; } + DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); + DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + DEFINE_ATTRIBUTE_EVENT_LISTENER(load); + DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(progress); using RefCounted<XMLHttpRequestUpload>::ref; using RefCounted<XMLHttpRequestUpload>::deref; @@ -92,19 +68,13 @@ namespace WebCore { 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; + virtual EventTargetData* eventTargetData(); + virtual EventTargetData* ensureEventTargetData(); XMLHttpRequest* m_xmlHttpRequest; + EventTargetData m_eventTargetData; }; } // namespace WebCore diff --git a/WebCore/xml/XMLHttpRequestUpload.idl b/WebCore/xml/XMLHttpRequestUpload.idl index 3172f68..ce392f3 100644 --- a/WebCore/xml/XMLHttpRequestUpload.idl +++ b/WebCore/xml/XMLHttpRequestUpload.idl @@ -29,8 +29,8 @@ module xml { interface [ - GenerateConstructor, CustomMarkFunction, + EventTarget, NoStaticTables ] XMLHttpRequestUpload { // From XMLHttpRequestEventTarget diff --git a/WebCore/xml/XMLSerializer.idl b/WebCore/xml/XMLSerializer.idl index 6dcc3a4..8c59446 100644 --- a/WebCore/xml/XMLSerializer.idl +++ b/WebCore/xml/XMLSerializer.idl @@ -20,7 +20,7 @@ module xpath { - interface [GenerateConstructor, CanBeConstructed] XMLSerializer { + interface [CanBeConstructed] XMLSerializer { DOMString serializeToString(in Node node) raises(DOMException); }; diff --git a/WebCore/xml/XPathEvaluator.idl b/WebCore/xml/XPathEvaluator.idl index da6155b..c075b01 100644 --- a/WebCore/xml/XPathEvaluator.idl +++ b/WebCore/xml/XPathEvaluator.idl @@ -18,7 +18,7 @@ */ module xpath { - interface [GenerateConstructor, CanBeConstructed, Conditional=XPATH] XPathEvaluator { + interface [CanBeConstructed, Conditional=XPATH] XPathEvaluator { XPathExpression createExpression(in DOMString expression, in XPathNSResolver resolver) raises(core::DOMException); diff --git a/WebCore/xml/XPathException.idl b/WebCore/xml/XPathException.idl index c3c95e3..d5a9af6 100644 --- a/WebCore/xml/XPathException.idl +++ b/WebCore/xml/XPathException.idl @@ -29,7 +29,6 @@ module xpath { interface [ - GenerateConstructor, Conditional=XPATH ] XPathException { diff --git a/WebCore/xml/XPathExpression.idl b/WebCore/xml/XPathExpression.idl index c1fc15e..6b6ceeb 100644 --- a/WebCore/xml/XPathExpression.idl +++ b/WebCore/xml/XPathExpression.idl @@ -22,8 +22,7 @@ module xpath { interface [ - Conditional=XPATH, - GenerateConstructor + Conditional=XPATH ] XPathExpression { [OldStyleObjC] XPathResult evaluate(in Node contextNode, in unsigned short type, diff --git a/WebCore/xml/XPathExpressionNode.h b/WebCore/xml/XPathExpressionNode.h index 74b134e..38070b9 100644 --- a/WebCore/xml/XPathExpressionNode.h +++ b/WebCore/xml/XPathExpressionNode.h @@ -39,7 +39,7 @@ namespace WebCore { namespace XPath { - struct EvaluationContext { + struct EvaluationContext : FastAllocBase { RefPtr<Node> node; unsigned long size; unsigned long position; diff --git a/WebCore/xml/XPathFunctions.cpp b/WebCore/xml/XPathFunctions.cpp index da39443..1089f7c 100644 --- a/WebCore/xml/XPathFunctions.cpp +++ b/WebCore/xml/XPathFunctions.cpp @@ -667,12 +667,13 @@ Value FunRound::evaluate() const return round(arg(0)->evaluate().toNumber()); } +struct FunctionMapping { + const char* name; + FunctionRec function; +}; + static void createFunctionMap() { - struct FunctionMapping { - const char *name; - FunctionRec function; - }; static const FunctionMapping functions[] = { { "boolean", { &createFunBoolean, 1 } }, { "ceiling", { &createFunCeiling, 1 } }, diff --git a/WebCore/xml/XPathNSResolver.idl b/WebCore/xml/XPathNSResolver.idl index 48c0113..4e996c2 100644 --- a/WebCore/xml/XPathNSResolver.idl +++ b/WebCore/xml/XPathNSResolver.idl @@ -20,7 +20,7 @@ module xpath { - interface [ObjCProtocol, Conditional=XPATH] XPathNSResolver { + interface [ObjCProtocol, Conditional=XPATH, OmitConstructor] XPathNSResolver { [ConvertNullStringTo=Null] DOMString lookupNamespaceURI(in DOMString prefix); }; diff --git a/WebCore/xml/XPathNamespace.cpp b/WebCore/xml/XPathNamespace.cpp index 3c8c42c..9646402 100644 --- a/WebCore/xml/XPathNamespace.cpp +++ b/WebCore/xml/XPathNamespace.cpp @@ -1,6 +1,6 @@ /* * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,18 +33,14 @@ namespace WebCore { -XPathNamespace::XPathNamespace(PassRefPtr<Element> ownerElement, const String& prefix, const String& uri) - : Node(ownerElement->document()) +XPathNamespace::XPathNamespace(PassRefPtr<Element> ownerElement, const AtomicString& prefix, const AtomicString& uri) + : Node(ownerElement->document(), CreateOther) , m_ownerElement(ownerElement) , m_prefix(prefix) , m_uri(uri) { } -XPathNamespace::~XPathNamespace() -{ -} - Document* XPathNamespace::ownerDocument() const { return m_ownerElement->ownerDocument(); diff --git a/WebCore/xml/XPathNamespace.h b/WebCore/xml/XPathNamespace.h index c0e4280..996cb9a 100644 --- a/WebCore/xml/XPathNamespace.h +++ b/WebCore/xml/XPathNamespace.h @@ -1,6 +1,6 @@ /* * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,13 +34,11 @@ namespace WebCore { - class Document; - class Element; + // FIXME: This class is never instantiated. Maybe it should be removed. class XPathNamespace : public Node { - public: - XPathNamespace(PassRefPtr<Element> ownerElement, const String& prefix, const String& uri); - virtual ~XPathNamespace(); + private: + XPathNamespace(PassRefPtr<Element> ownerElement, const AtomicString& prefix, const AtomicString& uri); virtual Document* ownerDocument() const; virtual Element* ownerElement() const; @@ -50,9 +48,8 @@ namespace WebCore { virtual String nodeValue() const; virtual const AtomicString& namespaceURI() const; - virtual Node::NodeType nodeType() const; + virtual NodeType nodeType() const; - private: RefPtr<Element> m_ownerElement; AtomicString m_prefix; AtomicString m_uri; diff --git a/WebCore/xml/XPathNodeSet.h b/WebCore/xml/XPathNodeSet.h index 1130488..d5c47be 100644 --- a/WebCore/xml/XPathNodeSet.h +++ b/WebCore/xml/XPathNodeSet.h @@ -37,7 +37,7 @@ namespace WebCore { namespace XPath { - class NodeSet { + class NodeSet : public FastAllocBase { public: NodeSet() : m_isSorted(true), m_subtreesAreDisjoint(false) { } diff --git a/WebCore/xml/XPathResult.idl b/WebCore/xml/XPathResult.idl index bc36c3e..ebbff42 100644 --- a/WebCore/xml/XPathResult.idl +++ b/WebCore/xml/XPathResult.idl @@ -19,7 +19,7 @@ module xpath { - interface [GenerateConstructor, Conditional=XPATH] XPathResult { + interface [Conditional=XPATH] XPathResult { const unsigned short ANY_TYPE = 0; const unsigned short NUMBER_TYPE = 1; const unsigned short STRING_TYPE = 2; diff --git a/WebCore/xml/XPathStep.cpp b/WebCore/xml/XPathStep.cpp index 411b616..6e60952 100644 --- a/WebCore/xml/XPathStep.cpp +++ b/WebCore/xml/XPathStep.cpp @@ -34,6 +34,7 @@ #include "Document.h" #include "Element.h" #include "NamedNodeMap.h" +#include "XMLNSNames.h" #include "XPathParser.h" #include "XPathUtil.h" @@ -173,7 +174,7 @@ static inline bool nodeMatchesBasicTest(Node* node, Step::Axis axis, const Step: ASSERT(node->isAttributeNode()); // In XPath land, namespace nodes are not accessible on the attribute axis. - if (node->namespaceURI() == "http://www.w3.org/2000/xmlns/") + if (node->namespaceURI() == XMLNSNames::xmlnsNamespaceURI) return false; if (name == starAtom) @@ -193,9 +194,13 @@ static inline bool nodeMatchesBasicTest(Node* node, Step::Axis axis, const Step: if (name == starAtom) return namespaceURI.isEmpty() || namespaceURI == node->namespaceURI(); - if (node->isHTMLElement() && node->document()->isHTMLDocument()) { - // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace. Names are compared case-insensitively. - return equalIgnoringCase(static_cast<Element*>(node)->localName(), name) && (namespaceURI.isNull() || namespaceURI == node->namespaceURI()); + if (node->document()->isHTMLDocument()) { + if (node->isHTMLElement()) { + // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace. Names are compared case-insensitively. + return equalIgnoringCase(static_cast<Element*>(node)->localName(), name) && (namespaceURI.isNull() || namespaceURI == node->namespaceURI()); + } + // An expression without any prefix shouldn't match no-namespace nodes (because HTML5 says so). + return static_cast<Element*>(node)->hasLocalName(name) && namespaceURI == node->namespaceURI() && !namespaceURI.isNull(); } return static_cast<Element*>(node)->hasLocalName(name) && namespaceURI == node->namespaceURI(); } @@ -331,7 +336,7 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const // Avoid lazily creating attribute nodes for attributes that we do not need anyway. if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != starAtom) { RefPtr<Node> n = static_cast<Element*>(context)->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data()); - if (n && n->namespaceURI() != "http://www.w3.org/2000/xmlns/") { // In XPath land, namespace nodes are not accessible on the attribute axis. + if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis. if (nodeMatches(n.get(), AttributeAxis, m_nodeTest)) // Still need to check merged predicates. nodes.append(n.release()); } diff --git a/WebCore/xml/XPathStep.h b/WebCore/xml/XPathStep.h index 11612e9..ec022b3 100644 --- a/WebCore/xml/XPathStep.h +++ b/WebCore/xml/XPathStep.h @@ -49,7 +49,7 @@ namespace WebCore { SelfAxis }; - class NodeTest { + class NodeTest : public FastAllocBase { public: enum Kind { TextNodeTest, CommentNodeTest, ProcessingInstructionNodeTest, AnyNodeTest, NameTest diff --git a/WebCore/xml/XSLImportRule.cpp b/WebCore/xml/XSLImportRule.cpp index 6ceb108..0908d75 100644 --- a/WebCore/xml/XSLImportRule.cpp +++ b/WebCore/xml/XSLImportRule.cpp @@ -52,13 +52,13 @@ XSLStyleSheet* XSLImportRule::parentStyleSheet() const return (parent() && parent()->isXSLStyleSheet()) ? static_cast<XSLStyleSheet*>(parent()) : 0; } -void XSLImportRule::setXSLStyleSheet(const String& url, const String& sheet) +void XSLImportRule::setXSLStyleSheet(const String& href, const KURL& baseURL, const String& sheet) { if (m_styleSheet) m_styleSheet->setParent(0); - - m_styleSheet = XSLStyleSheet::create(this, url); - + + m_styleSheet = XSLStyleSheet::create(this, href, baseURL); + XSLStyleSheet* parent = parentStyleSheet(); if (parent) m_styleSheet->setParentStyleSheet(parent); @@ -87,14 +87,14 @@ void XSLImportRule::loadSheet() String absHref = m_strHref; XSLStyleSheet* parentSheet = parentStyleSheet(); - if (!parentSheet->href().isNull()) + if (!parentSheet->finalURL().isNull()) // use parent styleheet's URL as the base URL - absHref = KURL(KURL(parentSheet->href()), m_strHref).string(); + absHref = KURL(parentSheet->finalURL(), 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 = this->parent(); parent; parent = parent->parent()) { - if (parent->isXSLStyleSheet() && absHref == static_cast<XSLStyleSheet*>(parent)->href()) + if (parent->isXSLStyleSheet() && absHref == static_cast<XSLStyleSheet*>(parent)->finalURL().string()) return; } diff --git a/WebCore/xml/XSLImportRule.h b/WebCore/xml/XSLImportRule.h index fc7a7f8..f3a9318 100644 --- a/WebCore/xml/XSLImportRule.h +++ b/WebCore/xml/XSLImportRule.h @@ -57,7 +57,7 @@ private: virtual bool isImportRule() { return true; } // from CachedResourceClient - virtual void setXSLStyleSheet(const String& url, const String& sheet); + virtual void setXSLStyleSheet(const String& href, const KURL& baseURL, const String& sheet); String m_strHref; RefPtr<XSLStyleSheet> m_styleSheet; diff --git a/WebCore/xml/XSLStyleSheet.h b/WebCore/xml/XSLStyleSheet.h index fe97b54..e6e4063 100644 --- a/WebCore/xml/XSLStyleSheet.h +++ b/WebCore/xml/XSLStyleSheet.h @@ -26,8 +26,12 @@ #if ENABLE(XSLT) #include "StyleSheet.h" + +#if !USE(QXMLQUERY) #include <libxml/parser.h> #include <libxslt/transform.h> +#endif + #include <wtf/PassRefPtr.h> namespace WebCore { @@ -38,17 +42,19 @@ class XSLImportRule; class XSLStyleSheet : public StyleSheet { public: - static PassRefPtr<XSLStyleSheet> create(XSLImportRule* parentImport, const String& href) +#if !USE(QXMLQUERY) + static PassRefPtr<XSLStyleSheet> create(XSLImportRule* parentImport, const String& originalURL, const KURL& finalURL) { - return adoptRef(new XSLStyleSheet(parentImport, href)); + return adoptRef(new XSLStyleSheet(parentImport, originalURL, finalURL)); } - static PassRefPtr<XSLStyleSheet> create(Node* parentNode, const String& href) +#endif + static PassRefPtr<XSLStyleSheet> create(Node* parentNode, const String& originalURL, const KURL& finalURL) { - return adoptRef(new XSLStyleSheet(parentNode, href, false)); + return adoptRef(new XSLStyleSheet(parentNode, originalURL, finalURL, false)); } - static PassRefPtr<XSLStyleSheet> createEmbedded(Node* parentNode, const String& href) + static PassRefPtr<XSLStyleSheet> createInline(Node* parentNode, const KURL& finalURL) { - return adoptRef(new XSLStyleSheet(parentNode, href, true)); + return adoptRef(new XSLStyleSheet(parentNode, finalURL.string(), finalURL, true)); } virtual ~XSLStyleSheet(); @@ -65,31 +71,41 @@ public: void loadChildSheets(); void loadChildSheet(const String& href); - xsltStylesheetPtr compileStyleSheet(); - DocLoader* docLoader(); Document* ownerDocument() { return m_ownerDocument; } void setParentStyleSheet(XSLStyleSheet* parent); +#if USE(QXMLQUERY) + String sheetString() const { return m_sheetString; } +#else xmlDocPtr document(); + xsltStylesheetPtr compileStyleSheet(); + xmlDocPtr locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri); +#endif void clearDocuments(); - xmlDocPtr locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri); - void markAsProcessed(); bool processed() const { return m_processed; } private: - XSLStyleSheet(Node* parentNode, const String& href, bool embedded); - XSLStyleSheet(XSLImportRule* parentImport, const String& href); + XSLStyleSheet(Node* parentNode, const String& originalURL, const KURL& finalURL, bool embedded); +#if !USE(QXMLQUERY) + XSLStyleSheet(XSLImportRule* parentImport, const String& originalURL, const KURL& finalURL); +#endif Document* m_ownerDocument; - xmlDocPtr m_stylesheetDoc; bool m_embedded; bool m_processed; + +#if USE(QXMLQUERY) + String m_sheetString; +#else + xmlDocPtr m_stylesheetDoc; bool m_stylesheetDocTaken; +#endif + XSLStyleSheet* m_parentStyleSheet; }; diff --git a/WebCore/xml/XSLStyleSheet.cpp b/WebCore/xml/XSLStyleSheetLibxslt.cpp index b7d52f8..dbd806a 100644 --- a/WebCore/xml/XSLStyleSheet.cpp +++ b/WebCore/xml/XSLStyleSheetLibxslt.cpp @@ -31,6 +31,7 @@ #include "Document.h" #include "Frame.h" #include "Node.h" +#include "TransformSource.h" #include "XMLTokenizer.h" #include "XMLTokenizerScope.h" #include "XSLImportRule.h" @@ -54,23 +55,23 @@ SOFT_LINK(libxslt, xsltLoadStylesheetPI, xsltStylesheetPtr, (xmlDocPtr doc), (do namespace WebCore { -XSLStyleSheet::XSLStyleSheet(XSLImportRule* parentRule, const String& href) - : StyleSheet(parentRule, href) +XSLStyleSheet::XSLStyleSheet(XSLImportRule* parentRule, const String& originalURL, const KURL& finalURL) + : StyleSheet(parentRule, originalURL, finalURL) , m_ownerDocument(0) - , m_stylesheetDoc(0) , m_embedded(false) , m_processed(false) // Child sheets get marked as processed when the libxslt engine has finally seen them. + , m_stylesheetDoc(0) , m_stylesheetDocTaken(false) , m_parentStyleSheet(0) { } -XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& href, bool embedded) - : StyleSheet(parentNode, href) +XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& originalURL, const KURL& finalURL, bool embedded) + : StyleSheet(parentNode, originalURL, finalURL) , m_ownerDocument(parentNode->document()) - , m_stylesheetDoc(0) , m_embedded(embedded) , m_processed(true) // The root sheet starts off processed. + , m_stylesheetDoc(0) , m_stylesheetDocTaken(false) , m_parentStyleSheet(0) { @@ -98,7 +99,7 @@ bool XSLStyleSheet::isLoading() void XSLStyleSheet::checkLoaded() { - if (isLoading()) + if (isLoading()) return; if (parent()) parent()->checkLoaded(); @@ -108,8 +109,8 @@ void XSLStyleSheet::checkLoaded() xmlDocPtr XSLStyleSheet::document() { - if (m_embedded && ownerDocument()) - return (xmlDocPtr)ownerDocument()->transformSource(); + if (m_embedded && ownerDocument() && ownerDocument()->transformSource()) + return (xmlDocPtr)ownerDocument()->transformSource()->platformSource(); return m_stylesheetDoc; } @@ -167,8 +168,8 @@ bool XSLStyleSheet::parseString(const String& string, bool) } m_stylesheetDoc = xmlCtxtReadMemory(ctxt, buffer, size, - href().utf8().data(), - BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", + finalURL().string().utf8().data(), + BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_NOWARNING | XML_PARSE_NOCDATA); xmlFreeParserCtxt(ctxt); @@ -181,17 +182,17 @@ void XSLStyleSheet::loadChildSheets() { if (!document()) return; - + xmlNodePtr stylesheetRoot = document()->children; - + // Top level children may include other things such as DTD nodes, we ignore those. while (stylesheetRoot && stylesheetRoot->type != XML_ELEMENT_NODE) stylesheetRoot = stylesheetRoot->next; - + if (m_embedded) { - // We have to locate (by ID) the appropriate embedded stylesheet element, so that we can walk the + // We have to locate (by ID) the appropriate embedded stylesheet element, so that we can walk the // import/include list. - xmlAttrPtr idNode = xmlGetID(document(), (const xmlChar*)(href().utf8().data())); + xmlAttrPtr idNode = xmlGetID(document(), (const xmlChar*)(finalURL().string().utf8().data())); if (!idNode) return; stylesheetRoot = idNode->parent; @@ -199,7 +200,7 @@ void XSLStyleSheet::loadChildSheets() // FIXME: Need to handle an external URI with a # in it. This is a pretty minor edge case, so we'll deal // with it later. } - + if (stylesheetRoot) { // Walk the children of the root element and look for import/include elements. // Imports must occur first. @@ -210,7 +211,7 @@ void XSLStyleSheet::loadChildSheets() continue; } if (IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "import")) { - xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE); + xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE); loadChildSheet(String::fromUTF8((const char*)uriRef)); xmlFree(uriRef); } else @@ -242,7 +243,7 @@ xsltStylesheetPtr XSLStyleSheet::compileStyleSheet() // FIXME: Hook up error reporting for the stylesheet compilation process. if (m_embedded) return xsltLoadStylesheetPI(document()); - + // xsltParseStylesheetDoc makes the document part of the stylesheet // so we have to release our pointer to it. ASSERT(!m_stylesheetDocTaken); @@ -273,7 +274,7 @@ xmlDocPtr XSLStyleSheet::locateStylesheetSubResource(xmlDocPtr parentDoc, const if (matchedParent) { if (child->processed()) continue; // libxslt has been given this sheet already. - + // Check the URI of the child stylesheet against the doc URI. // In order to ensure that libxml canonicalized both URLs, we get the original href // string from the import rule and canonicalize it using libxml before comparing it @@ -295,7 +296,7 @@ xmlDocPtr XSLStyleSheet::locateStylesheetSubResource(xmlDocPtr parentDoc, const } } } - + return 0; } diff --git a/WebCore/xml/XSLStyleSheetQt.cpp b/WebCore/xml/XSLStyleSheetQt.cpp new file mode 100644 index 0000000..cb55993 --- /dev/null +++ b/WebCore/xml/XSLStyleSheetQt.cpp @@ -0,0 +1,103 @@ +/* + * This file is part of the XSL implementation. + * + * Copyright (C) 2009 Jakub Wieczorek <faw217@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "XSLStyleSheet.h" + +#if ENABLE(XSLT) + +#include "DOMWindow.h" +#include "Document.h" +#include "Node.h" +#include "NotImplemented.h" +#include "XSLTProcessor.h" +#include "loader.h" + +namespace WebCore { + +XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& originalURL, const KURL& finalURL, bool embedded) + : StyleSheet(parentNode, originalURL, finalURL) + , m_ownerDocument(parentNode->document()) + , m_embedded(embedded) +{ +} + +XSLStyleSheet::~XSLStyleSheet() +{ +} + +bool XSLStyleSheet::isLoading() +{ + notImplemented(); + return false; +} + +void XSLStyleSheet::checkLoaded() +{ + if (ownerNode()) + ownerNode()->sheetLoaded(); +} + +void XSLStyleSheet::clearDocuments() +{ + notImplemented(); +} + +DocLoader* XSLStyleSheet::docLoader() +{ + if (!m_ownerDocument) + return 0; + return m_ownerDocument->docLoader(); +} + +bool XSLStyleSheet::parseString(const String& string, bool) +{ + // FIXME: Fix QXmlQuery so that it allows compiling the stylesheet before setting the document + // to be transformed. This way we could not only check if the stylesheet is correct before using it + // but also turn XSLStyleSheet::sheetString() into XSLStyleSheet::query() that returns a QXmlQuery. + + m_sheetString = string; + return !m_sheetString.isEmpty(); +} + +void XSLStyleSheet::loadChildSheets() +{ + notImplemented(); +} + +void XSLStyleSheet::loadChildSheet(const String&) +{ + notImplemented(); +} + +void XSLStyleSheet::setParentStyleSheet(XSLStyleSheet*) +{ + notImplemented(); +} + +void XSLStyleSheet::markAsProcessed() +{ + notImplemented(); +} + +} // namespace WebCore + +#endif // ENABLE(XSLT) diff --git a/WebCore/xml/XSLTProcessor.cpp b/WebCore/xml/XSLTProcessor.cpp index a26fe77..b182243 100644 --- a/WebCore/xml/XSLTProcessor.cpp +++ b/WebCore/xml/XSLTProcessor.cpp @@ -26,10 +26,7 @@ #include "XSLTProcessor.h" -#include "CString.h" -#include "Console.h" #include "DOMImplementation.h" -#include "DOMWindow.h" #include "DocLoader.h" #include "DocumentFragment.h" #include "Frame.h" @@ -38,166 +35,17 @@ #include "HTMLDocument.h" #include "HTMLTokenizer.h" // for parseHTMLDocumentFragment #include "Page.h" -#include "ResourceError.h" -#include "ResourceHandle.h" -#include "ResourceRequest.h" -#include "ResourceResponse.h" #include "Text.h" #include "TextResourceDecoder.h" #include "XMLTokenizer.h" -#include "XSLTExtensions.h" -#include "XSLTUnicodeSort.h" #include "loader.h" #include "markup.h" -#include <libxslt/imports.h> -#include <libxslt/variables.h> -#include <libxslt/xsltutils.h> #include <wtf/Assertions.h> #include <wtf/Platform.h> #include <wtf/Vector.h> -#if PLATFORM(MAC) -#include "SoftLinking.h" - -SOFT_LINK_LIBRARY(libxslt); -SOFT_LINK(libxslt, xsltFreeStylesheet, void, (xsltStylesheetPtr sheet), (sheet)) -SOFT_LINK(libxslt, xsltFreeTransformContext, void, (xsltTransformContextPtr ctxt), (ctxt)) -SOFT_LINK(libxslt, xsltNewTransformContext, xsltTransformContextPtr, (xsltStylesheetPtr style, xmlDocPtr doc), (style, doc)) -SOFT_LINK(libxslt, xsltApplyStylesheetUser, xmlDocPtr, (xsltStylesheetPtr style, xmlDocPtr doc, const char** params, const char* output, FILE* profile, xsltTransformContextPtr userCtxt), (style, doc, params, output, profile, userCtxt)) -SOFT_LINK(libxslt, xsltQuoteUserParams, int, (xsltTransformContextPtr ctxt, const char** params), (ctxt, params)) -SOFT_LINK(libxslt, xsltSetCtxtSortFunc, void, (xsltTransformContextPtr ctxt, xsltSortFunc handler), (ctxt, handler)) -SOFT_LINK(libxslt, xsltSetLoaderFunc, void, (xsltDocLoaderFunc f), (f)) -SOFT_LINK(libxslt, xsltSaveResultTo, int, (xmlOutputBufferPtr buf, xmlDocPtr result, xsltStylesheetPtr style), (buf, result, style)) -SOFT_LINK(libxslt, xsltNextImport, xsltStylesheetPtr, (xsltStylesheetPtr style), (style)) -#endif - namespace WebCore { -void XSLTProcessor::genericErrorFunc(void*, const char*, ...) -{ - // It would be nice to do something with this error message. -} - -void XSLTProcessor::parseErrorFunc(void* userData, xmlError* error) -{ - Console* console = static_cast<Console*>(userData); - if (!console) - return; - - MessageLevel level; - switch (error->level) { - case XML_ERR_NONE: - level = TipMessageLevel; - break; - case XML_ERR_WARNING: - level = WarningMessageLevel; - break; - case XML_ERR_ERROR: - case XML_ERR_FATAL: - default: - level = ErrorMessageLevel; - break; - } - - console->addMessage(XMLMessageSource, LogMessageType, 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. -static XSLTProcessor* globalProcessor = 0; -static DocLoader* globalDocLoader = 0; -static xmlDocPtr docLoaderFunc(const xmlChar* uri, - xmlDictPtr, - int options, - void* ctxt, - xsltLoadType type) -{ - if (!globalProcessor) - return 0; - - switch (type) { - case XSLT_LOAD_DOCUMENT: { - xsltTransformContextPtr context = (xsltTransformContextPtr)ctxt; - xmlChar* base = xmlNodeGetBase(context->document->doc, context->node); - KURL url(KURL(reinterpret_cast<const char*>(base)), reinterpret_cast<const char*>(uri)); - xmlFree(base); - ResourceError error; - ResourceResponse response; - - Vector<char> data; - - bool requestAllowed = globalDocLoader->frame() && globalDocLoader->doc()->securityOrigin()->canRequest(url); - if (requestAllowed) { - globalDocLoader->frame()->loader()->loadResourceSynchronously(url, AllowStoredCredentials, error, response, data); - 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; - } - case XSLT_LOAD_STYLESHEET: - return globalProcessor->xslStylesheet()->locateStylesheetSubResource(((xsltStylesheetPtr)ctxt)->doc, uri); - default: - break; - } - - return 0; -} - -static inline void setXSLTLoadCallBack(xsltDocLoaderFunc func, XSLTProcessor* processor, DocLoader* loader) -{ - xsltSetLoaderFunc(func); - globalProcessor = processor; - globalDocLoader = loader; -} - -static int writeToVector(void* context, const char* buffer, int len) -{ - Vector<UChar>& resultOutput = *static_cast<Vector<UChar>*>(context); - String decodedChunk = String::fromUTF8(buffer, len); - resultOutput.append(decodedChunk.characters(), decodedChunk.length()); - return len; -} - -static bool saveResultToString(xmlDocPtr resultDoc, xsltStylesheetPtr sheet, String& resultString) -{ - xmlOutputBufferPtr outputBuf = xmlAllocOutputBuffer(0); - if (!outputBuf) - return false; - - Vector<UChar> resultVector; - outputBuf->context = &resultVector; - outputBuf->writecallback = writeToVector; - - int retval = xsltSaveResultTo(outputBuf, resultDoc, sheet); - xmlOutputBufferClose(outputBuf); - if (retval < 0) - return false; - - // Workaround for <http://bugzilla.gnome.org/show_bug.cgi?id=495668>: libxslt appends an extra line feed to the result. - if (resultVector.size() > 0 && resultVector[resultVector.size() - 1] == '\n') - resultVector.removeLast(); - - resultString = String::adopt(resultVector); - - return true; -} - static inline void transformTextStringToXHTMLDocumentString(String& text) { // Modify the output so that it is a well-formed XHTML document with a <pre> tag enclosing the text. @@ -213,38 +61,6 @@ static inline void transformTextStringToXHTMLDocumentString(String& text) "</html>\n"; } -static const char** xsltParamArrayFromParameterMap(XSLTProcessor::ParameterMap& parameters) -{ - if (parameters.isEmpty()) - return 0; - - const char** parameterArray = (const char**)fastMalloc(((parameters.size() * 2) + 1) * sizeof(char*)); - - XSLTProcessor::ParameterMap::iterator end = parameters.end(); - unsigned index = 0; - for (XSLTProcessor::ParameterMap::iterator it = parameters.begin(); it != end; ++it) { - parameterArray[index++] = strdup(it->first.utf8().data()); - parameterArray[index++] = strdup(it->second.utf8().data()); - } - parameterArray[index] = 0; - - return parameterArray; -} - -static void freeXsltParamArray(const char** params) -{ - const char** temp = params; - if (!params) - return; - - while (*temp) { - free((void*)*(temp++)); // strdup returns malloc'd blocks, so we have to use free() here - free((void*)*(temp++)); - } - fastFree(params); -} - - PassRefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourceString, const String& sourceEncoding, const String& sourceMIMEType, Node* sourceNode, Frame* frame) { @@ -258,7 +74,7 @@ PassRefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourc transformTextStringToXHTMLDocumentString(documentSource); } else result = ownerDocument->implementation()->createDocument(sourceMIMEType, frame, false); - + // Before parsing, we need to save & detach the old document and get the new document // in place. We have to do this only if we're rendering the result document. if (frame) { @@ -267,15 +83,15 @@ PassRefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourc result->setTransformSourceDocument(frame->document()); frame->setDocument(result); } - + if (sourceIsDocument) result->setURL(ownerDocument->url()); result->open(); - + RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create(sourceMIMEType); decoder->setEncoding(sourceEncoding.isEmpty() ? UTF8Encoding() : TextEncoding(sourceEncoding), TextResourceDecoder::EncodingFromXMLHeader); result->setDecoder(decoder.release()); - + result->write(documentSource); result->finishParsing(); result->close(); @@ -285,129 +101,21 @@ PassRefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourc static inline RefPtr<DocumentFragment> createFragmentFromSource(const String& sourceString, const String& sourceMIMEType, Document* outputDoc) { - RefPtr<DocumentFragment> fragment = new DocumentFragment(outputDoc); - + RefPtr<DocumentFragment> fragment = DocumentFragment::create(outputDoc); + if (sourceMIMEType == "text/html") parseHTMLDocumentFragment(sourceString, fragment.get()); else if (sourceMIMEType == "text/plain") - fragment->addChild(new Text(outputDoc, sourceString)); + fragment->addChild(Text::create(outputDoc, sourceString)); else { bool successfulParse = parseXMLDocumentFragment(sourceString, fragment.get(), outputDoc->documentElement()); if (!successfulParse) return 0; } - - // FIXME: Do we need to mess with URLs here? - - return fragment; -} - -static xsltStylesheetPtr xsltStylesheetPointer(RefPtr<XSLStyleSheet>& cachedStylesheet, Node* stylesheetRootNode) -{ - if (!cachedStylesheet && stylesheetRootNode) { - cachedStylesheet = XSLStyleSheet::create(stylesheetRootNode->parent() ? stylesheetRootNode->parent() : stylesheetRootNode, - stylesheetRootNode->document()->url().string()); - cachedStylesheet->parseString(createMarkup(stylesheetRootNode)); - } - - if (!cachedStylesheet || !cachedStylesheet->document()) - return 0; - - return cachedStylesheet->compileStyleSheet(); -} -static inline xmlDocPtr xmlDocPtrFromNode(Node* sourceNode, bool& shouldDelete) -{ - RefPtr<Document> ownerDocument = sourceNode->document(); - bool sourceIsDocument = (sourceNode == ownerDocument.get()); - - xmlDocPtr sourceDoc = 0; - if (sourceIsDocument) - sourceDoc = (xmlDocPtr)ownerDocument->transformSource(); - if (!sourceDoc) { - sourceDoc = (xmlDocPtr)xmlDocPtrForString(ownerDocument->docLoader(), createMarkup(sourceNode), - sourceIsDocument ? ownerDocument->url().string() : String()); - shouldDelete = (sourceDoc != 0); - } - return sourceDoc; -} - -static inline String resultMIMEType(xmlDocPtr resultDoc, xsltStylesheetPtr sheet) -{ - // There are three types of output we need to be able to deal with: - // HTML (create an HTML document), XML (create an XML document), - // and text (wrap in a <pre> and create an XML document). - - const xmlChar* resultType = 0; - XSLT_GET_IMPORT_PTR(resultType, sheet, method); - if (resultType == 0 && resultDoc->type == XML_HTML_DOCUMENT_NODE) - resultType = (const xmlChar*)"html"; - - if (xmlStrEqual(resultType, (const xmlChar*)"html")) - return "text/html"; - else if (xmlStrEqual(resultType, (const xmlChar*)"text")) - return "text/plain"; - - return "application/xml"; -} - -bool XSLTProcessor::transformToString(Node* sourceNode, String& mimeType, String& resultString, String& resultEncoding) -{ - RefPtr<Document> ownerDocument = sourceNode->document(); - - setXSLTLoadCallBack(docLoaderFunc, this, ownerDocument->docLoader()); - xsltStylesheetPtr sheet = xsltStylesheetPointer(m_stylesheet, m_stylesheetRootNode.get()); - if (!sheet) { - setXSLTLoadCallBack(0, 0, 0); - return false; - } - m_stylesheet->clearDocuments(); - - xmlChar* origMethod = sheet->method; - if (!origMethod && mimeType == "text/html") - sheet->method = (xmlChar*)"html"; - - bool success = false; - bool shouldFreeSourceDoc = false; - if (xmlDocPtr sourceDoc = xmlDocPtrFromNode(sourceNode, shouldFreeSourceDoc)) { - // The XML declaration would prevent parsing the result as a fragment, and it's not needed even for documents, - // as the result of this function is always immediately parsed. - sheet->omitXmlDeclaration = true; - - xsltTransformContextPtr transformContext = xsltNewTransformContext(sheet, sourceDoc); - registerXSLTExtensions(transformContext); - - // <http://bugs.webkit.org/show_bug.cgi?id=16077>: XSLT processor <xsl:sort> algorithm only compares by code point - xsltSetCtxtSortFunc(transformContext, xsltUnicodeSortFunction); - - // This is a workaround for a bug in libxslt. - // The bug has been fixed in version 1.1.13, so once we ship that this can be removed. - if (transformContext->globalVars == NULL) - transformContext->globalVars = xmlHashCreate(20); - - const char** params = xsltParamArrayFromParameterMap(m_parameters); - xsltQuoteUserParams(transformContext, params); - xmlDocPtr resultDoc = xsltApplyStylesheetUser(sheet, sourceDoc, 0, 0, 0, transformContext); - - xsltFreeTransformContext(transformContext); - freeXsltParamArray(params); - - if (shouldFreeSourceDoc) - xmlFreeDoc(sourceDoc); - - if (success = saveResultToString(resultDoc, sheet, resultString)) { - mimeType = resultMIMEType(resultDoc, sheet); - resultEncoding = (char*)resultDoc->encoding; - } - xmlFreeDoc(resultDoc); - } - - sheet->method = origMethod; - setXSLTLoadCallBack(0, 0, 0); - xsltFreeStylesheet(sheet); - m_stylesheet = 0; + // FIXME: Do we need to mess with URLs here? - return success; + return fragment; } PassRefPtr<Document> XSLTProcessor::transformToDocument(Node* sourceNode) @@ -429,7 +137,7 @@ PassRefPtr<DocumentFragment> XSLTProcessor::transformToFragment(Node* sourceNode // If the output document is HTML, default to HTML method. if (outputDoc->isHTMLDocument()) resultMIMEType = "text/html"; - + if (!transformToString(sourceNode, resultMIMEType, resultString, resultEncoding)) return 0; return createFragmentFromSource(resultString, resultMIMEType, outputDoc); @@ -455,6 +163,13 @@ void XSLTProcessor::removeParameter(const String& /*namespaceURI*/, const String m_parameters.remove(localName); } +void XSLTProcessor::reset() +{ + m_stylesheet.clear(); + m_stylesheetRootNode.clear(); + m_parameters.clear(); +} + } // namespace WebCore #endif // ENABLE(XSLT) diff --git a/WebCore/xml/XSLTProcessor.h b/WebCore/xml/XSLTProcessor.h index 9ee2aad..9b91017 100644 --- a/WebCore/xml/XSLTProcessor.h +++ b/WebCore/xml/XSLTProcessor.h @@ -28,9 +28,12 @@ #include "Node.h" #include "StringHash.h" #include "XSLStyleSheet.h" +#include <wtf/HashMap.h> + +#if !USE(QXMLQUERY) #include <libxml/parserInternals.h> #include <libxslt/documents.h> -#include <wtf/HashMap.h> +#endif namespace WebCore { @@ -56,14 +59,15 @@ public: void removeParameter(const String& namespaceURI, const String& localName); void clearParameters() { m_parameters.clear(); } - void reset() { m_stylesheet.clear(); m_stylesheetRootNode.clear(); m_parameters.clear(); } + void reset(); +#if !USE(QXMLQUERY) 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(); } +#endif typedef HashMap<String, String> ParameterMap; diff --git a/WebCore/xml/XSLTProcessor.idl b/WebCore/xml/XSLTProcessor.idl index 0a6ff93..28bd878 100644 --- a/WebCore/xml/XSLTProcessor.idl +++ b/WebCore/xml/XSLTProcessor.idl @@ -33,7 +33,8 @@ module xml { // http://bugs.webkit.org/show_bug.cgi?id=5446 interface [ - Conditional=XSLT + Conditional=XSLT, + CustomConstructor ] XSLTProcessor { [Custom] void importStylesheet(in Node stylesheet); diff --git a/WebCore/xml/XSLTProcessorLibxslt.cpp b/WebCore/xml/XSLTProcessorLibxslt.cpp new file mode 100644 index 0000000..e2da3ed --- /dev/null +++ b/WebCore/xml/XSLTProcessorLibxslt.cpp @@ -0,0 +1,336 @@ +/* + * This file is part of the XSL implementation. + * + * 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 + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(XSLT) + +#include "XSLTProcessor.h" + +#include "Console.h" +#include "CString.h" +#include "DOMWindow.h" +#include "DocLoader.h" +#include "Frame.h" +#include "ResourceError.h" +#include "ResourceHandle.h" +#include "ResourceRequest.h" +#include "ResourceResponse.h" +#include "TransformSource.h" +#include "XMLTokenizer.h" +#include "XSLStyleSheet.h" +#include "XSLTExtensions.h" +#include "XSLTUnicodeSort.h" +#include "loader.h" +#include "markup.h" +#include <libxslt/imports.h> +#include <libxslt/variables.h> +#include <libxslt/xsltutils.h> +#include <wtf/Assertions.h> +#include <wtf/Platform.h> +#include <wtf/Vector.h> + +#if PLATFORM(MAC) +#include "SoftLinking.h" + +SOFT_LINK_LIBRARY(libxslt); +SOFT_LINK(libxslt, xsltFreeStylesheet, void, (xsltStylesheetPtr sheet), (sheet)) +SOFT_LINK(libxslt, xsltFreeTransformContext, void, (xsltTransformContextPtr ctxt), (ctxt)) +SOFT_LINK(libxslt, xsltNewTransformContext, xsltTransformContextPtr, (xsltStylesheetPtr style, xmlDocPtr doc), (style, doc)) +SOFT_LINK(libxslt, xsltApplyStylesheetUser, xmlDocPtr, (xsltStylesheetPtr style, xmlDocPtr doc, const char** params, const char* output, FILE* profile, xsltTransformContextPtr userCtxt), (style, doc, params, output, profile, userCtxt)) +SOFT_LINK(libxslt, xsltQuoteUserParams, int, (xsltTransformContextPtr ctxt, const char** params), (ctxt, params)) +SOFT_LINK(libxslt, xsltSetCtxtSortFunc, void, (xsltTransformContextPtr ctxt, xsltSortFunc handler), (ctxt, handler)) +SOFT_LINK(libxslt, xsltSetLoaderFunc, void, (xsltDocLoaderFunc f), (f)) +SOFT_LINK(libxslt, xsltSaveResultTo, int, (xmlOutputBufferPtr buf, xmlDocPtr result, xsltStylesheetPtr style), (buf, result, style)) +SOFT_LINK(libxslt, xsltNextImport, xsltStylesheetPtr, (xsltStylesheetPtr style), (style)) +#endif + +namespace WebCore { + +void XSLTProcessor::genericErrorFunc(void*, const char*, ...) +{ + // It would be nice to do something with this error message. +} + +void XSLTProcessor::parseErrorFunc(void* userData, xmlError* error) +{ + Console* console = static_cast<Console*>(userData); + if (!console) + return; + + MessageLevel level; + switch (error->level) { + case XML_ERR_NONE: + level = TipMessageLevel; + break; + case XML_ERR_WARNING: + level = WarningMessageLevel; + break; + case XML_ERR_ERROR: + case XML_ERR_FATAL: + default: + level = ErrorMessageLevel; + break; + } + + console->addMessage(XMLMessageSource, LogMessageType, 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. +static XSLTProcessor* globalProcessor = 0; +static DocLoader* globalDocLoader = 0; +static xmlDocPtr docLoaderFunc(const xmlChar* uri, + xmlDictPtr, + int options, + void* ctxt, + xsltLoadType type) +{ + if (!globalProcessor) + return 0; + + switch (type) { + case XSLT_LOAD_DOCUMENT: { + xsltTransformContextPtr context = (xsltTransformContextPtr)ctxt; + xmlChar* base = xmlNodeGetBase(context->document->doc, context->node); + KURL url(KURL(ParsedURLString, reinterpret_cast<const char*>(base)), reinterpret_cast<const char*>(uri)); + xmlFree(base); + ResourceError error; + ResourceResponse response; + + Vector<char> data; + + bool requestAllowed = globalDocLoader->frame() && globalDocLoader->doc()->securityOrigin()->canRequest(url); + if (requestAllowed) { + globalDocLoader->frame()->loader()->loadResourceSynchronously(url, AllowStoredCredentials, error, response, data); + 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; + } + case XSLT_LOAD_STYLESHEET: + return globalProcessor->xslStylesheet()->locateStylesheetSubResource(((xsltStylesheetPtr)ctxt)->doc, uri); + default: + break; + } + + return 0; +} + +static inline void setXSLTLoadCallBack(xsltDocLoaderFunc func, XSLTProcessor* processor, DocLoader* loader) +{ + xsltSetLoaderFunc(func); + globalProcessor = processor; + globalDocLoader = loader; +} + +static int writeToVector(void* context, const char* buffer, int len) +{ + Vector<UChar>& resultOutput = *static_cast<Vector<UChar>*>(context); + String decodedChunk = String::fromUTF8(buffer, len); + resultOutput.append(decodedChunk.characters(), decodedChunk.length()); + return len; +} + +static bool saveResultToString(xmlDocPtr resultDoc, xsltStylesheetPtr sheet, String& resultString) +{ + xmlOutputBufferPtr outputBuf = xmlAllocOutputBuffer(0); + if (!outputBuf) + return false; + + Vector<UChar> resultVector; + outputBuf->context = &resultVector; + outputBuf->writecallback = writeToVector; + + int retval = xsltSaveResultTo(outputBuf, resultDoc, sheet); + xmlOutputBufferClose(outputBuf); + if (retval < 0) + return false; + + // Workaround for <http://bugzilla.gnome.org/show_bug.cgi?id=495668>: libxslt appends an extra line feed to the result. + if (resultVector.size() > 0 && resultVector[resultVector.size() - 1] == '\n') + resultVector.removeLast(); + + resultString = String::adopt(resultVector); + + return true; +} + +static const char** xsltParamArrayFromParameterMap(XSLTProcessor::ParameterMap& parameters) +{ + if (parameters.isEmpty()) + return 0; + + const char** parameterArray = (const char**)fastMalloc(((parameters.size() * 2) + 1) * sizeof(char*)); + + XSLTProcessor::ParameterMap::iterator end = parameters.end(); + unsigned index = 0; + for (XSLTProcessor::ParameterMap::iterator it = parameters.begin(); it != end; ++it) { + parameterArray[index++] = fastStrDup(it->first.utf8().data()); + parameterArray[index++] = fastStrDup(it->second.utf8().data()); + } + parameterArray[index] = 0; + + return parameterArray; +} + +static void freeXsltParamArray(const char** params) +{ + const char** temp = params; + if (!params) + return; + + while (*temp) { + fastFree((void*)*(temp++)); + fastFree((void*)*(temp++)); + } + fastFree(params); +} + +static xsltStylesheetPtr xsltStylesheetPointer(RefPtr<XSLStyleSheet>& cachedStylesheet, Node* stylesheetRootNode) +{ + if (!cachedStylesheet && stylesheetRootNode) { + cachedStylesheet = XSLStyleSheet::create(stylesheetRootNode->parent() ? stylesheetRootNode->parent() : stylesheetRootNode, + stylesheetRootNode->document()->url().string(), + stylesheetRootNode->document()->url()); // FIXME: Should we use baseURL here? + cachedStylesheet->parseString(createMarkup(stylesheetRootNode)); + } + + if (!cachedStylesheet || !cachedStylesheet->document()) + return 0; + + return cachedStylesheet->compileStyleSheet(); +} + +static inline xmlDocPtr xmlDocPtrFromNode(Node* sourceNode, bool& shouldDelete) +{ + RefPtr<Document> ownerDocument = sourceNode->document(); + bool sourceIsDocument = (sourceNode == ownerDocument.get()); + + xmlDocPtr sourceDoc = 0; + if (sourceIsDocument && ownerDocument->transformSource()) + sourceDoc = (xmlDocPtr)ownerDocument->transformSource()->platformSource(); + if (!sourceDoc) { + sourceDoc = (xmlDocPtr)xmlDocPtrForString(ownerDocument->docLoader(), createMarkup(sourceNode), + sourceIsDocument ? ownerDocument->url().string() : String()); + shouldDelete = sourceDoc; + } + return sourceDoc; +} + +static inline String resultMIMEType(xmlDocPtr resultDoc, xsltStylesheetPtr sheet) +{ + // There are three types of output we need to be able to deal with: + // HTML (create an HTML document), XML (create an XML document), + // and text (wrap in a <pre> and create an XML document). + + const xmlChar* resultType = 0; + XSLT_GET_IMPORT_PTR(resultType, sheet, method); + if (!resultType && resultDoc->type == XML_HTML_DOCUMENT_NODE) + resultType = (const xmlChar*)"html"; + + if (xmlStrEqual(resultType, (const xmlChar*)"html")) + return "text/html"; + if (xmlStrEqual(resultType, (const xmlChar*)"text")) + return "text/plain"; + + return "application/xml"; +} + +bool XSLTProcessor::transformToString(Node* sourceNode, String& mimeType, String& resultString, String& resultEncoding) +{ + RefPtr<Document> ownerDocument = sourceNode->document(); + + setXSLTLoadCallBack(docLoaderFunc, this, ownerDocument->docLoader()); + xsltStylesheetPtr sheet = xsltStylesheetPointer(m_stylesheet, m_stylesheetRootNode.get()); + if (!sheet) { + setXSLTLoadCallBack(0, 0, 0); + return false; + } + m_stylesheet->clearDocuments(); + + xmlChar* origMethod = sheet->method; + if (!origMethod && mimeType == "text/html") + sheet->method = (xmlChar*)"html"; + + bool success = false; + bool shouldFreeSourceDoc = false; + if (xmlDocPtr sourceDoc = xmlDocPtrFromNode(sourceNode, shouldFreeSourceDoc)) { + // The XML declaration would prevent parsing the result as a fragment, and it's not needed even for documents, + // as the result of this function is always immediately parsed. + sheet->omitXmlDeclaration = true; + + xsltTransformContextPtr transformContext = xsltNewTransformContext(sheet, sourceDoc); + registerXSLTExtensions(transformContext); + + // <http://bugs.webkit.org/show_bug.cgi?id=16077>: XSLT processor <xsl:sort> algorithm only compares by code point + xsltSetCtxtSortFunc(transformContext, xsltUnicodeSortFunction); + + // This is a workaround for a bug in libxslt. + // The bug has been fixed in version 1.1.13, so once we ship that this can be removed. + if (!transformContext->globalVars) + transformContext->globalVars = xmlHashCreate(20); + + const char** params = xsltParamArrayFromParameterMap(m_parameters); + xsltQuoteUserParams(transformContext, params); + xmlDocPtr resultDoc = xsltApplyStylesheetUser(sheet, sourceDoc, 0, 0, 0, transformContext); + + xsltFreeTransformContext(transformContext); + freeXsltParamArray(params); + + if (shouldFreeSourceDoc) + xmlFreeDoc(sourceDoc); + + if (success = saveResultToString(resultDoc, sheet, resultString)) { + mimeType = resultMIMEType(resultDoc, sheet); + resultEncoding = (char*)resultDoc->encoding; + } + xmlFreeDoc(resultDoc); + } + + sheet->method = origMethod; + setXSLTLoadCallBack(0, 0, 0); + xsltFreeStylesheet(sheet); + m_stylesheet = 0; + + return success; +} + +} // namespace WebCore + +#endif // ENABLE(XSLT) diff --git a/WebCore/xml/XSLTProcessorQt.cpp b/WebCore/xml/XSLTProcessorQt.cpp new file mode 100644 index 0000000..9ac3f5d --- /dev/null +++ b/WebCore/xml/XSLTProcessorQt.cpp @@ -0,0 +1,181 @@ +/* + * This file is part of the XSL implementation. + * + * Copyright (C) 2009 Jakub Wieczorek <faw217@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(XSLT) + +#include "XSLTProcessor.h" + +#include "Console.h" +#include "DOMWindow.h" +#include "Frame.h" +#include "TransformSource.h" +#include "loader.h" +#include "markup.h" +#include <wtf/Assertions.h> +#include <wtf/Platform.h> +#include <wtf/Vector.h> + +#include <qabstractmessagehandler.h> +#include <qabstracturiresolver.h> +#include <qbuffer.h> +#include <qsourcelocation.h> +#include <qxmlquery.h> + +namespace WebCore { + +class XSLTMessageHandler : public QAbstractMessageHandler { + +public: + XSLTMessageHandler(Document* document = 0); + virtual void handleMessage(QtMsgType type, const QString& description, + const QUrl& identifier, const QSourceLocation& sourceLocation); + +private: + Document* m_document; +}; + +XSLTMessageHandler::XSLTMessageHandler(Document* document) + : QAbstractMessageHandler() + , m_document(document) +{ +} + +void XSLTMessageHandler::handleMessage(QtMsgType type, const QString& description, + const QUrl&, const QSourceLocation& sourceLocation) +{ + if (!m_document->frame()) + return; + + MessageLevel level; + switch (type) { + case QtDebugMsg: + level = TipMessageLevel; + break; + case QtWarningMsg: + level = WarningMessageLevel; + break; + case QtCriticalMsg: + case QtFatalMsg: + level = ErrorMessageLevel; + break; + default: + level = LogMessageLevel; + break; + } + + Console* console = m_document->frame()->domWindow()->console(); + console->addMessage(XMLMessageSource, LogMessageType, level, description, + sourceLocation.line(), sourceLocation.uri().toString()); +} + +class XSLTUriResolver : public QAbstractUriResolver { + +public: + XSLTUriResolver(Document* document); + virtual QUrl resolve(const QUrl& relative, const QUrl& baseURI) const; + +private: + Document* m_document; +}; + +XSLTUriResolver::XSLTUriResolver(Document* document) + : QAbstractUriResolver() + , m_document(document) +{ +} + +QUrl XSLTUriResolver::resolve(const QUrl& relative, const QUrl& baseURI) const +{ + QUrl url = baseURI.resolved(relative); + + if (!m_document->frame() || !m_document->securityOrigin()->canRequest(url)) + return QUrl(); + return url; +} + +bool XSLTProcessor::transformToString(Node* sourceNode, String&, String& resultString, String&) +{ + bool success = false; + + RefPtr<XSLStyleSheet> stylesheet = m_stylesheet; + if (!stylesheet && m_stylesheetRootNode) { + Node* node = m_stylesheetRootNode.get(); + stylesheet = XSLStyleSheet::create(node->parent() ? node->parent() : node, + node->document()->url().string(), + node->document()->url()); // FIXME: Should we use baseURL here? + stylesheet->parseString(createMarkup(node)); + } + + if (!stylesheet || stylesheet->sheetString().isEmpty()) + return success; + + RefPtr<Document> ownerDocument = sourceNode->document(); + bool sourceIsDocument = (sourceNode == ownerDocument.get()); + + QXmlQuery query(QXmlQuery::XSLT20); + + XSLTMessageHandler messageHandler(ownerDocument.get()); + XSLTUriResolver uriResolver(ownerDocument.get()); + query.setMessageHandler(&messageHandler); + + XSLTProcessor::ParameterMap::iterator end = m_parameters.end(); + for (XSLTProcessor::ParameterMap::iterator it = m_parameters.begin(); it != end; ++it) + query.bindVariable(QString(it->first), QXmlItem(QVariant(it->second))); + + QString source; + if (sourceIsDocument && ownerDocument->transformSource()) + source = ownerDocument->transformSource()->platformSource(); + if (!sourceIsDocument || source.isEmpty()) + source = createMarkup(sourceNode); + + QBuffer inputBuffer; + QBuffer styleSheetBuffer; + QBuffer outputBuffer; + + inputBuffer.setData(source.toUtf8()); + styleSheetBuffer.setData(QString(stylesheet->sheetString()).toUtf8()); + + inputBuffer.open(QIODevice::ReadOnly); + styleSheetBuffer.open(QIODevice::ReadOnly); + outputBuffer.open(QIODevice::ReadWrite); + + query.setFocus(&inputBuffer); + query.setQuery(&styleSheetBuffer, QUrl(stylesheet->href())); + + query.setUriResolver(&uriResolver); + + success = query.evaluateTo(&outputBuffer); + outputBuffer.reset(); + resultString = QString::fromUtf8(outputBuffer.readAll()).trimmed(); + + if (m_stylesheet) { + m_stylesheet->clearDocuments(); + m_stylesheet = 0; + } + + return success; +} + +} // namespace WebCore + +#endif // ENABLE(XSLT) diff --git a/WebCore/xml/xmlnsattrs.in b/WebCore/xml/xmlnsattrs.in new file mode 100644 index 0000000..7ac415a --- /dev/null +++ b/WebCore/xml/xmlnsattrs.in @@ -0,0 +1,4 @@ +namespace="XMLNS" +namespaceURI="http://www.w3.org/2000/xmlns/" + +xmlns |