summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLFormElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/HTMLFormElement.cpp')
-rw-r--r--WebCore/html/HTMLFormElement.cpp271
1 files changed, 51 insertions, 220 deletions
diff --git a/WebCore/html/HTMLFormElement.cpp b/WebCore/html/HTMLFormElement.cpp
index 0e4d88e..afc9c1e 100644
--- a/WebCore/html/HTMLFormElement.cpp
+++ b/WebCore/html/HTMLFormElement.cpp
@@ -44,10 +44,9 @@
#include "MIMETypeRegistry.h"
#include "Page.h"
#include "RenderTextControl.h"
+#include <wtf/RandomNumber.h>
-#if PLATFORM(QT)
-#include <QtCore/QFileInfo>
-#endif
+#include <limits>
#if PLATFORM(WX)
#include <wx/defs.h>
@@ -62,21 +61,17 @@ namespace WebCore {
using namespace HTMLNames;
-static const char hexDigits[17] = "0123456789ABCDEF";
-
-HTMLFormElement::HTMLFormElement(Document* doc)
- : HTMLElement(formTag, doc)
+HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* doc)
+ : HTMLElement(tagName, doc)
, m_elementAliases(0)
, collectionInfo(0)
- , m_enctype("application/x-www-form-urlencoded")
- , m_post(false)
- , m_multipart(false)
, m_autocomplete(true)
, m_insubmit(false)
, m_doingsubmit(false)
, m_inreset(false)
, m_malformed(false)
{
+ ASSERT(hasTagName(formTag));
}
HTMLFormElement::~HTMLFormElement()
@@ -161,193 +156,93 @@ void HTMLFormElement::submitClick(Event* event)
prepareSubmit(event);
}
-static void appendString(Vector<char>& buffer, const char* string)
-{
- buffer.append(string, strlen(string));
-}
-
-static void appendString(Vector<char>& buffer, const CString& string)
-{
- buffer.append(string.data(), string.length());
-}
-
-static void appendEncodedString(Vector<char>& buffer, const CString& string)
-{
- // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
- int length = string.length();
- for (int i = 0; i < length; i++) {
- unsigned char c = string.data()[i];
-
- // Same safe characters as Netscape for compatibility.
- static const char safe[] = "-._*";
- if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || strchr(safe, c))
- buffer.append(c);
- else if (c == ' ')
- buffer.append('+');
- else if (c == '\n' || (c == '\r' && (i + 1 >= length || string.data()[i + 1] != '\n')))
- appendString(buffer, "%0D%0A");
- else if (c != '\r') {
- buffer.append('%');
- buffer.append(hexDigits[c >> 4]);
- buffer.append(hexDigits[c & 0xF]);
- }
- }
-}
-
-// FIXME: Move to platform directory?
-static int randomNumber()
-{
- static bool randomSeeded = false;
-
-#if PLATFORM(DARWIN)
- if (!randomSeeded) {
- srandomdev();
- randomSeeded = true;
- }
- return random();
-#else
- if (!randomSeeded) {
- srand(static_cast<unsigned>(time(0)));
- randomSeeded = true;
- }
- return rand();
-#endif
-}
-
TextEncoding HTMLFormElement::dataEncoding() const
{
if (isMailtoForm())
return UTF8Encoding();
- TextEncoding encoding;
- String str = m_acceptcharset;
- str.replace(',', ' ');
- Vector<String> charsets;
- str.split(' ', charsets);
- Vector<String>::const_iterator end = charsets.end();
- for (Vector<String>::const_iterator it = charsets.begin(); it != end; ++it)
- if ((encoding = TextEncoding(*it)).isValid())
- return encoding;
- if (Frame* frame = document()->frame())
- return frame->loader()->encoding();
- return Latin1Encoding();
+ return m_formDataBuilder.dataEncoding(document());
}
-PassRefPtr<FormData> HTMLFormElement::formData(const char* boundary) const
+PassRefPtr<FormData> HTMLFormElement::createFormData(const CString& boundary)
{
Vector<char> encodedData;
- TextEncoding encoding = dataEncoding();
+ TextEncoding encoding = dataEncoding().encodingForFormSubmission();
RefPtr<FormData> result = FormData::create();
-
+
for (unsigned i = 0; i < formElements.size(); ++i) {
HTMLFormControlElement* control = formElements[i];
FormDataList list(encoding);
- if (!control->disabled() && control->appendFormData(list, m_multipart)) {
+ if (!control->disabled() && control->appendFormData(list, m_formDataBuilder.isMultiPartForm())) {
size_t formDataListSize = list.list().size();
ASSERT(formDataListSize % 2 == 0);
for (size_t j = 0; j < formDataListSize; j += 2) {
const FormDataList::Item& key = list.list()[j];
const FormDataList::Item& value = list.list()[j + 1];
- if (!m_multipart) {
+ if (!m_formDataBuilder.isMultiPartForm()) {
// Omit the name "isindex" if it's the first form data element.
// FIXME: Why is this a good rule? Is this obsolete now?
if (encodedData.isEmpty() && key.data() == "isindex")
- appendEncodedString(encodedData, value.data());
- else {
- if (!encodedData.isEmpty())
- encodedData.append('&');
- appendEncodedString(encodedData, key.data());
- encodedData.append('=');
- appendEncodedString(encodedData, value.data());
- }
+ FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
+ else
+ m_formDataBuilder.addKeyValuePairAsFormData(encodedData, key.data(), value.data());
} else {
Vector<char> header;
- appendString(header, "--");
- appendString(header, boundary);
- appendString(header, "\r\n");
- appendString(header, "Content-Disposition: form-data; name=\"");
- header.append(key.data().data(), key.data().length());
- header.append('"');
+ m_formDataBuilder.beginMultiPartHeader(header, boundary, key.data());
bool shouldGenerateFile = false;
- // if the current type is FILE, then we also need to
- // include the filename
+ // if the current type is FILE, then we also need to include the filename
if (value.file()) {
const String& path = value.file()->path();
- String filename = value.file()->fileName();
+ String fileName = value.file()->fileName();
// Let the application specify a filename if it's going to generate a replacement file for the upload.
if (!path.isEmpty()) {
if (Page* page = document()->page()) {
- String generatedFilename;
- shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFilename);
- if (shouldGenerateFile)
- filename = generatedFilename;
+ String generatedFileName;
+ if (shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName))
+ fileName = generatedFileName;
}
}
- // 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.
- appendString(header, "; filename=\"");
- appendString(header, encoding.encode(filename.characters(), filename.length(), QuestionMarksForUnencodables));
- header.append('"');
+ // We have to include the filename=".." part in the header, even if the filename is empty
+ m_formDataBuilder.addFilenameToMultiPartHeader(header, encoding, fileName);
- if (!filename.isEmpty()) {
+ if (!fileName.isEmpty()) {
// FIXME: The MIMETypeRegistry function's name makes it sound like it takes a path,
// not just a basename. But filename is not the path. But note that it's not safe to
// just use path instead since in the generated-file case it will not reflect the
// MIME type of the generated file.
- String mimeType = MIMETypeRegistry::getMIMETypeForPath(filename);
- if (!mimeType.isEmpty()) {
- appendString(header, "\r\nContent-Type: ");
- appendString(header, mimeType.latin1());
- }
+ String mimeType = MIMETypeRegistry::getMIMETypeForPath(fileName);
+ if (!mimeType.isEmpty())
+ m_formDataBuilder.addContentTypeToMultiPartHeader(header, mimeType.latin1());
}
}
- appendString(header, "\r\n\r\n");
+ m_formDataBuilder.finishMultiPartHeader(header);
- // append body
+ // Append body
result->appendData(header.data(), header.size());
if (size_t dataSize = value.data().length())
result->appendData(value.data().data(), dataSize);
else if (value.file() && !value.file()->path().isEmpty())
result->appendFile(value.file()->path(), shouldGenerateFile);
+
result->appendData("\r\n", 2);
}
}
}
}
-
- if (m_multipart) {
- appendString(encodedData, "--");
- appendString(encodedData, boundary);
- appendString(encodedData, "--\r\n");
- }
+ if (m_formDataBuilder.isMultiPartForm())
+ m_formDataBuilder.addBoundaryToMultiPartHeader(encodedData, boundary, true);
result->appendData(encodedData.data(), encodedData.size());
return result;
}
-void HTMLFormElement::parseEnctype(const String& type)
-{
- if(type.contains("multipart", false) || type.contains("form-data", false)) {
- m_enctype = "multipart/form-data";
- m_multipart = true;
- } else if (type.contains("text", false) || type.contains("plain", false)) {
- m_enctype = "text/plain";
- m_multipart = false;
- } else {
- m_enctype = "application/x-www-form-urlencoded";
- m_multipart = false;
- }
-}
-
bool HTMLFormElement::isMailtoForm() const
{
return protocolIs(m_url, "mailto");
@@ -373,62 +268,7 @@ bool HTMLFormElement::prepareSubmit(Event* event)
return m_doingsubmit;
}
-void HTMLFormElement::submit()
-{
- submit(0, false);
-}
-
-// Returns a 0-terminated C string in the vector.
-static void getUniqueBoundaryString(Vector<char>& boundary)
-{
- // The RFC 2046 spec says the AlphaNumeric characters plus the following characters
- // are legal for boundaries: '()+_,-./:=?
- // However the following characters, though legal, cause some sites to fail:
- // (),./:=
- // http://bugs.webkit.org/show_bug.cgi?id=13352
- static const char AlphaNumericEncMap[64] =
- {
- 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
- 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
- 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
- 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
- 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
- 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
- 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33,
- 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x41
- // FIXME <rdar://problem/5252577> gmail does not accept legal characters in the form boundary
- // As stated above, some legal characters cause, sites to fail. Specifically
- // the / character which was the last character in the above array. I have
- // replaced the last character with another character already in the array
- // (notice the first and last values are both 0x41, A). Instead of picking
- // another unique legal character for boundary strings that, because it has
- // never been tested, may or may not break other sites, I simply
- // replaced / with A. This means A is twice as likely to occur in our boundary
- // strings than any other character but I think this is fine for the time being.
- // The FIXME here is about restoring the / character once the aforementioned
- // radar has been resolved.
- };
-
- // Start with an informative prefix.
- const char boundaryPrefix[] = "----WebKitFormBoundary";
- boundary.append(boundaryPrefix, strlen(boundaryPrefix));
-
- // Append 16 random 7bit ascii AlphaNumeric characters.
- Vector<char> randomBytes;
-
- for (int i = 0; i < 4; ++i) {
- int randomness = randomNumber();
- randomBytes.append(AlphaNumericEncMap[(randomness >> 24) & 0x3F]);
- randomBytes.append(AlphaNumericEncMap[(randomness >> 16) & 0x3F]);
- randomBytes.append(AlphaNumericEncMap[(randomness >> 8) & 0x3F]);
- randomBytes.append(AlphaNumericEncMap[randomness & 0x3F]);
- }
-
- boundary.append(randomBytes);
- boundary.append(0); // Add a 0 at the end so we can use this as a C-style string.
-}
-
-void HTMLFormElement::submit(Event* event, bool activateSubmitButton)
+void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockHistory, bool lockBackForwardList)
{
FrameView* view = document()->view();
Frame* frame = document()->frame();
@@ -471,34 +311,33 @@ void HTMLFormElement::submit(Event* event, bool activateSubmitButton)
if (m_url.isEmpty())
m_url = document()->url().string();
- if (m_post) {
- if (m_multipart && isMailtoForm()) {
+ if (m_formDataBuilder.isPostMethod()) {
+ if (m_formDataBuilder.isMultiPartForm() && isMailtoForm()) {
setEnctype("application/x-www-form-urlencoded");
- m_multipart = false;
+ ASSERT(!m_formDataBuilder.isMultiPartForm());
}
- if (!m_multipart) {
- RefPtr<FormData> data = formData(0);
+ if (!m_formDataBuilder.isMultiPartForm()) {
+ RefPtr<FormData> data = createFormData(CString());
if (isMailtoForm()) {
String body = data->flattenToString();
- if (equalIgnoringCase(enctype(), "text/plain")) {
+ if (equalIgnoringCase(m_formDataBuilder.encodingType(), "text/plain")) {
// Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20.
body = decodeURLEscapeSequences(body.replace('&', "\r\n").replace('+', ' ') + "\r\n");
}
Vector<char> bodyData;
- appendString(bodyData, "body=");
- appendEncodedString(bodyData, body.utf8());
+ bodyData.append("body=", 5);
+ FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8());
data = FormData::create(String(bodyData.data(), bodyData.size()).replace('+', "%20").latin1());
}
- frame->loader()->submitForm("POST", m_url, data, m_target, enctype(), String(), event);
+ frame->loader()->submitForm("POST", m_url, data, m_target, m_formDataBuilder.encodingType(), String(), event, lockHistory, lockBackForwardList);
} else {
- Vector<char> boundary;
- getUniqueBoundaryString(boundary);
- frame->loader()->submitForm("POST", m_url, formData(boundary.data()), m_target, enctype(), boundary.data(), event);
+ Vector<char> boundary = m_formDataBuilder.generateUniqueBoundaryString();
+ frame->loader()->submitForm("POST", m_url, createFormData(boundary.data()), m_target, m_formDataBuilder.encodingType(), boundary.data(), event, lockHistory, lockBackForwardList);
}
} else {
- m_multipart = false;
- frame->loader()->submitForm("GET", m_url, formData(0), m_target, String(), String(), event);
+ m_formDataBuilder.setIsMultiPartForm(false);
+ frame->loader()->submitForm("GET", m_url, createFormData(CString()), m_target, String(), String(), event, lockHistory, lockBackForwardList);
}
if (needButtonActivation && firstSuccessfulSubmitButton)
@@ -534,17 +373,14 @@ void HTMLFormElement::parseMappedAttribute(MappedAttribute* attr)
m_url = parseURL(attr->value());
else if (attr->name() == targetAttr)
m_target = attr->value();
- else if (attr->name() == methodAttr) {
- if (equalIgnoringCase(attr->value(), "post"))
- m_post = true;
- else if (equalIgnoringCase(attr->value(), "get"))
- m_post = false;
- } else if (attr->name() == enctypeAttr)
- parseEnctype(attr->value());
+ else if (attr->name() == methodAttr)
+ m_formDataBuilder.parseMethodType(attr->value());
+ else if (attr->name() == enctypeAttr)
+ m_formDataBuilder.parseEncodingType(attr->value());
else if (attr->name() == accept_charsetAttr)
// space separated list of charsets the server
// accepts - see rfc2045
- m_acceptcharset = attr->value();
+ m_formDataBuilder.setAcceptCharset(attr->value());
else if (attr->name() == acceptAttr) {
// ignore this one for the moment...
} else if (attr->name() == autocompleteAttr) {
@@ -591,7 +427,7 @@ unsigned HTMLFormElement::formElementIndex(HTMLFormControlElement* e)
if (node == e)
return i;
if (node->isHTMLElement()
- && static_cast<HTMLElement*>(node)->isGenericFormElement()
+ && static_cast<Element*>(node)->isFormControlElement()
&& static_cast<HTMLFormControlElement*>(node)->form() == this)
++i;
}
@@ -642,11 +478,6 @@ void HTMLFormElement::setName(const String &value)
setAttribute(nameAttr, value);
}
-String HTMLFormElement::acceptCharset() const
-{
- return getAttribute(accept_charsetAttr);
-}
-
void HTMLFormElement::setAcceptCharset(const String &value)
{
setAttribute(accept_charsetAttr, value);