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 "CString.h"
27 #include "FormData.h"
28 #include "Frame.h"
29 #include "FrameLoader.h"
30 #include "HTMLNames.h"
31 #include "MappedAttribute.h"
32 #include "ResourceRequest.h"
33 #include "TextEncoding.h"
34 #include "WMLCardElement.h"
35 #include "WMLDocument.h"
36 #include "WMLNames.h"
37 #include "WMLPageState.h"
38 #include "WMLPostfieldElement.h"
39 #include "WMLTimerElement.h"
40 #include "WMLVariables.h"
41
42 namespace WebCore {
43
44 using namespace WMLNames;
45
WMLGoElement(const QualifiedName & tagName,Document * doc)46 WMLGoElement::WMLGoElement(const QualifiedName& tagName, Document* doc)
47 : WMLTaskElement(tagName, doc)
48 {
49 }
50
registerPostfieldElement(WMLPostfieldElement * postfield)51 void WMLGoElement::registerPostfieldElement(WMLPostfieldElement* postfield)
52 {
53 ASSERT(m_postfieldElements.find(postfield) == WTF::notFound);
54 m_postfieldElements.append(postfield);
55 }
56
deregisterPostfieldElement(WMLPostfieldElement * postfield)57 void WMLGoElement::deregisterPostfieldElement(WMLPostfieldElement* postfield)
58 {
59 size_t position = m_postfieldElements.find(postfield);
60 ASSERT(position != WTF::notFound);
61 m_postfieldElements.remove(position);
62 }
63
parseMappedAttribute(MappedAttribute * attr)64 void WMLGoElement::parseMappedAttribute(MappedAttribute* attr)
65 {
66 if (attr->name() == HTMLNames::methodAttr)
67 m_formDataBuilder.parseMethodType(attr->value());
68 else if (attr->name() == HTMLNames::enctypeAttr)
69 m_formDataBuilder.parseEncodingType(parseValueSubstitutingVariableReferences(attr->value()));
70 else if (attr->name() == HTMLNames::accept_charsetAttr)
71 m_formDataBuilder.setAcceptCharset(parseValueForbiddingVariableReferences(attr->value()));
72 else
73 WMLTaskElement::parseMappedAttribute(attr);
74 }
75
executeTask(Event *)76 void WMLGoElement::executeTask(Event*)
77 {
78 Document* doc = document();
79 WMLPageState* pageState = wmlPageStateForDocument(doc);
80 if (!pageState)
81 return;
82
83 WMLCardElement* card = pageState->activeCard();
84 if (!card)
85 return;
86
87 Frame* frame = doc->frame();
88 if (!frame)
89 return;
90
91 FrameLoader* loader = frame->loader();
92 if (!loader)
93 return;
94
95 String href = getAttribute(HTMLNames::hrefAttr);
96 if (href.isEmpty())
97 return;
98
99 // Substitute variables within target url attribute value
100 KURL url = doc->completeURL(substituteVariableReferences(href, doc, WMLVariableEscapingEscape));
101 if (url.isEmpty())
102 return;
103
104 storeVariableState(pageState);
105
106 // Stop the timer of the current card if it is active
107 if (WMLTimerElement* eventTimer = card->eventTimer())
108 eventTimer->stop();
109
110 // FIXME: 'newcontext' handling not implemented for external cards
111 bool inSameDeck = doc->url().path() == url.path();
112 if (inSameDeck && url.hasFragmentIdentifier()) {
113 if (WMLCardElement* card = WMLCardElement::findNamedCardInDocument(doc, url.fragmentIdentifier())) {
114 if (card->isNewContext())
115 pageState->reset();
116 }
117 }
118
119 // Prepare loading the destination url
120 ResourceRequest request(url);
121
122 if (getAttribute(sendrefererAttr) == "true")
123 request.setHTTPReferrer(loader->outgoingReferrer());
124
125 String cacheControl = getAttribute(cache_controlAttr);
126
127 if (m_formDataBuilder.isPostMethod())
128 preparePOSTRequest(request, inSameDeck, cacheControl);
129 else
130 prepareGETRequest(request, url);
131
132 // Set HTTP cache-control header if needed
133 if (!cacheControl.isEmpty()) {
134 request.setHTTPHeaderField("cache-control", cacheControl);
135
136 if (cacheControl == "no-cache")
137 request.setCachePolicy(ReloadIgnoringCacheData);
138 }
139
140 loader->load(request, false);
141 }
142
preparePOSTRequest(ResourceRequest & request,bool inSameDeck,const String & cacheControl)143 void WMLGoElement::preparePOSTRequest(ResourceRequest& request, bool inSameDeck, const String& cacheControl)
144 {
145 request.setHTTPMethod("POST");
146
147 if (inSameDeck && cacheControl != "no-cache") {
148 request.setCachePolicy(ReturnCacheDataDontLoad);
149 return;
150 }
151
152 RefPtr<FormData> data;
153
154 if (m_formDataBuilder.isMultiPartForm()) { // multipart/form-data
155 Vector<char> boundary = m_formDataBuilder.generateUniqueBoundaryString();
156 data = createFormData(boundary.data());
157 request.setHTTPContentType(m_formDataBuilder.encodingType() + "; boundary=" + boundary.data());
158 } else {
159 // text/plain or application/x-www-form-urlencoded
160 data = createFormData(CString());
161 request.setHTTPContentType(m_formDataBuilder.encodingType());
162 }
163
164 request.setHTTPBody(data.get());
165 }
166
prepareGETRequest(ResourceRequest & request,const KURL & url)167 void WMLGoElement::prepareGETRequest(ResourceRequest& request, const KURL& url)
168 {
169 request.setHTTPMethod("GET");
170
171 // Eventually display error message?
172 if (m_formDataBuilder.isMultiPartForm())
173 return;
174
175 RefPtr<FormData> data = createFormData(CString());
176
177 KURL remoteURL(url);
178 remoteURL.setQuery(data->flattenToString());
179 request.setURL(remoteURL);
180 }
181
createFormData(const CString & boundary)182 PassRefPtr<FormData> WMLGoElement::createFormData(const CString& boundary)
183 {
184 CString key;
185 CString value;
186
187 Vector<char> encodedData;
188 TextEncoding encoding = m_formDataBuilder.dataEncoding(document()).encodingForFormSubmission();
189
190 Vector<WMLPostfieldElement*>::iterator it = m_postfieldElements.begin();
191 Vector<WMLPostfieldElement*>::iterator end = m_postfieldElements.end();
192
193 RefPtr<FormData> result = FormData::create();
194 for (; it != end; ++it) {
195 (*it)->encodeData(encoding, key, value);
196
197 if (m_formDataBuilder.isMultiPartForm()) {
198 Vector<char> header;
199 m_formDataBuilder.beginMultiPartHeader(header, boundary, key);
200 m_formDataBuilder.finishMultiPartHeader(header);
201 result->appendData(header.data(), header.size());
202
203 if (size_t dataSize = value.length())
204 result->appendData(value.data(), dataSize);
205
206 result->appendData("\r\n", 2);
207 } else
208 m_formDataBuilder.addKeyValuePairAsFormData(encodedData, key, value);
209 }
210
211 if (m_formDataBuilder.isMultiPartForm())
212 m_formDataBuilder.addBoundaryToMultiPartHeader(encodedData, boundary, true);
213
214 result->appendData(encodedData.data(), encodedData.size());
215 return result;
216 }
217
218 }
219
220 #endif
221