ea6f8f7ece535531b974f87a8865502f02a5083e
[WebKit-https.git] / WebCore / platform / network / qt / QNetworkReplyHandler.cpp
1 /*
2     Copyright (C) 2007 Trolltech ASA
3     Copyright (C) 2007 Staikos Computing Services Inc.  <info@staikos.net>
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Library General Public
7     License as published by the Free Software Foundation; either
8     version 2 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Library General Public License for more details.
14
15     You should have received a copy of the GNU Library General Public License
16     along with this library; see the file COPYING.LIB.  If not, write to
17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18     Boston, MA 02110-1301, USA.
19 */
20 #include "config.h"
21 #include "QNetworkReplyHandler.h"
22
23 #if QT_VERSION >= 0x040400
24
25 #include "HTTPParsers.h"
26 #include "MIMETypeRegistry.h"
27 #include "ResourceHandle.h"
28 #include "ResourceHandleClient.h"
29 #include "ResourceHandleInternal.h"
30 #include "ResourceResponse.h"
31 #include "ResourceRequest.h"
32 #include <QNetworkReply>
33 #include <QNetworkCookie>
34 #include <qwebframe.h>
35 #include <qwebpage.h>
36
37 namespace WebCore {
38
39 QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle *handle)
40     : QObject(0)
41       , m_resourceHandle(handle)
42       , m_reply(0)
43       , m_redirected(false)
44       , m_responseSent(false)
45 {
46     const ResourceRequest &r = m_resourceHandle->request();
47
48     if (r.httpMethod() == "GET")
49         m_method = QNetworkAccessManager::GetOperation;
50     else if (r.httpMethod() == "HEAD")
51         m_method = QNetworkAccessManager::HeadOperation;
52     else if (r.httpMethod() == "POST")
53         m_method = QNetworkAccessManager::PostOperation;
54     else if (r.httpMethod() == "PUT")
55         m_method = QNetworkAccessManager::PutOperation;
56     else
57         m_method = QNetworkAccessManager::UnknownOperation;
58
59     m_request = r.toNetworkRequest();
60     start();
61 }
62
63 void QNetworkReplyHandler::abort()
64 {
65     if (m_reply) {
66         m_reply->abort();
67         deleteLater();
68     }
69 }
70
71 void QNetworkReplyHandler::finish()
72 {
73     sendResponseIfNeeded();
74
75     ResourceHandleClient* client = m_resourceHandle->client();
76     m_reply->deleteLater();
77     if (!client)
78         return;
79     if (m_redirected) {
80         m_redirected = false;
81         start();
82     } else if (m_reply->error() != QNetworkReply::NoError) {
83         QUrl url = m_reply->url();
84         ResourceError error(url.host(), m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),
85                             url.toString(), m_reply->errorString());
86         client->didFail(m_resourceHandle, error);
87     } else {
88         client->didFinishLoading(m_resourceHandle);
89     }
90 }
91
92 void QNetworkReplyHandler::sendResponseIfNeeded()
93 {
94     if (m_responseSent)
95         return;
96     m_responseSent = true;
97
98     ResourceHandleClient* client = m_resourceHandle->client();
99     if (!client)
100         return;
101
102     WebCore::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
103     WebCore::String encoding = extractCharsetFromMediaType(contentType);
104     WebCore::String mimeType = extractMIMETypeFromMediaType(contentType);
105
106     if (mimeType.isEmpty()) {
107         // let's try to guess from the extension
108         QString extension = m_reply->url().path();
109         int index = extension.lastIndexOf(QLatin1Char('.'));
110         if (index > 0) {
111             extension = extension.mid(index + 1);
112             mimeType = MIMETypeRegistry::getMIMETypeForExtension(extension);
113         }
114     }
115
116     KURL url(m_reply->url().toString());
117     String contentDisposition = QString::fromAscii(m_reply->rawHeader("Content-Disposition"));
118
119     ResourceResponse response(url, mimeType,
120                               m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(),
121                               encoding,
122                               filenameFromHTTPContentDisposition(contentDisposition));
123
124     int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
125     if (m_reply->url().scheme() != QLatin1String("file"))
126         response.setHTTPStatusCode(statusCode);
127     else if (m_reply->error() == QNetworkReply::ContentNotFoundError)
128         response.setHTTPStatusCode(404);
129
130
131     /* Fill in the other fields */
132     foreach (QByteArray headerName, m_reply->rawHeaderList())
133         response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName)));
134
135     QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
136     if (redirection.isValid()) {
137         QUrl newUrl = m_reply->url().resolved(redirection);
138         ResourceRequest newRequest = m_resourceHandle->request();
139         newRequest.setURL(KURL(newUrl.toString()));
140         client->willSendRequest(m_resourceHandle, newRequest, response);
141
142         if (statusCode >= 301 && statusCode <= 303 && m_method == QNetworkAccessManager::PostOperation)
143             m_method = QNetworkAccessManager::GetOperation;
144         m_redirected = true;
145         m_responseSent = false;
146
147         m_request.setUrl(newUrl);
148     } else {
149         client->didReceiveResponse(m_resourceHandle, response);
150     }
151 }
152
153 void QNetworkReplyHandler::forwardData()
154 {
155     sendResponseIfNeeded();
156
157     // don't emit the "Document has moved here" type of HTML
158     if (m_redirected)
159         return;
160
161     QByteArray data = m_reply->read(m_reply->bytesAvailable());
162
163     ResourceHandleClient* client = m_resourceHandle->client();
164     if (!client)
165         return;
166
167     if (!data.isEmpty())
168         client->didReceiveData(m_resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/);
169 }
170
171 void QNetworkReplyHandler::start()
172 {
173     ResourceHandleInternal* d = m_resourceHandle->getInternal();
174
175     QNetworkAccessManager* manager = d->m_frame->page()->networkAccessManager();
176
177     switch (m_method) {
178         case QNetworkAccessManager::GetOperation:
179             m_reply = manager->get(m_request);
180             break;
181         case QNetworkAccessManager::PostOperation: {
182             DeprecatedString pd = d->m_request.httpBody()->flattenToString().deprecatedString();
183             m_reply = manager->post(m_request, QByteArray(pd.ascii(), pd.length()));
184             break;
185         }
186         case QNetworkAccessManager::HeadOperation:
187             m_reply = manager->head(m_request);
188             break;
189         case QNetworkAccessManager::PutOperation: {
190             // ### data?
191             DeprecatedString pd = d->m_request.httpBody()->flattenToString().deprecatedString();
192             m_reply = manager->put(m_request, QByteArray(pd.ascii(), pd.length()));
193             break;
194         }
195         case QNetworkAccessManager::UnknownOperation:
196             break; // eh?
197     }
198
199     m_reply->setParent(this);
200
201     connect(m_reply, SIGNAL(finished()),
202             this, SLOT(finish()));
203
204     // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we
205     // can send the response as early as possible
206     QString scheme = m_request.url().scheme();
207     if (scheme == QLatin1String("http") || scheme == QLatin1String("https"))
208         connect(m_reply, SIGNAL(metaDataChanged()),
209                 this, SLOT(sendResponseIfNeeded()));
210
211     connect(m_reply, SIGNAL(readyRead()),
212             this, SLOT(forwardData()));
213 }
214
215 }
216
217 #include "moc_QNetworkReplyHandler.cpp"
218
219 #endif