1 /**
2 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21 #include "config.h"
22
23 #if ENABLE(WML)
24 #include "WMLGoElement.h"
25
26 #include "Attribute.h"
27 #include "FormData.h"
28 #include "FormDataBuilder.h"
29 #include "FormSubmission.h"
30 #include "Frame.h"
31 #include "FrameLoader.h"
32 #include "HTMLNames.h"
33 #include "ResourceRequest.h"
34 #include "TextEncoding.h"
35 #include "WMLCardElement.h"
36 #include "WMLDocument.h"
37 #include "WMLNames.h"
38 #include "WMLPageState.h"
39 #include "WMLPostfieldElement.h"
40 #include "WMLTimerElement.h"
41 #include "WMLVariables.h"
42 #include <wtf/text/CString.h>
43
44 namespace WebCore {
45
46 using namespace WMLNames;
47
WMLGoElement(const QualifiedName & tagName,Document * doc)48 WMLGoElement::WMLGoElement(const QualifiedName& tagName, Document* doc)
49 : WMLTaskElement(tagName, doc)
50 {
51 }
52
create(const QualifiedName & tagName,Document * document)53 PassRefPtr<WMLGoElement> WMLGoElement::create(const QualifiedName& tagName, Document* document)
54 {
55 return adoptRef(new WMLGoElement(tagName, document));
56 }
57
registerPostfieldElement(WMLPostfieldElement * postfield)58 void WMLGoElement::registerPostfieldElement(WMLPostfieldElement* postfield)
59 {
60 ASSERT(m_postfieldElements.find(postfield) == WTF::notFound);
61 m_postfieldElements.append(postfield);
62 }
63
deregisterPostfieldElement(WMLPostfieldElement * postfield)64 void WMLGoElement::deregisterPostfieldElement(WMLPostfieldElement* postfield)
65 {
66 size_t position = m_postfieldElements.find(postfield);
67 ASSERT(position != WTF::notFound);
68 m_postfieldElements.remove(position);
69 }
70
parseMappedAttribute(Attribute * attr)71 void WMLGoElement::parseMappedAttribute(Attribute* attr)
72 {
73 if (attr->name() == HTMLNames::methodAttr)
74 m_formAttributes.parseMethodType(attr->value());
75 else if (attr->name() == HTMLNames::enctypeAttr)
76 m_formAttributes.parseEncodingType(parseValueSubstitutingVariableReferences(attr->value()));
77 else if (attr->name() == HTMLNames::accept_charsetAttr)
78 m_formAttributes.setAcceptCharset(parseValueForbiddingVariableReferences(attr->value()));
79 else
80 WMLTaskElement::parseMappedAttribute(attr);
81 }
82
executeTask()83 void WMLGoElement::executeTask()
84 {
85 ASSERT(document()->isWMLDocument());
86 WMLDocument* document = static_cast<WMLDocument*>(this->document());
87
88 WMLPageState* pageState = wmlPageStateForDocument(document);
89 if (!pageState)
90 return;
91
92 WMLCardElement* card = document->activeCard();
93 if (!card)
94 return;
95
96 Frame* frame = document->frame();
97 if (!frame)
98 return;
99
100 FrameLoader* loader = frame->loader();
101 if (!loader)
102 return;
103
104 String href = getAttribute(HTMLNames::hrefAttr);
105 if (href.isEmpty())
106 return;
107
108 // Substitute variables within target url attribute value
109 KURL url = document->completeURL(substituteVariableReferences(href, document, WMLVariableEscapingEscape));
110 if (url.isEmpty())
111 return;
112
113 storeVariableState(pageState);
114
115 // Stop the timer of the current card if it is active
116 if (WMLTimerElement* eventTimer = card->eventTimer())
117 eventTimer->stop();
118
119 // FIXME: 'newcontext' handling not implemented for external cards
120 bool inSameDeck = document->url().path() == url.path();
121 if (inSameDeck && url.hasFragmentIdentifier()) {
122 if (WMLCardElement* card = WMLCardElement::findNamedCardInDocument(document, url.fragmentIdentifier())) {
123 if (card->isNewContext())
124 pageState->reset();
125 }
126 }
127
128 // Prepare loading the destination url
129 ResourceRequest request(url);
130
131 if (getAttribute(sendrefererAttr) == "true")
132 request.setHTTPReferrer(loader->outgoingReferrer());
133
134 String cacheControl = getAttribute(cache_controlAttr);
135
136 if (m_formAttributes.method() == FormSubmission::PostMethod)
137 preparePOSTRequest(request, inSameDeck, cacheControl);
138 else
139 prepareGETRequest(request, url);
140
141 // Set HTTP cache-control header if needed
142 if (!cacheControl.isEmpty()) {
143 request.setHTTPHeaderField("cache-control", cacheControl);
144
145 if (cacheControl == "no-cache")
146 request.setCachePolicy(ReloadIgnoringCacheData);
147 }
148
149 loader->load(request, false);
150 }
151
preparePOSTRequest(ResourceRequest & request,bool inSameDeck,const String & cacheControl)152 void WMLGoElement::preparePOSTRequest(ResourceRequest& request, bool inSameDeck, const String& cacheControl)
153 {
154 request.setHTTPMethod("POST");
155
156 if (inSameDeck && cacheControl != "no-cache") {
157 request.setCachePolicy(ReturnCacheDataDontLoad);
158 return;
159 }
160
161 RefPtr<FormData> data;
162
163 if (m_formAttributes.isMultiPartForm()) { // multipart/form-data
164 Vector<char> boundary = FormDataBuilder::generateUniqueBoundaryString();
165 data = createFormData(boundary.data());
166 request.setHTTPContentType(m_formAttributes.encodingType() + "; boundary=" + boundary.data());
167 } else {
168 // text/plain or application/x-www-form-urlencoded
169 data = createFormData(CString());
170 request.setHTTPContentType(m_formAttributes.encodingType());
171 }
172
173 request.setHTTPBody(data.get());
174 }
175
prepareGETRequest(ResourceRequest & request,const KURL & url)176 void WMLGoElement::prepareGETRequest(ResourceRequest& request, const KURL& url)
177 {
178 request.setHTTPMethod("GET");
179
180 // Eventually display error message?
181 if (m_formAttributes.isMultiPartForm())
182 return;
183
184 RefPtr<FormData> data = createFormData(CString());
185
186 KURL remoteURL(url);
187 remoteURL.setQuery(data->flattenToString());
188 request.setURL(remoteURL);
189 }
190
createFormData(const CString & boundary)191 PassRefPtr<FormData> WMLGoElement::createFormData(const CString& boundary)
192 {
193 CString key;
194 CString value;
195
196 Vector<char> encodedData;
197 TextEncoding encoding = FormDataBuilder::encodingFromAcceptCharset(m_formAttributes.acceptCharset(), document()).encodingForFormSubmission();
198
199 Vector<WMLPostfieldElement*>::iterator it = m_postfieldElements.begin();
200 Vector<WMLPostfieldElement*>::iterator end = m_postfieldElements.end();
201
202 RefPtr<FormData> result = FormData::create();
203 for (; it != end; ++it) {
204 (*it)->encodeData(encoding, key, value);
205
206 if (m_formAttributes.isMultiPartForm()) {
207 Vector<char> header;
208 FormDataBuilder::beginMultiPartHeader(header, boundary, key);
209 FormDataBuilder::finishMultiPartHeader(header);
210 result->appendData(header.data(), header.size());
211
212 if (size_t dataSize = value.length())
213 result->appendData(value.data(), dataSize);
214
215 result->appendData("\r\n", 2);
216 } else
217 FormDataBuilder::addKeyValuePairAsFormData(encodedData, key, value);
218 }
219
220 if (m_formAttributes.isMultiPartForm())
221 FormDataBuilder::addBoundaryToMultiPartHeader(encodedData, boundary, true);
222
223 result->appendData(encodedData.data(), encodedData.size());
224 return result;
225 }
226
227 }
228
229 #endif
230