📄 xmlhttprequest.cpp
字号:
// -*- c-basic-offset: 2 -*-/* * This file is part of the KDE libraries * Copyright (C) 2003 Apple Computer, Inc. * * 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 "xmlhttprequest.h"#include "xmlhttprequest.lut.h"#include "kjs_window.h"#include "kjs_events.h"#include "dom/dom_doc.h"#include "dom/dom_exception.h"#include "dom/dom_string.h"#include "misc/loader.h"#include "html/html_documentimpl.h"#include "xml/dom2_eventsimpl.h"#include "khtml_part.h"#include "khtmlview.h"#include <kio/scheduler.h>#include <kio/job.h>#include <qobject.h>#include <kdebug.h>#ifdef APPLE_CHANGES#include "KWQLoader.h"#else#include <kio/netaccess.h>using KIO::NetAccess;#endif#define BANNED_HTTP_HEADERS "authorization,proxy-authorization,"\ "content-length,host,connect,copy,move,"\ "delete,head,trace,put,propfind,proppatch,"\ "mkcol,lock,unlock,options,via"using namespace KJS;using khtml::Decoder;////////////////////// XMLHttpRequest Object /////////////////////////* Source for XMLHttpRequestProtoTable.@begin XMLHttpRequestProtoTable 7 abort XMLHttpRequest::Abort DontDelete|Function 0 getAllResponseHeaders XMLHttpRequest::GetAllResponseHeaders DontDelete|Function 0 getResponseHeader XMLHttpRequest::GetResponseHeader DontDelete|Function 1 open XMLHttpRequest::Open DontDelete|Function 5 send XMLHttpRequest::Send DontDelete|Function 1 setRequestHeader XMLHttpRequest::SetRequestHeader DontDelete|Function 2@end*/DEFINE_PROTOTYPE("XMLHttpRequest",XMLHttpRequestProto)IMPLEMENT_PROTOFUNC_DOM(XMLHttpRequestProtoFunc)IMPLEMENT_PROTOTYPE(XMLHttpRequestProto,XMLHttpRequestProtoFunc)namespace KJS {XMLHttpRequestQObject::XMLHttpRequestQObject(XMLHttpRequest *_jsObject){ jsObject = _jsObject;}#ifdef APPLE_CHANGESvoid XMLHttpRequestQObject::slotData( KIO::Job* job, const char *data, int size ){ jsObject->slotData(job, data, size);}#elsevoid XMLHttpRequestQObject::slotData( KIO::Job* job, const QByteArray &data ){ jsObject->slotData(job, data);}#endifvoid XMLHttpRequestQObject::slotFinished( KIO::Job* job ){ jsObject->slotFinished(job);}void XMLHttpRequestQObject::slotRedirection( KIO::Job* job, const KURL& url){ jsObject->slotRedirection( job, url );}XMLHttpRequestConstructorImp::XMLHttpRequestConstructorImp(ExecState *, const DOM::Document &d) : ObjectImp(), doc(d){}bool XMLHttpRequestConstructorImp::implementsConstruct() const{ return true;}Object XMLHttpRequestConstructorImp::construct(ExecState *exec, const List &){ return Object(new XMLHttpRequest(exec, doc));}const ClassInfo XMLHttpRequest::info = { "XMLHttpRequest", 0, &XMLHttpRequestTable, 0 };/* Source for XMLHttpRequestTable.@begin XMLHttpRequestTable 7 readyState XMLHttpRequest::ReadyState DontDelete|ReadOnly responseText XMLHttpRequest::ResponseText DontDelete|ReadOnly responseXML XMLHttpRequest::ResponseXML DontDelete|ReadOnly status XMLHttpRequest::Status DontDelete|ReadOnly statusText XMLHttpRequest::StatusText DontDelete|ReadOnly onreadystatechange XMLHttpRequest::Onreadystatechange DontDelete onload XMLHttpRequest::Onload DontDelete@end*/Value XMLHttpRequest::tryGet(ExecState *exec, const Identifier &propertyName) const{ return DOMObjectLookupGetValue<XMLHttpRequest,DOMObject>(exec, propertyName, &XMLHttpRequestTable, this);}Value XMLHttpRequest::getValueProperty(ExecState *exec, int token) const{ switch (token) { case ReadyState: return Number(state); case ResponseText: return getString(DOM::DOMString(response)); case ResponseXML: if (state != Completed) { return Undefined(); } if (!createdDocument) { QString mimeType = "text/xml"; Value header = getResponseHeader("Content-Type"); if (header.type() != UndefinedType) { mimeType = QStringList::split(";", header.toString(exec).qstring())[0].stripWhiteSpace(); } if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "application/xhtml+xml") { responseXML = DOM::Document(doc->implementation()->createDocument()); DOM::DocumentImpl *docImpl = static_cast<DOM::DocumentImpl *>(responseXML.handle()); docImpl->open(); docImpl->write(response); docImpl->finishParsing(); docImpl->close(); typeIsXML = true; } else { typeIsXML = false; } createdDocument = true; } if (!typeIsXML) { return Undefined(); } return getDOMNode(exec,responseXML); case Status: return getStatus(); case StatusText: return getStatusText(); case Onreadystatechange: if (onReadyStateChangeListener && onReadyStateChangeListener->listenerObjImp()) { return onReadyStateChangeListener->listenerObj(); } else { return Null(); } case Onload: if (onLoadListener && onLoadListener->listenerObjImp()) { return onLoadListener->listenerObj(); } else { return Null(); } default: kdWarning() << "XMLHttpRequest::getValueProperty unhandled token " << token << endl; return Value(); }}void XMLHttpRequest::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr){ DOMObjectLookupPut<XMLHttpRequest,DOMObject>(exec, propertyName, value, attr, &XMLHttpRequestTable, this );}void XMLHttpRequest::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/){ switch(token) { case Onreadystatechange: onReadyStateChangeListener = Window::retrieveActive(exec)->getJSEventListener(value, true); if (onReadyStateChangeListener) onReadyStateChangeListener->ref(); break; case Onload: onLoadListener = Window::retrieveActive(exec)->getJSEventListener(value, true); if (onLoadListener) onLoadListener->ref(); break; default: kdWarning() << "XMLHttpRequest::putValue unhandled token " << token << endl; }}XMLHttpRequest::XMLHttpRequest(ExecState *exec, const DOM::Document &d) : DOMObject(XMLHttpRequestProto::self(exec)), qObject(new XMLHttpRequestQObject(this)), doc(static_cast<DOM::DocumentImpl*>(d.handle())), async(true), contentType(QString::null), job(0), state(Uninitialized), onReadyStateChangeListener(0), onLoadListener(0), decoder(0), createdDocument(false), aborted(false){}XMLHttpRequest::~XMLHttpRequest(){ delete qObject; qObject = 0; delete decoder; decoder = 0;}void XMLHttpRequest::changeState(XMLHttpRequestState newState){ if (state != newState) { state = newState; ref(); if (onReadyStateChangeListener != 0 && doc->view() && doc->view()->part()) { DOM::Event ev = doc->view()->part()->document().createEvent("HTMLEvents"); ev.initEvent("readystatechange", true, true); onReadyStateChangeListener->handleEvent(ev); } if (state == Completed && onLoadListener != 0 && doc->view() && doc->view()->part()) { DOM::Event ev = doc->view()->part()->document().createEvent("HTMLEvents"); ev.initEvent("load", true, true); onLoadListener->handleEvent(ev); } deref(); }}bool XMLHttpRequest::urlMatchesDocumentDomain(const KURL& _url) const{ // No need to do work if _url is not valid... if (!_url.isValid()) return false; KURL documentURL(doc->URL()); // a local file can load anything if (documentURL.protocol().lower() == "file") { return true; } // but a remote document can only load from the same port on the server if (documentURL.protocol().lower() == _url.protocol().lower() && documentURL.host().lower() == _url.host().lower() && documentURL.port() == _url.port()) { return true; } return false;}void XMLHttpRequest::open(const QString& _method, const KURL& _url, bool _async){ abort(); aborted = false; // clear stuff from possible previous load requestHeaders.clear(); responseHeaders = QString(); response = QString(); createdDocument = false; responseXML = DOM::Document(); changeState(Uninitialized); if (aborted) { return; } if (!urlMatchesDocumentDomain(_url)) { return; } method = _method.lower(); url = _url; async = _async; changeState(Loading);}void XMLHttpRequest::send(const QString& _body){ aborted = false; if (method == "post") { QString protocol = url.protocol().lower(); // Abondon the request when the protocol is other than "http", // instead of blindly changing it to a "get" request. if (!protocol.startsWith("http") && !protocol.startsWith("webdav")) { abort(); return; } // FIXME: determine post encoding correctly by looking in headers // for charset. QByteArray buf; buf.duplicate(_body.utf8().data(), _body.length()); job = KIO::http_post( url, buf, false ); if(contentType.isNull()) job->addMetaData( "content-type", "Content-type: text/plain" ); else job->addMetaData( "content-type", contentType ); } else { job = KIO::get( url, false, false ); } if (!requestHeaders.isEmpty()) { QString rh; QMap<QString, QString>::ConstIterator begin = requestHeaders.begin(); QMap<QString, QString>::ConstIterator end = requestHeaders.end(); for (QMap<QString, QString>::ConstIterator i = begin; i != end; ++i) { if (i != begin) rh += "\r\n"; rh += i.key() + ": " + i.data(); } job->addMetaData("customHTTPHeader", rh); } job->addMetaData("PropagateHttpHeader", "true"); // Set the default referrer if one is not already supplied // through setRequestHeader. NOTE: the user can still disable // this feature at the protocol level (kio_http). if (requestHeaders.find("Referer") == requestHeaders.end()) { KURL documentURL(doc->URL()); documentURL.setPass(QString::null); documentURL.setUser(QString::null); job->addMetaData("referrer", documentURL.url()); // kdDebug() << "Adding referrer: " << documentURL << endl; } if (!async) { QByteArray data; KURL finalURL; QString headers;#ifdef APPLE_CHANGES
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -