1/* 2 Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 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#ifndef QNetworkReplyHandler_h 20#define QNetworkReplyHandler_h 21 22#include <QObject> 23 24#include <QNetworkAccessManager> 25#include <QNetworkReply> 26#include <QNetworkRequest> 27#include <QBasicTimer> 28 29#include "FormData.h" 30#include "QtMIMETypeSniffer.h" 31 32QT_BEGIN_NAMESPACE 33class QFile; 34class QNetworkReply; 35QT_END_NAMESPACE 36 37namespace WebCore { 38 39class FormDataIODevice; 40class ResourceError; 41class ResourceHandle; 42class ResourceRequest; 43class ResourceResponse; 44class QNetworkReplyHandler; 45 46class QNetworkReplyHandlerCallQueue : public QObject { 47 Q_OBJECT 48public: 49 QNetworkReplyHandlerCallQueue(QNetworkReplyHandler*, bool deferSignals); 50 bool deferSignals() const { return m_deferSignals; } 51 void setDeferSignals(bool, bool sync = false); 52 53 typedef void (QNetworkReplyHandler::*EnqueuedCall)(); 54 void push(EnqueuedCall method); 55 void clear() { m_enqueuedCalls.clear(); } 56 57 void lock(); 58 void unlock(); 59private: 60 QNetworkReplyHandler* m_replyHandler; 61 int m_locks; 62 bool m_deferSignals; 63 bool m_flushing; 64 QList<EnqueuedCall> m_enqueuedCalls; 65 66 Q_INVOKABLE void flush(); 67}; 68 69class QNetworkReplyWrapper : public QObject { 70 Q_OBJECT 71public: 72 QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue*, QNetworkReply*, bool sniffMIMETypes, QObject* parent = 0); 73 ~QNetworkReplyWrapper(); 74 75 QNetworkReply* reply() const { return m_reply; } 76 QNetworkReply* release(); 77 78 void synchronousLoad(); 79 80 QUrl redirectionTargetUrl() const { return m_redirectionTargetUrl; } 81 QString encoding() const { return m_encoding; } 82 QString advertisedMIMEType() const { return m_advertisedMIMEType; } 83 QString mimeType() const { return m_sniffedMIMEType.isEmpty() ? m_advertisedMIMEType : m_sniffedMIMEType; } 84 85 bool responseContainsData() const { return m_responseContainsData; } 86 bool wasRedirected() const { return m_redirectionTargetUrl.isValid(); } 87 88 // See setFinished(). 89 bool isFinished() const { return m_reply->property("_q_isFinished").toBool(); } 90 91private Q_SLOTS: 92 void receiveMetaData(); 93 void didReceiveFinished(); 94 void didReceiveReadyRead(); 95 void receiveSniffedMIMEType(); 96 void setFinished(); 97 void replyDestroyed(); 98 99private: 100 void stopForwarding(); 101 void emitMetaDataChanged(); 102 103 QNetworkReply* m_reply; 104 QUrl m_redirectionTargetUrl; 105 106 QString m_encoding; 107 QNetworkReplyHandlerCallQueue* m_queue; 108 bool m_responseContainsData; 109 110 QString m_advertisedMIMEType; 111 112 QString m_sniffedMIMEType; 113 OwnPtr<QtMIMETypeSniffer> m_sniffer; 114 bool m_sniffMIMETypes; 115}; 116 117class QNetworkReplyHandler : public QObject 118{ 119 Q_OBJECT 120public: 121 enum LoadType { 122 AsynchronousLoad, 123 SynchronousLoad 124 }; 125 126 QNetworkReplyHandler(ResourceHandle*, LoadType, bool deferred = false); 127 void setLoadingDeferred(bool deferred) { m_queue.setDeferSignals(deferred, m_loadType == SynchronousLoad); } 128 129 QNetworkReply* reply() const { return m_replyWrapper ? m_replyWrapper->reply() : 0; } 130 131 void abort(); 132 133 QNetworkReply* release(); 134 135 void finish(); 136 void forwardData(); 137 void sendResponseIfNeeded(); 138 139 static ResourceError errorForReply(QNetworkReply*); 140 141private Q_SLOTS: 142 void uploadProgress(qint64 bytesSent, qint64 bytesTotal); 143 144private: 145 void start(); 146 String httpMethod() const; 147 void redirect(ResourceResponse&, const QUrl&); 148 bool wasAborted() const { return !m_resourceHandle; } 149 QNetworkReply* sendNetworkRequest(QNetworkAccessManager*, const ResourceRequest&); 150 FormDataIODevice* getIODevice(const ResourceRequest&); 151 void clearContentHeaders(); 152 virtual void timerEvent(QTimerEvent*) OVERRIDE; 153 void timeout(); 154 155 OwnPtr<QNetworkReplyWrapper> m_replyWrapper; 156 ResourceHandle* m_resourceHandle; 157 LoadType m_loadType; 158 QNetworkAccessManager::Operation m_method; 159 QNetworkRequest m_request; 160 QBasicTimer m_timeoutTimer; 161 162 // defer state holding 163 int m_redirectionTries; 164 165 QNetworkReplyHandlerCallQueue m_queue; 166}; 167 168// Self destructing QIODevice for FormData 169// For QNetworkAccessManager::put we will have to gurantee that the 170// QIODevice is valid as long finished() of the QNetworkReply has not 171// been emitted. With the presence of QNetworkReplyHandler::release I do 172// not want to gurantee this. 173class FormDataIODevice : public QIODevice { 174 Q_OBJECT 175public: 176 FormDataIODevice(FormData*); 177 ~FormDataIODevice(); 178 179 bool isSequential() const; 180 qint64 getFormDataSize() const { return m_fileSize + m_dataSize; } 181 182protected: 183 qint64 readData(char*, qint64); 184 qint64 writeData(const char*, qint64); 185 186private: 187 void prepareFormElements(FormData*); 188 void moveToNextElement(); 189 qint64 computeSize(); 190 void openFileForCurrentElement(); 191 void prepareCurrentElement(); 192 193private: 194 Vector<FormDataElement> m_formElements; 195 QFile* m_currentFile; 196 qint64 m_currentDelta; 197 qint64 m_fileSize; 198 qint64 m_dataSize; 199}; 200 201} 202 203#endif // QNetworkReplyHandler_h 204