1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
6 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB.  If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "HTMLFormElement.h"
27
28#include "CSSHelper.h"
29#include "Chrome.h"
30#include "ChromeClient.h"
31#include "Document.h"
32#include "Event.h"
33#include "EventNames.h"
34#include "FileList.h"
35#include "FileSystem.h"
36#include "FormData.h"
37#include "FormDataList.h"
38#include "FormState.h"
39#include "Frame.h"
40#include "FrameLoader.h"
41#include "HTMLDocument.h"
42#include "HTMLFormCollection.h"
43#include "HTMLImageElement.h"
44#include "HTMLInputElement.h"
45#include "HTMLNames.h"
46#include "ScriptEventListener.h"
47#include "MIMETypeRegistry.h"
48#include "MappedAttribute.h"
49#include "Page.h"
50#include "RenderTextControl.h"
51#include "ValidityState.h"
52#include <limits>
53#include <wtf/CurrentTime.h>
54#include <wtf/RandomNumber.h>
55
56#if PLATFORM(WX)
57#include <wx/defs.h>
58#include <wx/filename.h>
59#endif
60
61using namespace std;
62
63namespace WebCore {
64
65using namespace HTMLNames;
66
67static int64_t generateFormDataIdentifier()
68{
69    // Initialize to the current time to reduce the likelihood of generating
70    // identifiers that overlap with those from past/future browser sessions.
71    static int64_t nextIdentifier = static_cast<int64_t>(currentTime() * 1000000.0);
72    return ++nextIdentifier;
73}
74
75HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* doc)
76    : HTMLElement(tagName, doc)
77    , m_elementAliases(0)
78    , collectionInfo(0)
79    , m_autocomplete(true)
80    , m_insubmit(false)
81    , m_doingsubmit(false)
82    , m_inreset(false)
83    , m_malformed(false)
84    , m_demoted(false)
85{
86    ASSERT(hasTagName(formTag));
87}
88
89HTMLFormElement::~HTMLFormElement()
90{
91    if (!m_autocomplete)
92        document()->unregisterForDocumentActivationCallbacks(this);
93
94    delete m_elementAliases;
95    delete collectionInfo;
96
97    for (unsigned i = 0; i < formElements.size(); ++i)
98        formElements[i]->formDestroyed();
99    for (unsigned i = 0; i < imgElements.size(); ++i)
100        imgElements[i]->m_form = 0;
101}
102
103bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
104{
105    return document()->completeURL(url).protocolIs("https");
106}
107
108void HTMLFormElement::attach()
109{
110    HTMLElement::attach();
111}
112
113bool HTMLFormElement::rendererIsNeeded(RenderStyle* style)
114{
115    if (!isDemoted())
116        return HTMLElement::rendererIsNeeded(style);
117
118    Node* node = parentNode();
119    RenderObject* parentRenderer = node->renderer();
120    bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
121        || (parentRenderer->isTableRow() && node->hasTagName(trTag))
122        || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
123        || (parentRenderer->isTableCol() && node->hasTagName(colTag))
124        || (parentRenderer->isTableCell() && node->hasTagName(trTag));
125
126    if (!parentIsTableElementPart)
127        return true;
128
129    EDisplay display = style->display();
130    bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
131        || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
132        || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
133        || display == TABLE_CAPTION;
134
135    return formIsTablePart;
136}
137
138void HTMLFormElement::insertedIntoDocument()
139{
140    if (document()->isHTMLDocument())
141        static_cast<HTMLDocument*>(document())->addNamedItem(m_name);
142
143    HTMLElement::insertedIntoDocument();
144}
145
146void HTMLFormElement::removedFromDocument()
147{
148    if (document()->isHTMLDocument())
149        static_cast<HTMLDocument*>(document())->removeNamedItem(m_name);
150
151    HTMLElement::removedFromDocument();
152}
153
154void HTMLFormElement::handleLocalEvents(Event* event)
155{
156    Node* targetNode = event->target()->toNode();
157    if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
158        event->stopPropagation();
159        return;
160    }
161    HTMLElement::handleLocalEvents(event);
162}
163
164unsigned HTMLFormElement::length() const
165{
166    int len = 0;
167    for (unsigned i = 0; i < formElements.size(); ++i)
168        if (formElements[i]->isEnumeratable())
169            ++len;
170
171    return len;
172}
173
174Node* HTMLFormElement::item(unsigned index)
175{
176    return elements()->item(index);
177}
178
179void HTMLFormElement::submitClick(Event* event)
180{
181    bool submitFound = false;
182    for (unsigned i = 0; i < formElements.size(); ++i) {
183        if (formElements[i]->hasLocalName(inputTag)) {
184            HTMLInputElement* element = static_cast<HTMLInputElement*>(formElements[i]);
185            if (element->isSuccessfulSubmitButton() && element->renderer()) {
186                submitFound = true;
187                element->dispatchSimulatedClick(event);
188                break;
189            }
190        }
191    }
192    if (!submitFound) // submit the form without a submit or image input
193        prepareSubmit(event);
194}
195
196TextEncoding HTMLFormElement::dataEncoding() const
197{
198    if (isMailtoForm())
199        return UTF8Encoding();
200
201    return m_formDataBuilder.dataEncoding(document());
202}
203
204PassRefPtr<FormData> HTMLFormElement::createFormData(const CString& boundary)
205{
206    Vector<char> encodedData;
207    TextEncoding encoding = dataEncoding().encodingForFormSubmission();
208
209    RefPtr<FormData> result = FormData::create();
210
211    for (unsigned i = 0; i < formElements.size(); ++i) {
212        HTMLFormControlElement* control = formElements[i];
213        FormDataList list(encoding);
214
215        if (!control->disabled() && control->appendFormData(list, m_formDataBuilder.isMultiPartForm())) {
216            size_t formDataListSize = list.list().size();
217            ASSERT(formDataListSize % 2 == 0);
218            for (size_t j = 0; j < formDataListSize; j += 2) {
219                const FormDataList::Item& key = list.list()[j];
220                const FormDataList::Item& value = list.list()[j + 1];
221                if (!m_formDataBuilder.isMultiPartForm()) {
222                    // Omit the name "isindex" if it's the first form data element.
223                    // FIXME: Why is this a good rule? Is this obsolete now?
224                    if (encodedData.isEmpty() && key.data() == "isindex")
225                        FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
226                    else
227                        m_formDataBuilder.addKeyValuePairAsFormData(encodedData, key.data(), value.data());
228                } else {
229                    Vector<char> header;
230                    m_formDataBuilder.beginMultiPartHeader(header, boundary, key.data());
231
232                    bool shouldGenerateFile = false;
233                    // if the current type is FILE, then we also need to include the filename
234                    if (value.file()) {
235                        const String& path = value.file()->path();
236                        String fileName = value.file()->fileName();
237
238                        // Let the application specify a filename if it's going to generate a replacement file for the upload.
239                        if (!path.isEmpty()) {
240                            if (Page* page = document()->page()) {
241                                String generatedFileName;
242                                shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
243                                if (shouldGenerateFile)
244                                    fileName = generatedFileName;
245                            }
246                        }
247
248                        // We have to include the filename=".." part in the header, even if the filename is empty
249                        m_formDataBuilder.addFilenameToMultiPartHeader(header, encoding, fileName);
250
251                        if (!fileName.isEmpty()) {
252                            // FIXME: The MIMETypeRegistry function's name makes it sound like it takes a path,
253                            // not just a basename. But filename is not the path. But note that it's not safe to
254                            // just use path instead since in the generated-file case it will not reflect the
255                            // MIME type of the generated file.
256                            String mimeType = MIMETypeRegistry::getMIMETypeForPath(fileName);
257                            if (!mimeType.isEmpty())
258                                m_formDataBuilder.addContentTypeToMultiPartHeader(header, mimeType.latin1());
259                        }
260                    }
261
262                    m_formDataBuilder.finishMultiPartHeader(header);
263
264                    // Append body
265                    result->appendData(header.data(), header.size());
266                    if (size_t dataSize = value.data().length())
267                        result->appendData(value.data().data(), dataSize);
268                    else if (value.file() && !value.file()->path().isEmpty())
269                        result->appendFile(value.file()->path(), shouldGenerateFile);
270
271                    result->appendData("\r\n", 2);
272                }
273            }
274        }
275    }
276
277    if (m_formDataBuilder.isMultiPartForm())
278        m_formDataBuilder.addBoundaryToMultiPartHeader(encodedData, boundary, true);
279
280    result->appendData(encodedData.data(), encodedData.size());
281
282    result->setIdentifier(generateFormDataIdentifier());
283    return result;
284}
285
286bool HTMLFormElement::isMailtoForm() const
287{
288    return protocolIs(m_url, "mailto");
289}
290
291bool HTMLFormElement::prepareSubmit(Event* event)
292{
293    Frame* frame = document()->frame();
294    if (m_insubmit || !frame)
295        return m_insubmit;
296
297    m_insubmit = true;
298    m_doingsubmit = false;
299
300    if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)) && !m_doingsubmit)
301        m_doingsubmit = true;
302
303    m_insubmit = false;
304
305    if (m_doingsubmit)
306        submit(event, true, false, NotSubmittedByJavaScript);
307
308    return m_doingsubmit;
309}
310
311static void transferMailtoPostFormDataToURL(RefPtr<FormData>& data, KURL& url, const String& encodingType)
312{
313    String body = data->flattenToString();
314    data = FormData::create();
315
316    if (equalIgnoringCase(encodingType, "text/plain")) {
317        // Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20.
318        body = decodeURLEscapeSequences(body.replace('&', "\r\n").replace('+', ' ') + "\r\n");
319    }
320
321    Vector<char> bodyData;
322    bodyData.append("body=", 5);
323    FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8());
324    body = String(bodyData.data(), bodyData.size()).replace('+', "%20");
325
326    String query = url.query();
327    if (!query.isEmpty())
328        query.append('&');
329    query.append(body);
330    url.setQuery(query);
331}
332
333void HTMLFormElement::submit(Frame* javaScriptActiveFrame)
334{
335    if (javaScriptActiveFrame)
336        submit(0, false, !javaScriptActiveFrame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript);
337    else
338        submit(0, false, false, NotSubmittedByJavaScript);
339}
340
341void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockHistory, FormSubmissionTrigger formSubmissionTrigger)
342{
343    FrameView* view = document()->view();
344    Frame* frame = document()->frame();
345    if (!view || !frame)
346        return;
347
348    if (m_insubmit) {
349        m_doingsubmit = true;
350        return;
351    }
352
353    m_insubmit = true;
354
355    HTMLFormControlElement* firstSuccessfulSubmitButton = 0;
356    bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
357
358    Vector<pair<String, String> > formValues;
359
360    for (unsigned i = 0; i < formElements.size(); ++i) {
361        HTMLFormControlElement* control = formElements[i];
362        if (control->hasLocalName(inputTag)) {
363            HTMLInputElement* input = static_cast<HTMLInputElement*>(control);
364            if (input->isTextField()) {
365                formValues.append(pair<String, String>(input->name(), input->value()));
366                if (input->isSearchField())
367                    input->addSearchResult();
368            }
369        }
370        if (needButtonActivation) {
371            if (control->isActivatedSubmit())
372                needButtonActivation = false;
373            else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
374                firstSuccessfulSubmitButton = control;
375        }
376    }
377
378    RefPtr<FormState> formState = FormState::create(this, formValues, frame, formSubmissionTrigger);
379
380    if (needButtonActivation && firstSuccessfulSubmitButton)
381        firstSuccessfulSubmitButton->setActivatedSubmit(true);
382
383    if (m_url.isEmpty())
384        m_url = document()->url().string();
385
386    if (m_formDataBuilder.isPostMethod()) {
387        if (m_formDataBuilder.isMultiPartForm() && isMailtoForm()) {
388            setEnctype("application/x-www-form-urlencoded");
389            ASSERT(!m_formDataBuilder.isMultiPartForm());
390        }
391
392        if (!m_formDataBuilder.isMultiPartForm()) {
393            RefPtr<FormData> data = createFormData(CString());
394
395            if (isMailtoForm()) {
396                // Convert the form data into a string that we put into the URL.
397                KURL url = document()->completeURL(m_url);
398                transferMailtoPostFormDataToURL(data, url, m_formDataBuilder.encodingType());
399                m_url = url.string();
400            }
401
402            frame->loader()->submitForm("POST", m_url, data.release(), m_target, m_formDataBuilder.encodingType(), String(), lockHistory, event, formState.release());
403        } else {
404            Vector<char> boundary = m_formDataBuilder.generateUniqueBoundaryString();
405            frame->loader()->submitForm("POST", m_url, createFormData(boundary.data()), m_target, m_formDataBuilder.encodingType(), boundary.data(), lockHistory, event, formState.release());
406        }
407    } else {
408        m_formDataBuilder.setIsMultiPartForm(false);
409        frame->loader()->submitForm("GET", m_url, createFormData(CString()), m_target, String(), String(), lockHistory, event, formState.release());
410    }
411
412    if (needButtonActivation && firstSuccessfulSubmitButton)
413        firstSuccessfulSubmitButton->setActivatedSubmit(false);
414
415    m_doingsubmit = m_insubmit = false;
416}
417
418void HTMLFormElement::reset()
419{
420    Frame* frame = document()->frame();
421    if (m_inreset || !frame)
422        return;
423
424    m_inreset = true;
425
426    // ### DOM2 labels this event as not cancelable, however
427    // common browsers( sick! ) allow it be cancelled.
428    if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
429        m_inreset = false;
430        return;
431    }
432
433    for (unsigned i = 0; i < formElements.size(); ++i)
434        formElements[i]->reset();
435
436    m_inreset = false;
437}
438
439void HTMLFormElement::parseMappedAttribute(MappedAttribute* attr)
440{
441    if (attr->name() == actionAttr)
442        m_url = deprecatedParseURL(attr->value());
443    else if (attr->name() == targetAttr)
444        m_target = attr->value();
445    else if (attr->name() == methodAttr)
446        m_formDataBuilder.parseMethodType(attr->value());
447    else if (attr->name() == enctypeAttr)
448        m_formDataBuilder.parseEncodingType(attr->value());
449    else if (attr->name() == accept_charsetAttr)
450        // space separated list of charsets the server
451        // accepts - see rfc2045
452        m_formDataBuilder.setAcceptCharset(attr->value());
453    else if (attr->name() == acceptAttr) {
454        // ignore this one for the moment...
455    } else if (attr->name() == autocompleteAttr) {
456        m_autocomplete = !equalIgnoringCase(attr->value(), "off");
457        if (!m_autocomplete)
458            document()->registerForDocumentActivationCallbacks(this);
459        else
460            document()->unregisterForDocumentActivationCallbacks(this);
461    } else if (attr->name() == onsubmitAttr)
462        setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attr));
463    else if (attr->name() == onresetAttr)
464        setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attr));
465    else if (attr->name() == nameAttr) {
466        const AtomicString& newName = attr->value();
467        if (inDocument() && document()->isHTMLDocument()) {
468            HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
469            document->removeNamedItem(m_name);
470            document->addNamedItem(newName);
471        }
472        m_name = newName;
473    } else
474        HTMLElement::parseMappedAttribute(attr);
475}
476
477template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
478{
479    size_t size = vec.size();
480    for (size_t i = 0; i != size; ++i)
481        if (vec[i] == item) {
482            vec.remove(i);
483            break;
484        }
485}
486
487unsigned HTMLFormElement::formElementIndex(HTMLFormControlElement* e)
488{
489    // Check for the special case where this element is the very last thing in
490    // the form's tree of children; we don't want to walk the entire tree in that
491    // common case that occurs during parsing; instead we'll just return a value
492    // that says "add this form element to the end of the array".
493    if (e->traverseNextNode(this)) {
494        unsigned i = 0;
495        for (Node* node = this; node; node = node->traverseNextNode(this)) {
496            if (node == e)
497                return i;
498            if (node->isHTMLElement()
499                    && static_cast<Element*>(node)->isFormControlElement()
500                    && static_cast<HTMLFormControlElement*>(node)->form() == this)
501                ++i;
502        }
503    }
504    return formElements.size();
505}
506
507void HTMLFormElement::registerFormElement(HTMLFormControlElement* e)
508{
509    document()->checkedRadioButtons().removeButton(e);
510    m_checkedRadioButtons.addButton(e);
511    formElements.insert(formElementIndex(e), e);
512}
513
514void HTMLFormElement::removeFormElement(HTMLFormControlElement* e)
515{
516    m_checkedRadioButtons.removeButton(e);
517    removeFromVector(formElements, e);
518}
519
520bool HTMLFormElement::isURLAttribute(Attribute* attr) const
521{
522    return attr->name() == actionAttr;
523}
524
525void HTMLFormElement::registerImgElement(HTMLImageElement* e)
526{
527    ASSERT(imgElements.find(e) == notFound);
528    imgElements.append(e);
529}
530
531void HTMLFormElement::removeImgElement(HTMLImageElement* e)
532{
533    ASSERT(imgElements.find(e) != notFound);
534    removeFromVector(imgElements, e);
535}
536
537PassRefPtr<HTMLCollection> HTMLFormElement::elements()
538{
539    return HTMLFormCollection::create(this);
540}
541
542String HTMLFormElement::name() const
543{
544    return getAttribute(nameAttr);
545}
546
547void HTMLFormElement::setName(const String &value)
548{
549    setAttribute(nameAttr, value);
550}
551
552bool HTMLFormElement::noValidate() const
553{
554    return !getAttribute(novalidateAttr).isNull();
555}
556
557void HTMLFormElement::setNoValidate(bool novalidate)
558{
559    setAttribute(novalidateAttr, novalidate ? "" : 0);
560}
561
562void HTMLFormElement::setAcceptCharset(const String &value)
563{
564    setAttribute(accept_charsetAttr, value);
565}
566
567String HTMLFormElement::action() const
568{
569    return getAttribute(actionAttr);
570}
571
572void HTMLFormElement::setAction(const String &value)
573{
574    setAttribute(actionAttr, value);
575}
576
577void HTMLFormElement::setEnctype(const String &value)
578{
579    setAttribute(enctypeAttr, value);
580}
581
582String HTMLFormElement::method() const
583{
584    return getAttribute(methodAttr);
585}
586
587void HTMLFormElement::setMethod(const String &value)
588{
589    setAttribute(methodAttr, value);
590}
591
592String HTMLFormElement::target() const
593{
594    return getAttribute(targetAttr);
595}
596
597void HTMLFormElement::setTarget(const String &value)
598{
599    setAttribute(targetAttr, value);
600}
601
602HTMLFormControlElement* HTMLFormElement::defaultButton() const
603{
604    for (unsigned i = 0; i < formElements.size(); ++i) {
605        HTMLFormControlElement* control = formElements[i];
606        if (control->isSuccessfulSubmitButton())
607            return control;
608    }
609
610    return 0;
611}
612
613bool HTMLFormElement::checkValidity()
614{
615    // TODO: Check for unhandled invalid controls, see #27452 for tips.
616
617    bool hasOnlyValidControls = true;
618    for (unsigned i = 0; i < formElements.size(); ++i) {
619        HTMLFormControlElement* control = formElements[i];
620        if (!control->checkValidity())
621            hasOnlyValidControls = false;
622    }
623
624    return hasOnlyValidControls;
625}
626
627PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias)
628{
629    if (alias.isEmpty() || !m_elementAliases)
630        return 0;
631    return m_elementAliases->get(alias.impl());
632}
633
634void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
635{
636    if (alias.isEmpty())
637        return;
638    if (!m_elementAliases)
639        m_elementAliases = new AliasMap;
640    m_elementAliases->set(alias.impl(), element);
641}
642
643void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
644{
645    elements()->namedItems(name, namedItems);
646
647    // see if we have seen something with this name before
648    RefPtr<HTMLFormControlElement> aliasElem;
649    if (aliasElem = elementForAlias(name)) {
650        bool found = false;
651        for (unsigned n = 0; n < namedItems.size(); n++) {
652            if (namedItems[n] == aliasElem.get()) {
653                found = true;
654                break;
655            }
656        }
657        if (!found)
658            // we have seen it before but it is gone now. still, we need to return it.
659            namedItems.append(aliasElem.get());
660    }
661    // name has been accessed, remember it
662    if (namedItems.size() && aliasElem != namedItems.first())
663        addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
664}
665
666void HTMLFormElement::documentDidBecomeActive()
667{
668    ASSERT(!m_autocomplete);
669
670    for (unsigned i = 0; i < formElements.size(); ++i)
671        formElements[i]->reset();
672}
673
674void HTMLFormElement::willMoveToNewOwnerDocument()
675{
676    if (!m_autocomplete)
677        document()->unregisterForDocumentActivationCallbacks(this);
678    HTMLElement::willMoveToNewOwnerDocument();
679}
680
681void HTMLFormElement::didMoveToNewOwnerDocument()
682{
683    if (!m_autocomplete)
684        document()->registerForDocumentActivationCallbacks(this);
685    HTMLElement::didMoveToNewOwnerDocument();
686}
687
688} // namespace
689