1 /*
2     Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3     Copyright (C) 2007 Staikos Computing Services Inc.  <info@staikos.net>
4     Copyright (C) 2008 Holger Hans Peter Freyther
5 
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10 
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15 
16     You should have received a copy of the GNU Library General Public License
17     along with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19     Boston, MA 02110-1301, USA.
20 */
21 #include "config.h"
22 #include "QNetworkReplyHandler.h"
23 
24 #include "HTTPParsers.h"
25 #include "MIMETypeRegistry.h"
26 #include "ResourceHandle.h"
27 #include "ResourceHandleClient.h"
28 #include "ResourceHandleInternal.h"
29 #include "ResourceResponse.h"
30 #include "ResourceRequest.h"
31 #include <QDateTime>
32 #include <QFile>
33 #include <QFileInfo>
34 #include <QNetworkReply>
35 #include <QNetworkCookie>
36 #include <qwebframe.h>
37 #include <qwebpage.h>
38 
39 #include <wtf/text/CString.h>
40 
41 #include <QDebug>
42 #include <QCoreApplication>
43 
44 // In Qt 4.8, the attribute for sending a request synchronously will be made public,
45 // for now, use this hackish solution for setting the internal attribute.
46 const QNetworkRequest::Attribute gSynchronousNetworkRequestAttribute = static_cast<QNetworkRequest::Attribute>(QNetworkRequest::HttpPipeliningWasUsedAttribute + 7);
47 
48 static const int gMaxRedirections = 10;
49 
50 namespace WebCore {
51 
52 // Take a deep copy of the FormDataElement
FormDataIODevice(FormData * data)53 FormDataIODevice::FormDataIODevice(FormData* data)
54     : m_formElements(data ? data->elements() : Vector<FormDataElement>())
55     , m_currentFile(0)
56     , m_currentDelta(0)
57     , m_fileSize(0)
58     , m_dataSize(0)
59 {
60     setOpenMode(FormDataIODevice::ReadOnly);
61 
62     if (!m_formElements.isEmpty() && m_formElements[0].m_type == FormDataElement::encodedFile)
63         openFileForCurrentElement();
64     computeSize();
65 }
66 
~FormDataIODevice()67 FormDataIODevice::~FormDataIODevice()
68 {
69     delete m_currentFile;
70 }
71 
computeSize()72 qint64 FormDataIODevice::computeSize()
73 {
74     for (int i = 0; i < m_formElements.size(); ++i) {
75         const FormDataElement& element = m_formElements[i];
76         if (element.m_type == FormDataElement::data)
77             m_dataSize += element.m_data.size();
78         else {
79             QFileInfo fi(element.m_filename);
80             m_fileSize += fi.size();
81         }
82     }
83     return m_dataSize + m_fileSize;
84 }
85 
moveToNextElement()86 void FormDataIODevice::moveToNextElement()
87 {
88     if (m_currentFile)
89         m_currentFile->close();
90     m_currentDelta = 0;
91 
92     m_formElements.remove(0);
93 
94     if (m_formElements.isEmpty() || m_formElements[0].m_type == FormDataElement::data)
95         return;
96 
97     openFileForCurrentElement();
98 }
99 
openFileForCurrentElement()100 void FormDataIODevice::openFileForCurrentElement()
101 {
102     if (!m_currentFile)
103         m_currentFile = new QFile;
104 
105     m_currentFile->setFileName(m_formElements[0].m_filename);
106     m_currentFile->open(QFile::ReadOnly);
107 }
108 
109 // m_formElements[0] is the current item. If the destination buffer is
110 // big enough we are going to read from more than one FormDataElement
readData(char * destination,qint64 size)111 qint64 FormDataIODevice::readData(char* destination, qint64 size)
112 {
113     if (m_formElements.isEmpty())
114         return -1;
115 
116     qint64 copied = 0;
117     while (copied < size && !m_formElements.isEmpty()) {
118         const FormDataElement& element = m_formElements[0];
119         const qint64 available = size-copied;
120 
121         if (element.m_type == FormDataElement::data) {
122             const qint64 toCopy = qMin<qint64>(available, element.m_data.size() - m_currentDelta);
123             memcpy(destination+copied, element.m_data.data()+m_currentDelta, toCopy);
124             m_currentDelta += toCopy;
125             copied += toCopy;
126 
127             if (m_currentDelta == element.m_data.size())
128                 moveToNextElement();
129         } else {
130             const QByteArray data = m_currentFile->read(available);
131             memcpy(destination+copied, data.constData(), data.size());
132             copied += data.size();
133 
134             if (m_currentFile->atEnd() || !m_currentFile->isOpen())
135                 moveToNextElement();
136         }
137     }
138 
139     return copied;
140 }
141 
writeData(const char *,qint64)142 qint64 FormDataIODevice::writeData(const char*, qint64)
143 {
144     return -1;
145 }
146 
isSequential() const147 bool FormDataIODevice::isSequential() const
148 {
149     return true;
150 }
151 
QNetworkReplyHandlerCallQueue(QNetworkReplyHandler * handler,bool deferSignals)152 QNetworkReplyHandlerCallQueue::QNetworkReplyHandlerCallQueue(QNetworkReplyHandler* handler, bool deferSignals)
153     : m_replyHandler(handler)
154     , m_locks(0)
155     , m_deferSignals(deferSignals)
156     , m_flushing(false)
157 {
158     Q_ASSERT(handler);
159 }
160 
push(EnqueuedCall method)161 void QNetworkReplyHandlerCallQueue::push(EnqueuedCall method)
162 {
163     m_enqueuedCalls.append(method);
164     flush();
165 }
166 
lock()167 void QNetworkReplyHandlerCallQueue::lock()
168 {
169     ++m_locks;
170 }
171 
unlock()172 void QNetworkReplyHandlerCallQueue::unlock()
173 {
174     if (!m_locks)
175         return;
176 
177     --m_locks;
178     flush();
179 }
180 
setDeferSignals(bool defer)181 void QNetworkReplyHandlerCallQueue::setDeferSignals(bool defer)
182 {
183     m_deferSignals = defer;
184     flush();
185 }
186 
flush()187 void QNetworkReplyHandlerCallQueue::flush()
188 {
189     if (m_flushing)
190         return;
191 
192     m_flushing = true;
193 
194     while (!m_deferSignals && !m_locks && !m_enqueuedCalls.isEmpty())
195         (m_replyHandler->*(m_enqueuedCalls.takeFirst()))();
196 
197     m_flushing = false;
198 }
199 
200 class QueueLocker {
201 public:
QueueLocker(QNetworkReplyHandlerCallQueue * queue)202     QueueLocker(QNetworkReplyHandlerCallQueue* queue) : m_queue(queue) { m_queue->lock(); }
~QueueLocker()203     ~QueueLocker() { m_queue->unlock(); }
204 private:
205     QNetworkReplyHandlerCallQueue* m_queue;
206 };
207 
QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue * queue,QNetworkReply * reply,bool sniffMIMETypes,QObject * parent)208 QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue* queue, QNetworkReply* reply, bool sniffMIMETypes, QObject* parent)
209     : QObject(parent)
210     , m_reply(reply)
211     , m_queue(queue)
212     , m_responseContainsData(false)
213     , m_sniffMIMETypes(sniffMIMETypes)
214 {
215     Q_ASSERT(m_reply);
216 
217     // setFinished() must be the first that we connect, so isFinished() is updated when running other slots.
218     connect(m_reply, SIGNAL(finished()), this, SLOT(setFinished()));
219     connect(m_reply, SIGNAL(finished()), this, SLOT(receiveMetaData()));
220     connect(m_reply, SIGNAL(readyRead()), this, SLOT(receiveMetaData()));
221 }
222 
~QNetworkReplyWrapper()223 QNetworkReplyWrapper::~QNetworkReplyWrapper()
224 {
225     if (m_reply)
226         m_reply->deleteLater();
227     m_queue->clear();
228 }
229 
release()230 QNetworkReply* QNetworkReplyWrapper::release()
231 {
232     if (!m_reply)
233         return 0;
234 
235     resetConnections();
236     QNetworkReply* reply = m_reply;
237     m_reply = 0;
238     m_sniffer = nullptr;
239 
240     reply->setParent(0);
241     return reply;
242 }
243 
synchronousLoad()244 void QNetworkReplyWrapper::synchronousLoad()
245 {
246     setFinished();
247     receiveMetaData();
248 }
249 
resetConnections()250 void QNetworkReplyWrapper::resetConnections()
251 {
252     if (m_reply) {
253         // Disconnect all connections except the one to setFinished() slot.
254         m_reply->disconnect(this, SLOT(receiveMetaData()));
255         m_reply->disconnect(this, SLOT(didReceiveFinished()));
256         m_reply->disconnect(this, SLOT(didReceiveReadyRead()));
257     }
258     QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
259 }
260 
receiveMetaData()261 void QNetworkReplyWrapper::receiveMetaData()
262 {
263     // This slot is only used to receive the first signal from the QNetworkReply object.
264     resetConnections();
265 
266 
267     WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
268     m_encoding = extractCharsetFromMediaType(contentType);
269     m_advertisedMIMEType = extractMIMETypeFromMediaType(contentType);
270 
271     m_redirectionTargetUrl = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
272     if (m_redirectionTargetUrl.isValid()) {
273         QueueLocker lock(m_queue);
274         m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded);
275         m_queue->push(&QNetworkReplyHandler::finish);
276         return;
277     }
278 
279     if (!m_sniffMIMETypes) {
280         emitMetaDataChanged();
281         return;
282     }
283 
284     bool isSupportedImageType = MIMETypeRegistry::isSupportedImageMIMEType(m_advertisedMIMEType);
285 
286     Q_ASSERT(!m_sniffer);
287 
288     m_sniffer = adoptPtr(new QtMIMETypeSniffer(m_reply, m_advertisedMIMEType, isSupportedImageType));
289 
290     if (m_sniffer->isFinished()) {
291         receiveSniffedMIMEType();
292         return;
293     }
294 
295     connect(m_sniffer.get(), SIGNAL(finished()), this, SLOT(receiveSniffedMIMEType()));
296 }
297 
receiveSniffedMIMEType()298 void QNetworkReplyWrapper::receiveSniffedMIMEType()
299 {
300     Q_ASSERT(m_sniffer);
301 
302     m_sniffedMIMEType = m_sniffer->mimeType();
303     m_sniffer = nullptr;
304 
305     emitMetaDataChanged();
306 }
307 
setFinished()308 void QNetworkReplyWrapper::setFinished()
309 {
310     // Due to a limitation of QNetworkReply public API, its subclasses never get the chance to
311     // change the result of QNetworkReply::isFinished() method. So we need to keep track of the
312     // finished state ourselves. This limitation is fixed in 4.8, but we'll still have applications
313     // that don't use the solution. See http://bugreports.qt.nokia.com/browse/QTBUG-11737.
314     Q_ASSERT(!isFinished());
315     m_reply->setProperty("_q_isFinished", true);
316 }
317 
emitMetaDataChanged()318 void QNetworkReplyWrapper::emitMetaDataChanged()
319 {
320     QueueLocker lock(m_queue);
321     m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded);
322 
323     if (m_reply->bytesAvailable()) {
324         m_responseContainsData = true;
325         m_queue->push(&QNetworkReplyHandler::forwardData);
326     }
327 
328     if (isFinished()) {
329         m_queue->push(&QNetworkReplyHandler::finish);
330         return;
331     }
332 
333     // If not finished, connect to the slots that will be used from this point on.
334     connect(m_reply, SIGNAL(readyRead()), this, SLOT(didReceiveReadyRead()));
335     connect(m_reply, SIGNAL(finished()), this, SLOT(didReceiveFinished()));
336 }
337 
didReceiveReadyRead()338 void QNetworkReplyWrapper::didReceiveReadyRead()
339 {
340     if (m_reply->bytesAvailable())
341         m_responseContainsData = true;
342     m_queue->push(&QNetworkReplyHandler::forwardData);
343 }
344 
didReceiveFinished()345 void QNetworkReplyWrapper::didReceiveFinished()
346 {
347     // Disconnecting will make sure that nothing will happen after emitting the finished signal.
348     resetConnections();
349     m_queue->push(&QNetworkReplyHandler::finish);
350 }
351 
httpMethod() const352 String QNetworkReplyHandler::httpMethod() const
353 {
354     switch (m_method) {
355     case QNetworkAccessManager::GetOperation:
356         return "GET";
357     case QNetworkAccessManager::HeadOperation:
358         return "HEAD";
359     case QNetworkAccessManager::PostOperation:
360         return "POST";
361     case QNetworkAccessManager::PutOperation:
362         return "PUT";
363     case QNetworkAccessManager::DeleteOperation:
364         return "DELETE";
365     case QNetworkAccessManager::CustomOperation:
366         return m_resourceHandle->firstRequest().httpMethod();
367     default:
368         ASSERT_NOT_REACHED();
369         return "GET";
370     }
371 }
372 
QNetworkReplyHandler(ResourceHandle * handle,LoadType loadType,bool deferred)373 QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadType loadType, bool deferred)
374     : QObject(0)
375     , m_resourceHandle(handle)
376     , m_loadType(loadType)
377     , m_redirectionTries(gMaxRedirections)
378     , m_queue(this, deferred)
379 {
380     const ResourceRequest &r = m_resourceHandle->firstRequest();
381 
382     if (r.httpMethod() == "GET")
383         m_method = QNetworkAccessManager::GetOperation;
384     else if (r.httpMethod() == "HEAD")
385         m_method = QNetworkAccessManager::HeadOperation;
386     else if (r.httpMethod() == "POST")
387         m_method = QNetworkAccessManager::PostOperation;
388     else if (r.httpMethod() == "PUT")
389         m_method = QNetworkAccessManager::PutOperation;
390     else if (r.httpMethod() == "DELETE")
391         m_method = QNetworkAccessManager::DeleteOperation;
392     else
393         m_method = QNetworkAccessManager::CustomOperation;
394 
395     QObject* originatingObject = 0;
396     if (m_resourceHandle->getInternal()->m_context)
397         originatingObject = m_resourceHandle->getInternal()->m_context->originatingObject();
398 
399     m_request = r.toNetworkRequest(originatingObject);
400 
401     m_queue.push(&QNetworkReplyHandler::start);
402 }
403 
abort()404 void QNetworkReplyHandler::abort()
405 {
406     m_resourceHandle = 0;
407     if (QNetworkReply* reply = release()) {
408         reply->abort();
409         reply->deleteLater();
410     }
411     deleteLater();
412 }
413 
release()414 QNetworkReply* QNetworkReplyHandler::release()
415 {
416     if (!m_replyWrapper)
417         return 0;
418 
419     QNetworkReply* reply = m_replyWrapper->release();
420     m_replyWrapper = nullptr;
421     return reply;
422 }
423 
shouldIgnoreHttpError(QNetworkReply * reply,bool receivedData)424 static bool shouldIgnoreHttpError(QNetworkReply* reply, bool receivedData)
425 {
426     int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
427 
428     if (httpStatusCode == 401 || httpStatusCode == 407)
429         return true;
430 
431     if (receivedData && (httpStatusCode >= 400 && httpStatusCode < 600))
432         return true;
433 
434     return false;
435 }
436 
finish()437 void QNetworkReplyHandler::finish()
438 {
439     ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());
440 
441     ResourceHandleClient* client = m_resourceHandle->client();
442     if (!client) {
443         m_replyWrapper = nullptr;
444         return;
445     }
446 
447     if (m_replyWrapper->wasRedirected()) {
448         m_replyWrapper = nullptr;
449         m_queue.push(&QNetworkReplyHandler::start);
450         return;
451     }
452 
453     if (!m_replyWrapper->reply()->error() || shouldIgnoreHttpError(m_replyWrapper->reply(), m_replyWrapper->responseContainsData()))
454         client->didFinishLoading(m_resourceHandle, 0);
455     else {
456         QUrl url = m_replyWrapper->reply()->url();
457         int httpStatusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
458 
459         if (httpStatusCode) {
460             ResourceError error("HTTP", httpStatusCode, url.toString(), m_replyWrapper->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString());
461             client->didFail(m_resourceHandle, error);
462         } else {
463             ResourceError error("QtNetwork", m_replyWrapper->reply()->error(), url.toString(), m_replyWrapper->reply()->errorString());
464             client->didFail(m_resourceHandle, error);
465         }
466     }
467 
468     m_replyWrapper = nullptr;
469 }
470 
sendResponseIfNeeded()471 void QNetworkReplyHandler::sendResponseIfNeeded()
472 {
473     ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());
474 
475     if (m_replyWrapper->reply()->error() && m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).isNull())
476         return;
477 
478     ResourceHandleClient* client = m_resourceHandle->client();
479     if (!client)
480         return;
481 
482     WTF::String mimeType = m_replyWrapper->mimeType();
483 
484     if (mimeType.isEmpty()) {
485         // let's try to guess from the extension
486         mimeType = MIMETypeRegistry::getMIMETypeForPath(m_replyWrapper->reply()->url().path());
487     }
488 
489     KURL url(m_replyWrapper->reply()->url());
490     ResourceResponse response(url, mimeType.lower(),
491                               m_replyWrapper->reply()->header(QNetworkRequest::ContentLengthHeader).toLongLong(),
492                               m_replyWrapper->encoding(), String());
493 
494     if (url.isLocalFile()) {
495         client->didReceiveResponse(m_resourceHandle, response);
496         return;
497     }
498 
499     // The status code is equal to 0 for protocols not in the HTTP family.
500     int statusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
501 
502     if (url.protocolInHTTPFamily()) {
503         String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromLatin1(m_replyWrapper->reply()->rawHeader("Content-Disposition")));
504 
505         if (!suggestedFilename.isEmpty())
506             response.setSuggestedFilename(suggestedFilename);
507         else
508             response.setSuggestedFilename(url.lastPathComponent());
509 
510         response.setHTTPStatusCode(statusCode);
511         response.setHTTPStatusText(m_replyWrapper->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData());
512 
513         // Add remaining headers.
514         foreach (const QNetworkReply::RawHeaderPair& pair, m_replyWrapper->reply()->rawHeaderPairs())
515             response.setHTTPHeaderField(QString::fromLatin1(pair.first), QString::fromLatin1(pair.second));
516     }
517 
518     QUrl redirection = m_replyWrapper->reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
519     if (redirection.isValid()) {
520         redirect(response, redirection);
521         return;
522     }
523 
524     client->didReceiveResponse(m_resourceHandle, response);
525 }
526 
redirect(ResourceResponse & response,const QUrl & redirection)527 void QNetworkReplyHandler::redirect(ResourceResponse& response, const QUrl& redirection)
528 {
529     QUrl newUrl = m_replyWrapper->reply()->url().resolved(redirection);
530 
531     ResourceHandleClient* client = m_resourceHandle->client();
532     ASSERT(client);
533 
534     int statusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
535 
536     m_redirectionTries--;
537     if (!m_redirectionTries) {
538         ResourceError error(newUrl.host(), 400 /*bad request*/,
539                             newUrl.toString(),
540                             QCoreApplication::translate("QWebPage", "Redirection limit reached"));
541         client->didFail(m_resourceHandle, error);
542         m_replyWrapper = nullptr;
543         return;
544     }
545 
546     //  Status Code 301 (Moved Permanently), 302 (Moved Temporarily), 303 (See Other):
547     //    - If original request is POST convert to GET and redirect automatically
548     //  Status Code 307 (Temporary Redirect) and all other redirect status codes:
549     //    - Use the HTTP method from the previous request
550     if ((statusCode >= 301 && statusCode <= 303) && m_resourceHandle->firstRequest().httpMethod() == "POST")
551         m_method = QNetworkAccessManager::GetOperation;
552 
553     ResourceRequest newRequest = m_resourceHandle->firstRequest();
554     newRequest.setHTTPMethod(httpMethod());
555     newRequest.setURL(newUrl);
556 
557     // Should not set Referer after a redirect from a secure resource to non-secure one.
558     if (!newRequest.url().protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https"))
559         newRequest.clearHTTPReferrer();
560 
561     client->willSendRequest(m_resourceHandle, newRequest, response);
562     if (wasAborted()) // Network error cancelled the request.
563         return;
564 
565     QObject* originatingObject = 0;
566     if (m_resourceHandle->getInternal()->m_context)
567         originatingObject = m_resourceHandle->getInternal()->m_context->originatingObject();
568 
569     m_request = newRequest.toNetworkRequest(originatingObject);
570 }
571 
forwardData()572 void QNetworkReplyHandler::forwardData()
573 {
574     ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted() && !m_replyWrapper->wasRedirected());
575 
576     QByteArray data = m_replyWrapper->reply()->read(m_replyWrapper->reply()->bytesAvailable());
577 
578     ResourceHandleClient* client = m_resourceHandle->client();
579     if (!client)
580         return;
581 
582     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793
583     // -1 means we do not provide any data about transfer size to inspector so it would use
584     // Content-Length headers or content size to show transfer size.
585     if (!data.isEmpty())
586         client->didReceiveData(m_resourceHandle, data.constData(), data.length(), -1);
587 }
588 
uploadProgress(qint64 bytesSent,qint64 bytesTotal)589 void QNetworkReplyHandler::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
590 {
591     if (wasAborted())
592         return;
593 
594     ResourceHandleClient* client = m_resourceHandle->client();
595     if (!client)
596         return;
597 
598     client->didSendData(m_resourceHandle, bytesSent, bytesTotal);
599 }
600 
sendNetworkRequest(QNetworkAccessManager * manager,const ResourceRequest & request)601 QNetworkReply* QNetworkReplyHandler::sendNetworkRequest(QNetworkAccessManager* manager, const ResourceRequest& request)
602 {
603     if (m_loadType == SynchronousLoad)
604         m_request.setAttribute(gSynchronousNetworkRequestAttribute, true);
605 
606     if (!manager)
607         return 0;
608 
609     const QUrl url = m_request.url();
610     const QString scheme = url.scheme();
611     // Post requests on files and data don't really make sense, but for
612     // fast/forms/form-post-urlencoded.html and for fast/forms/button-state-restore.html
613     // we still need to retrieve the file/data, which means we map it to a Get instead.
614     if (m_method == QNetworkAccessManager::PostOperation
615         && (!url.toLocalFile().isEmpty() || url.scheme() == QLatin1String("data")))
616         m_method = QNetworkAccessManager::GetOperation;
617 
618     if (m_method != QNetworkAccessManager::PostOperation && m_method != QNetworkAccessManager::PutOperation) {
619         // clearing Contents-length and Contents-type of the requests that do not have contents.
620         m_request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
621         m_request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
622     }
623 
624     switch (m_method) {
625         case QNetworkAccessManager::GetOperation:
626             return manager->get(m_request);
627         case QNetworkAccessManager::PostOperation: {
628             FormDataIODevice* postDevice = new FormDataIODevice(request.httpBody());
629             // We may be uploading files so prevent QNR from buffering data
630             m_request.setHeader(QNetworkRequest::ContentLengthHeader, postDevice->getFormDataSize());
631             m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true));
632             QNetworkReply* result = manager->post(m_request, postDevice);
633             postDevice->setParent(result);
634             return result;
635         }
636         case QNetworkAccessManager::HeadOperation:
637             return manager->head(m_request);
638         case QNetworkAccessManager::PutOperation: {
639             FormDataIODevice* putDevice = new FormDataIODevice(request.httpBody());
640             // We may be uploading files so prevent QNR from buffering data
641             m_request.setHeader(QNetworkRequest::ContentLengthHeader, putDevice->getFormDataSize());
642             m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true));
643             QNetworkReply* result = manager->put(m_request, putDevice);
644             putDevice->setParent(result);
645             return result;
646         }
647         case QNetworkAccessManager::DeleteOperation: {
648             return manager->deleteResource(m_request);
649         }
650         case QNetworkAccessManager::CustomOperation:
651             return manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data());
652         case QNetworkAccessManager::UnknownOperation:
653             ASSERT_NOT_REACHED();
654             return 0;
655     }
656     return 0;
657 }
658 
start()659 void QNetworkReplyHandler::start()
660 {
661     ResourceHandleInternal* d = m_resourceHandle->getInternal();
662     if (!d || !d->m_context)
663         return;
664 
665     QNetworkReply* reply = sendNetworkRequest(d->m_context->networkAccessManager(), d->m_firstRequest);
666     if (!reply)
667         return;
668 
669     m_replyWrapper = adoptPtr(new QNetworkReplyWrapper(&m_queue, reply, m_resourceHandle->shouldContentSniff() && d->m_context->mimeSniffingEnabled(), this));
670 
671     if (m_loadType == SynchronousLoad) {
672         m_replyWrapper->synchronousLoad();
673         // If supported, a synchronous request will be finished at this point, no need to hook up the signals.
674         return;
675     }
676 
677     if (m_resourceHandle->firstRequest().reportUploadProgress())
678         connect(m_replyWrapper->reply(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)));
679 }
680 
681 }
682 
683 #include "moc_QNetworkReplyHandler.cpp"
684