⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmlhttprequest.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* *  Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. *  Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org> *  Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org> *  Copyright (C) 2008 David Levin <levin@chromium.org> * *  This library is free software; you can redistribute it and/or *  modify it under the terms of the GNU Lesser 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 *  Lesser General Public License for more details. * *  You should have received a copy of the GNU Lesser General Public *  License along with this library; if not, write to the Free Software *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA */#include "config.h"#include "XMLHttpRequest.h"#include "CString.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 "KURL.h"#include "KURLHash.h"#include "ResourceError.h"#include "ResourceRequest.h"#include "ScriptExecutionContext.h"#include "SecurityOrigin.h"#include "Settings.h"#include "SystemTime.h"#include "TextResourceDecoder.h"#include "ThreadableLoader.h"#include "XMLHttpRequestException.h"#include "XMLHttpRequestProgressEvent.h"#include "XMLHttpRequestUpload.h"#include "markup.h"#include <wtf/CurrentTime.h>#include <wtf/Noncopyable.h>#include <wtf/StdLibExtras.h>#include <wtf/Threading.h>#if USE(JSC)#include "JSDOMWindow.h"#endifnamespace WebCore {typedef HashSet<String, CaseFoldingHash> HeadersSet;struct XMLHttpRequestStaticData {    XMLHttpRequestStaticData();    String m_proxyHeaderPrefix;    String m_secHeaderPrefix;    HashSet<String, CaseFoldingHash> m_forbiddenRequestHeaders;    HashSet<String, CaseFoldingHash> m_allowedCrossSiteResponseHeaders;};XMLHttpRequestStaticData::XMLHttpRequestStaticData()    : m_proxyHeaderPrefix("proxy-")    , m_secHeaderPrefix("sec-"){    m_forbiddenRequestHeaders.add("accept-charset");    m_forbiddenRequestHeaders.add("accept-encoding");    m_forbiddenRequestHeaders.add("connection");    m_forbiddenRequestHeaders.add("content-length");    m_forbiddenRequestHeaders.add("content-transfer-encoding");    m_forbiddenRequestHeaders.add("date");    m_forbiddenRequestHeaders.add("expect");    m_forbiddenRequestHeaders.add("host");    m_forbiddenRequestHeaders.add("keep-alive");    m_forbiddenRequestHeaders.add("referer");    m_forbiddenRequestHeaders.add("te");    m_forbiddenRequestHeaders.add("trailer");    m_forbiddenRequestHeaders.add("transfer-encoding");    m_forbiddenRequestHeaders.add("upgrade");    m_forbiddenRequestHeaders.add("via");    m_allowedCrossSiteResponseHeaders.add("cache-control");    m_allowedCrossSiteResponseHeaders.add("content-language");    m_allowedCrossSiteResponseHeaders.add("content-type");    m_allowedCrossSiteResponseHeaders.add("expires");    m_allowedCrossSiteResponseHeaders.add("last-modified");    m_allowedCrossSiteResponseHeaders.add("pragma");}class PreflightResultCacheItem : Noncopyable {public:    PreflightResultCacheItem(bool credentials)        : m_absoluteExpiryTime(0)        , m_credentials(credentials)    {    }    bool parse(const ResourceResponse&);    bool allowsCrossSiteMethod(const String&) const;    bool allowsCrossSiteHeaders(const HTTPHeaderMap&) const;    bool allowsRequest(bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const;private:    template<class HashType>    static void addToAccessControlAllowList(const String& string, unsigned start, unsigned end, HashSet<String, HashType>&);    template<class HashType>    static bool parseAccessControlAllowList(const String& string, HashSet<String, HashType>&);    static bool parseAccessControlMaxAge(const String& string, unsigned& expiryDelta);    // FIXME: A better solution to holding onto the absolute expiration time might be    // to start a timer for the expiration delta, that removes this from the cache when    // it fires.    double m_absoluteExpiryTime;    bool m_credentials;    HashSet<String> m_methods;    HeadersSet m_headers;};class PreflightResultCache : Noncopyable {public:    static PreflightResultCache& shared();    void appendEntry(const String& origin, const KURL&, PreflightResultCacheItem*);    bool canSkipPreflight(const String& origin, const KURL&, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders);private:    PreflightResultCache() { }    typedef HashMap<std::pair<String, KURL>, PreflightResultCacheItem*> PreflightResultHashMap;    PreflightResultHashMap m_preflightHashMap;    Mutex m_mutex;};static bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name){    return equalIgnoringCase(name, "accept") || equalIgnoringCase(name, "accept-language") || equalIgnoringCase(name, "content-type");}// Determines if a string is a valid token, as defined by// "token" in section 2.2 of RFC 2616.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     // field-value in section 4.2 of RFC 2616.            return !name.contains('\r') && !name.contains('\n');}static bool isSetCookieHeader(const AtomicString& name){    return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2");}template<class HashType>void PreflightResultCacheItem::addToAccessControlAllowList(const String& string, unsigned start, unsigned end, HashSet<String, HashType>& set){    StringImpl* stringImpl = string.impl();    if (!stringImpl)        return;    // Skip white space from start.    while (start <= end && isSpaceOrNewline((*stringImpl)[start]))        start++;    // only white space    if (start > end)         return;    // Skip white space from end.    while (end && isSpaceOrNewline((*stringImpl)[end]))        end--;    // substringCopy() is called on the strings because the cache is accessed on multiple threads.    set.add(string.substringCopy(start, end - start + 1));}template<class HashType>bool PreflightResultCacheItem::parseAccessControlAllowList(const String& string, HashSet<String, HashType>& set){    int start = 0;    int end;    while ((end = string.find(',', start)) != -1) {        if (start == end)            return false;        addToAccessControlAllowList(string, start, end - 1, set);        start = end + 1;    }    if (start != static_cast<int>(string.length()))        addToAccessControlAllowList(string, start, string.length() - 1, set);    return true;}bool PreflightResultCacheItem::parseAccessControlMaxAge(const String& string, unsigned& expiryDelta){    // FIXME: this will not do the correct thing for a number starting with a '+'    bool ok = false;    expiryDelta = string.toUIntStrict(&ok);    return ok;}bool PreflightResultCacheItem::parse(const ResourceResponse& response){    m_methods.clear();    if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), m_methods))        return false;    m_headers.clear();    if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), m_headers))        return false;    unsigned expiryDelta = 0;    if (!parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta))        expiryDelta = 5;    m_absoluteExpiryTime = currentTime() + expiryDelta;    return true;}bool PreflightResultCacheItem::allowsCrossSiteMethod(const String& method) const{    return m_methods.contains(method) || method == "GET" || method == "POST";}bool PreflightResultCacheItem::allowsCrossSiteHeaders(const HTTPHeaderMap& requestHeaders) const{    HTTPHeaderMap::const_iterator end = requestHeaders.end();    for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {        if (!m_headers.contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first))            return false;    }    return true;}bool PreflightResultCacheItem::allowsRequest(bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const{    if (m_absoluteExpiryTime < currentTime())        return false;    if (includeCredentials && !m_credentials)        return false;    if (!allowsCrossSiteMethod(method))        return false;    if (!allowsCrossSiteHeaders(requestHeaders))        return false;    return true;}PreflightResultCache& PreflightResultCache::shared(){    AtomicallyInitializedStatic(PreflightResultCache&, cache = *new PreflightResultCache);    return cache;}void PreflightResultCache::appendEntry(const String& origin, const KURL& url, PreflightResultCacheItem* preflightResult){    MutexLocker lock(m_mutex);    // Note that the entry may already be present in the HashMap if another thread is accessing the same location.    m_preflightHashMap.set(std::make_pair(origin.copy(), url.copy()), preflightResult);}bool PreflightResultCache::canSkipPreflight(const String& origin, const KURL& url, bool includeCredentials,                                            const String& method, const HTTPHeaderMap& requestHeaders){    MutexLocker lock(m_mutex);    PreflightResultHashMap::iterator cacheIt = m_preflightHashMap.find(std::make_pair(origin, url));    if (cacheIt == m_preflightHashMap.end())        return false;    if (cacheIt->second->allowsRequest(includeCredentials, method, requestHeaders))        return true;    delete cacheIt->second;    m_preflightHashMap.remove(cacheIt);    return false;}static const XMLHttpRequestStaticData* staticData = 0;static const XMLHttpRequestStaticData* createXMLHttpRequestStaticData(){    staticData = new XMLHttpRequestStaticData;    return staticData;}static const XMLHttpRequestStaticData* initializeXMLHttpRequestStaticData(){    // Uses dummy to avoid warnings about an unused variable.    AtomicallyInitializedStatic(const XMLHttpRequestStaticData*, dummy = createXMLHttpRequestStaticData());    return dummy;}XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext* context)    : ActiveDOMObject(context, this)    , m_async(true)    , m_includeCredentials(false)    , m_state(UNSENT)    , m_responseText("")    , m_createdDocument(false)    , m_error(false)    , m_uploadComplete(false)    , m_sameOriginRequest(true)    , m_inPreflight(false)    , m_receivedLength(0)    , m_lastSendLineNumber(0)    , m_exceptionCode(0){    initializeXMLHttpRequestStaticData();}XMLHttpRequest::~XMLHttpRequest(){    if (m_upload)        m_upload->disconnectXMLHttpRequest();}Document* XMLHttpRequest::document() const{    ASSERT(scriptExecutionContext()->isDocument());    return static_cast<Document*>(scriptExecutionContext());}#if ENABLE(DASHBOARD_SUPPORT)bool XMLHttpRequest::usesDashboardBackwardCompatibilityMode() const{    if (scriptExecutionContext()->isWorkerContext())        return false;    Settings* settings = document()->settings();    return settings && settings->usesDashboardBackwardCompatibilityMode();}#endifXMLHttpRequest::State XMLHttpRequest::readyState() const{    return m_state;}const ScriptString& XMLHttpRequest::responseText() const{    return m_responseText;}Document* XMLHttpRequest::responseXML() const{    if (m_state != DONE)        return 0;    if (!m_createdDocument) {        if ((m_response.isHTTP() && !responseIsXML()) || scriptExecutionContext()->isWorkerContext()) {            // The W3C spec requires this.            m_responseXML = 0;        } else {            m_responseXML = document()->implementation()->createDocument(0);            m_responseXML->open();            m_responseXML->setURL(m_url);            // FIXME: set Last-Modified and cookies (currently, those are only available for HTMLDocuments).            m_responseXML->write(String(m_responseText));            m_responseXML->finishParsing();            m_responseXML->close();                        if (!m_responseXML->wellFormed())                m_responseXML = 0;        }        m_createdDocument = true;    }    return m_responseXML.get();}XMLHttpRequestUpload* XMLHttpRequest::upload(){    if (!m_upload)        m_upload = XMLHttpRequestUpload::create(this);    return m_upload.get();}void XMLHttpRequest::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool){    EventListenersMap::iterator iter = m_eventListeners.find(eventType);    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) {        m_state = newState;        callReadyStateChangeListener();    }}void XMLHttpRequest::callReadyStateChangeListener(){    if (!scriptExecutionContext())        return;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -