/** * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "config.h" #if ENABLE(WML) #include "WMLGoElement.h" #include "CString.h" #include "FormData.h" #include "Frame.h" #include "FrameLoader.h" #include "HTMLNames.h" #include "MappedAttribute.h" #include "ResourceRequest.h" #include "TextEncoding.h" #include "WMLCardElement.h" #include "WMLDocument.h" #include "WMLNames.h" #include "WMLPageState.h" #include "WMLPostfieldElement.h" #include "WMLTimerElement.h" #include "WMLVariables.h" namespace WebCore { using namespace WMLNames; WMLGoElement::WMLGoElement(const QualifiedName& tagName, Document* doc) : WMLTaskElement(tagName, doc) { } void WMLGoElement::registerPostfieldElement(WMLPostfieldElement* postfield) { ASSERT(m_postfieldElements.find(postfield) == WTF::notFound); m_postfieldElements.append(postfield); } void WMLGoElement::deregisterPostfieldElement(WMLPostfieldElement* postfield) { size_t position = m_postfieldElements.find(postfield); ASSERT(position != WTF::notFound); m_postfieldElements.remove(position); } void WMLGoElement::parseMappedAttribute(MappedAttribute* attr) { if (attr->name() == HTMLNames::methodAttr) m_formDataBuilder.parseMethodType(attr->value()); else if (attr->name() == HTMLNames::enctypeAttr) m_formDataBuilder.parseEncodingType(parseValueSubstitutingVariableReferences(attr->value())); else if (attr->name() == HTMLNames::accept_charsetAttr) m_formDataBuilder.setAcceptCharset(parseValueForbiddingVariableReferences(attr->value())); else WMLTaskElement::parseMappedAttribute(attr); } void WMLGoElement::executeTask() { ASSERT(document()->isWMLDocument()); WMLDocument* document = static_cast<WMLDocument*>(this->document()); WMLPageState* pageState = wmlPageStateForDocument(document); if (!pageState) return; WMLCardElement* card = document->activeCard(); if (!card) return; Frame* frame = document->frame(); if (!frame) return; FrameLoader* loader = frame->loader(); if (!loader) return; String href = getAttribute(HTMLNames::hrefAttr); if (href.isEmpty()) return; // Substitute variables within target url attribute value KURL url = document->completeURL(substituteVariableReferences(href, document, WMLVariableEscapingEscape)); if (url.isEmpty()) return; storeVariableState(pageState); // Stop the timer of the current card if it is active if (WMLTimerElement* eventTimer = card->eventTimer()) eventTimer->stop(); // FIXME: 'newcontext' handling not implemented for external cards bool inSameDeck = document->url().path() == url.path(); if (inSameDeck && url.hasFragmentIdentifier()) { if (WMLCardElement* card = WMLCardElement::findNamedCardInDocument(document, url.fragmentIdentifier())) { if (card->isNewContext()) pageState->reset(); } } // Prepare loading the destination url ResourceRequest request(url); if (getAttribute(sendrefererAttr) == "true") request.setHTTPReferrer(loader->outgoingReferrer()); String cacheControl = getAttribute(cache_controlAttr); if (m_formDataBuilder.isPostMethod()) preparePOSTRequest(request, inSameDeck, cacheControl); else prepareGETRequest(request, url); // Set HTTP cache-control header if needed if (!cacheControl.isEmpty()) { request.setHTTPHeaderField("cache-control", cacheControl); if (cacheControl == "no-cache") request.setCachePolicy(ReloadIgnoringCacheData); } loader->load(request, false); } void WMLGoElement::preparePOSTRequest(ResourceRequest& request, bool inSameDeck, const String& cacheControl) { request.setHTTPMethod("POST"); if (inSameDeck && cacheControl != "no-cache") { request.setCachePolicy(ReturnCacheDataDontLoad); return; } RefPtr<FormData> data; if (m_formDataBuilder.isMultiPartForm()) { // multipart/form-data Vector<char> boundary = m_formDataBuilder.generateUniqueBoundaryString(); data = createFormData(boundary.data()); request.setHTTPContentType(m_formDataBuilder.encodingType() + "; boundary=" + boundary.data()); } else { // text/plain or application/x-www-form-urlencoded data = createFormData(CString()); request.setHTTPContentType(m_formDataBuilder.encodingType()); } request.setHTTPBody(data.get()); } void WMLGoElement::prepareGETRequest(ResourceRequest& request, const KURL& url) { request.setHTTPMethod("GET"); // Eventually display error message? if (m_formDataBuilder.isMultiPartForm()) return; RefPtr<FormData> data = createFormData(CString()); KURL remoteURL(url); remoteURL.setQuery(data->flattenToString()); request.setURL(remoteURL); } PassRefPtr<FormData> WMLGoElement::createFormData(const CString& boundary) { CString key; CString value; Vector<char> encodedData; TextEncoding encoding = m_formDataBuilder.dataEncoding(document()).encodingForFormSubmission(); Vector<WMLPostfieldElement*>::iterator it = m_postfieldElements.begin(); Vector<WMLPostfieldElement*>::iterator end = m_postfieldElements.end(); RefPtr<FormData> result = FormData::create(); for (; it != end; ++it) { (*it)->encodeData(encoding, key, value); if (m_formDataBuilder.isMultiPartForm()) { Vector<char> header; m_formDataBuilder.beginMultiPartHeader(header, boundary, key); m_formDataBuilder.finishMultiPartHeader(header); result->appendData(header.data(), header.size()); if (size_t dataSize = value.length()) result->appendData(value.data(), dataSize); result->appendData("\r\n", 2); } else m_formDataBuilder.addKeyValuePairAsFormData(encodedData, key, value); } if (m_formDataBuilder.isMultiPartForm()) m_formDataBuilder.addBoundaryToMultiPartHeader(encodedData, boundary, true); result->appendData(encodedData.data(), encodedData.size()); return result; } } #endif