📄 html_formimpl.cpp
字号:
/*
* This file is part of the DOM implementation for KDE.
*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
* Copyright (C) 2004 Apple Computer, Inc.
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#undef FORMS_DEBUG
//#define FORMS_DEBUG
#include "html/html_formimpl.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include "html/html_documentimpl.h"
#include "html_imageimpl.h"
#include "khtml_settings.h"
#include "misc/htmlhashes.h"
#include "misc/formdata.h"
#include "css/cssstyleselector.h"
#include "css/cssproperties.h"
#include "css/csshelper.h"
#include "xml/dom_textimpl.h"
#include "xml/dom2_eventsimpl.h"
#include "khtml_ext.h"
#include "rendering/render_form.h"
#include <kcharsets.h>
#include <kglobal.h>
#include <kdebug.h>
#include <kmimetype.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <netaccess.h>
#include <kfileitem.h>
#include <qfile.h>
#include <qtextcodec.h>
// for keygen
#include <qstring.h>
#include <ksslkeygen.h>
#include <assert.h>
using namespace khtml;
namespace DOM {
struct FormDataListItem {
FormDataListItem(const QCString &data) : m_data(data) { }
FormDataListItem(const QString &path) : m_path(path) { }
QString m_path;
QCString m_data;
};
class FormDataList
OOM_MODIFIED
{
public:
FormDataList(QTextCodec *);
void appendData(const DOMString &key, const DOMString &value)
{ appendString(key.string()); appendString(value.string()); }
void appendData(const DOMString &key, const QString &value)
{ appendString(key.string()); appendString(value); }
void appendData(const DOMString &key, const QCString &value)
{ appendString(key.string()); appendString(value); }
void appendData(const DOMString &key, int value)
{ appendString(key.string()); appendString(QString::number(value)); }
void appendFile(const DOMString &key, const DOMString &filename);
QValueListConstIterator<FormDataListItem> begin() const
{ return m_list.begin(); }
QValueListConstIterator<FormDataListItem> end() const
{ return m_list.end(); }
private:
void appendString(const QCString &s);
void appendString(const QString &s);
QTextCodec *m_codec;
QValueList<FormDataListItem> m_list;
};
HTMLFormElementImpl::HTMLFormElementImpl(DocumentPtr *doc)
: HTMLElementImpl(doc)
{
collectionInfo = 0;
m_post = false;
m_multipart = false;
m_autocomplete = true;
m_insubmit = false;
m_doingsubmit = false;
m_inreset = false;
m_enctype = "application/x-www-form-urlencoded";
m_boundary = "----------0xKhTmLbOuNdArY";
m_acceptcharset = "UNKNOWN";
m_malformed = false;
}
HTMLFormElementImpl::~HTMLFormElementImpl()
{
delete collectionInfo;
for (unsigned i = 0; i < formElements.count(); ++i)
formElements[i]->m_form = 0;
for (unsigned i = 0; i < dormantFormElements.count(); ++i)
dormantFormElements[i]->m_form = 0;
for (unsigned i = 0; i < imgElements.count(); ++i)
imgElements[i]->m_form = 0;
}
NodeImpl::Id HTMLFormElementImpl::id() const
{
return ID_FORM;
}
#if APPLE_CHANGES
bool HTMLFormElementImpl::formWouldHaveSecureSubmission(const DOMString &url)
{
if (url.isNull()) {
return false;
}
return getDocument()->completeURL(url.string()).startsWith("https:", false);
}
#endif
void HTMLFormElementImpl::attach()
{
HTMLElementImpl::attach();
if (getDocument()->isHTMLDocument()) {
HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
document->addNamedImageOrForm(oldNameAttr);
document->addNamedImageOrForm(oldIdAttr);
}
#if APPLE_CHANGES
// note we don't deal with calling secureFormRemoved() on detach, because the timing
// was such that it cleared our state too early
if (formWouldHaveSecureSubmission(m_url))
getDocument()->secureFormAdded();
#endif
}
void HTMLFormElementImpl::detach()
{
if (getDocument()->isHTMLDocument()) {
HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
document->removeNamedImageOrForm(oldNameAttr);
document->removeNamedImageOrForm(oldIdAttr);
}
HTMLElementImpl::detach();
}
long HTMLFormElementImpl::length() const
{
int len = 0;
for (unsigned i = 0; i < formElements.count(); ++i)
if (formElements[i]->isEnumeratable())
++len;
return len;
}
#if APPLE_CHANGES
void HTMLFormElementImpl::submitClick()
{
bool submitFound = false;
for (unsigned i = 0; i < formElements.count(); ++i) {
if (formElements[i]->id() == ID_INPUT) {
HTMLInputElementImpl *element = static_cast<HTMLInputElementImpl *>(formElements[i]);
if (element->isSuccessfulSubmitButton() && element->renderer()) {
submitFound = true;
element->click(false);
break;
}
}
}
if (!submitFound) // submit the form without a submit or image input
prepareSubmit();
}
#endif // APPLE_CHANGES
static QCString encodeCString(const QCString& e)
{
// http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
// safe characters like NS handles them for compatibility
static const char *safe = "-._*";
int elen = e.length();
QCString encoded(( elen+e.contains( '\n' ) )*3+1);
int enclen = 0;
//QCString orig(e.data(), e.size());
for(int pos = 0; pos < elen; pos++) {
unsigned char c = e[pos];
if ( (( c >= 'A') && ( c <= 'Z')) ||
(( c >= 'a') && ( c <= 'z')) ||
(( c >= '0') && ( c <= '9')) ||
(strchr(safe, c))
)
encoded[enclen++] = c;
else if ( c == ' ' )
encoded[enclen++] = '+';
else if ( c == '\n' || ( c == '\r' && e[pos+1] != '\n' ) )
{
encoded[enclen++] = '%';
encoded[enclen++] = '0';
encoded[enclen++] = 'D';
encoded[enclen++] = '%';
encoded[enclen++] = '0';
encoded[enclen++] = 'A';
}
else if ( c != '\r' )
{
encoded[enclen++] = '%';
unsigned int h = c / 16;
h += (h > 9) ? ('A' - 10) : '0';
encoded[enclen++] = h;
unsigned int l = c % 16;
l += (l > 9) ? ('A' - 10) : '0';
encoded[enclen++] = l;
}
}
encoded[enclen++] = '\0';
encoded.truncate(enclen);
return encoded;
}
// Change plain CR and plain LF to CRLF pairs.
static QCString fixLineBreaks(const QCString &s)
{
// Compute the length.
unsigned newLen = 0;
const char *p = s.data();
while (char c = *p++) {
if (c == '\r') {
// Safe to look ahead because of trailing '\0'.
if (*p != '\n') {
// Turn CR into CRLF.
newLen += 2;
}
} else if (c == '\n') {
// Turn LF into CRLF.
newLen += 2;
} else {
// Leave other characters alone.
newLen += 1;
}
}
if (newLen == s.length()) {
return s;
}
// Make a copy of the string.
p = s.data();
QCString result(newLen + 1);
char *q = result.data();
while (char c = *p++) {
if (c == '\r') {
// Safe to look ahead because of trailing '\0'.
if (*p != '\n') {
// Turn CR into CRLF.
*q++ = '\r';
*q++ = '\n';
}
} else if (c == '\n') {
// Turn LF into CRLF.
*q++ = '\r';
*q++ = '\n';
} else {
// Leave other characters alone.
*q++ = c;
}
}
return result;
}
#if !APPLE_CHANGES
void HTMLFormElementImpl::i18nData()
{
QString foo1 = i18n( "You're about to send data to the Internet "
"via an unencrypted connection. It might be possible "
"for others to see this information.\n"
"Do you want to continue?");
QString foo2 = i18n("KDE Web browser");
QString foo3 = i18n("When you send a password unencrypted to the Internet, "
"it might be possible for others to capture it as plain text.\n"
"Do you want to continue?");
QString foo5 = i18n("Your data submission is redirected to "
"an insecure site. The data is sent unencrypted.\n"
"Do you want to continue?");
QString foo6 = i18n("The page contents expired. You can repost the form"
"data by using <a href=\"javascript:go(0);\">Reload</a>");
}
#endif
bool HTMLFormElementImpl::formData(FormData &form_data) const
{
#ifdef FORMS_DEBUG
kdDebug( 6030 ) << "form: formData()" << endl;
#endif
QCString enc_string = ""; // used for non-multipart data
// find out the QTextcodec to use
QString str = m_acceptcharset.string();
str.replace(',', ' ');
QStringList charsets = QStringList::split(' ', str);
QTextCodec* codec = 0;
KHTMLPart *part = getDocument()->part();
for ( QStringList::Iterator it = charsets.begin(); it != charsets.end(); ++it )
{
QString enc = (*it);
if(enc.contains("UNKNOWN"))
{
// use standard document encoding
enc = "ISO-8859-1";
if (part)
enc = part->encoding();
}
if((codec = KGlobal::charsets()->codecForName(enc.latin1())))
break;
}
if(!codec)
codec = QTextCodec::codecForLocale();
#if !APPLE_CHANGES
QStringList fileUploads;
#endif
for (unsigned i = 0; i < formElements.count(); ++i) {
HTMLGenericFormElementImpl* current = formElements[i];
FormDataList lst(codec);
if (!current->disabled() && current->appendFormData(lst, m_multipart))
{
//kdDebug(6030) << "adding name " << current->name().string() << endl;
for(QValueListConstIterator<FormDataListItem> it = lst.begin(); it != lst.end(); ++it )
{
if (!m_multipart)
{
// handle ISINDEX / <input name=isindex> special
// but only if its the first entry
if ( enc_string.isEmpty() && (*it).m_data == "isindex" ) {
++it;
enc_string += encodeCString( (*it).m_data );
}
else {
if(!enc_string.isEmpty())
enc_string += '&';
enc_string += encodeCString((*it).m_data);
enc_string += "=";
++it;
enc_string += encodeCString((*it).m_data);
}
}
else
{
QCString hstr("--");
hstr += m_boundary.string().latin1();
hstr += "\r\n";
hstr += "Content-Disposition: form-data; name=\"";
hstr += (*it).m_data.data();
hstr += "\"";
// if the current type is FILE, then we also need to
// include the filename
if (current->nodeType() == Node::ELEMENT_NODE && current->id() == ID_INPUT &&
static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::FILE)
{
QString path = static_cast<HTMLInputElementImpl*>(current)->value().string();
#if !APPLE_CHANGES
if (path.length()) fileUploads << path;
#endif
// FIXME: This won't work if the filename includes a " mark,
// or control characters like CR or LF. This also does strange
// things if the filename includes characters you can't encode
// in the website's character set.
hstr += "; filename=\"";
hstr += codec->fromUnicode(path.mid(path.findRev('/') + 1));
hstr += "\"";
if(!static_cast<HTMLInputElementImpl*>(current)->value().isEmpty())
{
#if APPLE_CHANGES
QString mimeType = part ? KWQ(part)->mimeTypeForFileName(path) : QString();
#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -