diff options
Diffstat (limited to 'WebCore/xml/XMLHttpRequest.cpp')
-rw-r--r-- | WebCore/xml/XMLHttpRequest.cpp | 100 |
1 files changed, 85 insertions, 15 deletions
diff --git a/WebCore/xml/XMLHttpRequest.cpp b/WebCore/xml/XMLHttpRequest.cpp index 32818df..5cde24d 100644 --- a/WebCore/xml/XMLHttpRequest.cpp +++ b/WebCore/xml/XMLHttpRequest.cpp @@ -24,8 +24,8 @@ #include "Blob.h" #include "Cache.h" -#include "CString.h" #include "CrossOriginAccessControl.h" +#include "DOMFormData.h" #include "DOMImplementation.h" #include "Document.h" #include "Event.h" @@ -33,6 +33,7 @@ #include "EventListener.h" #include "EventNames.h" #include "HTTPParsers.h" +#include "InspectorController.h" #include "InspectorTimelineAgent.h" #include "ResourceError.h" #include "ResourceRequest.h" @@ -44,6 +45,7 @@ #include "XMLHttpRequestProgressEvent.h" #include "XMLHttpRequestUpload.h" #include "markup.h" +#include <wtf/text/CString.h> #include <wtf/StdLibExtras.h> #include <wtf/RefCountedLeakCounter.h> @@ -127,6 +129,29 @@ static bool isSetCookieHeader(const AtomicString& name) return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2"); } +static void setCharsetInMediaType(String& mediaType, const String& charsetValue) +{ + unsigned int pos = 0, len = 0; + + findCharsetInMediaType(mediaType, pos, len); + + if (!len) { + // When no charset found, append new charset. + mediaType.stripWhiteSpace(); + if (mediaType[mediaType.length() - 1] != ';') + mediaType.append(";"); + mediaType.append(" charset="); + mediaType.append(charsetValue); + } else { + // Found at least one existing charset, replace all occurrences with new charset. + while (len) { + mediaType.replace(pos, len, charsetValue); + unsigned int start = pos + charsetValue.length(); + findCharsetInMediaType(mediaType, pos, len, start); + } + } +} + static const XMLHttpRequestStaticData* staticData = 0; static const XMLHttpRequestStaticData* createXMLHttpRequestStaticData() @@ -157,6 +182,7 @@ XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext* context) , m_receivedLength(0) , m_lastSendLineNumber(0) , m_exceptionCode(0) + , m_progressEventThrottle(this) { initializeXMLHttpRequestStaticData(); #ifndef NDEBUG @@ -214,7 +240,7 @@ Document* XMLHttpRequest::responseXML() const // The W3C spec requires this. m_responseXML = 0; } else { - m_responseXML = document()->implementation()->createDocument(0); + m_responseXML = Document::create(0); m_responseXML->open(); m_responseXML->setURL(m_url); // FIXME: Set Last-Modified. @@ -258,7 +284,7 @@ void XMLHttpRequest::callReadyStateChangeListener() timelineAgent->willChangeXHRReadyState(m_url.string(), m_state); #endif - dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().readystatechangeEvent)); + m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().readystatechangeEvent), m_state == DONE ? FlushProgressEvent : DoNotFlushProgressEvent); #if ENABLE(INSPECTOR) if (callTimelineAgentOnReadyStateChange && (timelineAgent = InspectorTimelineAgent::retrieve(scriptExecutionContext()))) @@ -273,7 +299,7 @@ void XMLHttpRequest::callReadyStateChangeListener() timelineAgent->willLoadXHR(m_url.string()); #endif - dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent)); + m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent)); #if ENABLE(INSPECTOR) if (callTimelineAgentOnLoad && (timelineAgent = InspectorTimelineAgent::retrieve(scriptExecutionContext()))) @@ -292,6 +318,11 @@ void XMLHttpRequest::setWithCredentials(bool value, ExceptionCode& ec) m_includeCredentials = value; } +void XMLHttpRequest::open(const String& method, const KURL& url, ExceptionCode& ec) +{ + open(method, url, true, ec); +} + void XMLHttpRequest::open(const String& method, const KURL& url, bool async, ExceptionCode& ec) { internalAbort(); @@ -425,6 +456,9 @@ void XMLHttpRequest::send(const String& body, ExceptionCode& ec) else #endif setRequestHeaderInternal("Content-Type", "application/xml"); + } else { + setCharsetInMediaType(contentType, "UTF-8"); + m_requestHeaders.set("Content-Type", contentType); } m_requestEntityBody = FormData::create(UTF8Encoding().encode(body.characters(), body.length(), EntitiesForUnencodables)); @@ -444,7 +478,34 @@ void XMLHttpRequest::send(Blob* body, ExceptionCode& ec) // FIXME: Should we set a Content-Type if one is not set. // FIXME: add support for uploading bundles. m_requestEntityBody = FormData::create(); +#if ENABLE(BLOB_SLICE) + m_requestEntityBody->appendFileRange(body->path(), body->start(), body->length(), body->modificationTime()); +#else m_requestEntityBody->appendFile(body->path(), false); +#endif + } + + createRequest(ec); +} + +void XMLHttpRequest::send(DOMFormData* body, ExceptionCode& ec) +{ + if (!initSend(ec)) + return; + + if (m_method != "GET" && m_method != "HEAD" && m_url.protocolInHTTPFamily()) { + m_requestEntityBody = FormData::createMultiPart(*body, document()); + + // We need to ask the client to provide the generated file names if needed. When FormData fills the element + // for the file, it could set a flag to use the generated file name, i.e. a package file on Mac. + m_requestEntityBody->generateFiles(document()); + + String contentType = getRequestHeader("Content-Type"); + if (contentType.isEmpty()) { + contentType = "multipart/form-data; boundary="; + contentType += m_requestEntityBody->boundary().data(); + setRequestHeaderInternal("Content-Type", contentType); + } } createRequest(ec); @@ -457,7 +518,7 @@ void XMLHttpRequest::createRequest(ExceptionCode& ec) // Also, only async requests support upload progress events. bool forcePreflight = false; if (m_async) { - dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); + m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); if (m_requestEntityBody && m_upload) { forcePreflight = m_upload->hasEventListeners(); m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); @@ -468,7 +529,7 @@ void XMLHttpRequest::createRequest(ExceptionCode& ec) // 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); + m_uploadEventsAllowed = m_sameOriginRequest || !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders); ResourceRequest request(m_url); request.setHTTPMethod(m_method); @@ -549,7 +610,7 @@ void XMLHttpRequest::abort() m_state = UNSENT; } - dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent)); + m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent)); if (!m_uploadComplete) { m_uploadComplete = true; if (m_upload && m_uploadEventsAllowed) @@ -603,7 +664,7 @@ void XMLHttpRequest::genericError() void XMLHttpRequest::networkError() { genericError(); - dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().errorEvent)); + m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().errorEvent)); if (!m_uploadComplete) { m_uploadComplete = true; if (m_upload && m_uploadEventsAllowed) @@ -615,7 +676,7 @@ void XMLHttpRequest::networkError() void XMLHttpRequest::abortError() { genericError(); - dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent)); + m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent)); if (!m_uploadComplete) { m_uploadComplete = true; if (m_upload && m_uploadEventsAllowed) @@ -651,7 +712,7 @@ static void reportUnsafeUsage(ScriptExecutionContext* context, const String& mes return; // FIXME: It's not good to report the bad usage without indicating what source line it came from. // We should pass additional parameters so we can tell the console where the mistake occurred. - context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); + context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); } void XMLHttpRequest::setRequestHeader(const AtomicString& name, const String& value, ExceptionCode& ec) @@ -841,9 +902,9 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier) if (m_decoder) 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); + if (InspectorController* inspector = scriptExecutionContext()->inspectorController()) + inspector->resourceRetrievedByXMLHttpRequest(identifier, m_responseText); #endif bool hadLoader = m_loader; @@ -918,9 +979,8 @@ void XMLHttpRequest::didReceiveData(const char* data, 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. - dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, expectedLength && m_receivedLength <= expectedLength, static_cast<unsigned>(m_receivedLength), static_cast<unsigned>(expectedLength))); + bool lengthComputable = expectedLength && m_receivedLength <= expectedLength; + m_progressEventThrottle.dispatchProgressEvent(lengthComputable, static_cast<unsigned>(m_receivedLength), static_cast<unsigned>(expectedLength)); if (m_state != LOADING) changeState(LOADING); @@ -935,6 +995,16 @@ bool XMLHttpRequest::canSuspend() const return !m_loader; } +void XMLHttpRequest::suspend() +{ + m_progressEventThrottle.suspend(); +} + +void XMLHttpRequest::resume() +{ + m_progressEventThrottle.resume(); +} + void XMLHttpRequest::stop() { internalAbort(); |