1 /* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
2  * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
3 
4 #ifndef __ARTICLE_NETMGR_HH_INCLUDED__
5 #define __ARTICLE_NETMGR_HH_INCLUDED__
6 
7 #include <QtNetwork>
8 
9 #if QT_VERSION >= 0x050300  // Qt 5.3+
10 #include <QWebSecurityOrigin>
11 #include <QSet>
12 #include <QMap>
13 #include <QPair>
14 #endif
15 
16 #include "dictionary.hh"
17 #include "article_maker.hh"
18 
19 using std::vector;
20 
21 /// A custom QNetworkAccessManager version which fetches images from the
22 /// dictionaries when requested.
23 
24 #if QT_VERSION >= 0x050300  // Qt 5.3+
25 
26 // White lists for QWebSecurityOrigin
27 struct SecurityWhiteList
28 {
29   QWebSecurityOrigin * origin;
30   QString originUri;
31   QSet< QPair< QString, QString > > hostsToAccess;
32 
SecurityWhiteListSecurityWhiteList33   SecurityWhiteList() :
34     origin( 0 )
35   {}
36 
~SecurityWhiteListSecurityWhiteList37   ~SecurityWhiteList()
38   { swlDelete(); }
39 
SecurityWhiteListSecurityWhiteList40   SecurityWhiteList( SecurityWhiteList const & swl ) :
41     origin( 0 )
42   { swlCopy( swl ); }
43 
44   SecurityWhiteList & operator=( SecurityWhiteList const & swl );
45   QWebSecurityOrigin * setOrigin( QUrl const & url );
46 
47 private:
48   void swlCopy( SecurityWhiteList const & swl );
49   void swlDelete();
50 };
51 
52 typedef QMap< QString, SecurityWhiteList > Origins;
53 
54 // Proxy class for QNetworkReply to remove X-Frame-Options header
55 // It allow to show websites in <iframe> tag like Qt 4.x
56 
57 class AllowFrameReply : public QNetworkReply
58 {
59   Q_OBJECT
60 private:
61   QNetworkReply * baseReply;
62   QByteArray buffer;
63 
64   AllowFrameReply();
65   AllowFrameReply( AllowFrameReply const & );
66 
67 public:
68   explicit AllowFrameReply( QNetworkReply * _reply );
~AllowFrameReply()69   ~AllowFrameReply()
70   { delete baseReply; }
71 
72   // QNetworkReply virtual functions
73   void setReadBufferSize( qint64 size );
close()74   void close()
75   { baseReply->close(); }
76 
77   // QIODevice virtual functions
78   qint64 bytesAvailable() const;
atEnd() const79   bool atEnd() const
80   { return baseReply->atEnd(); }
bytesToWrite() const81   qint64 bytesToWrite() const
82   { return baseReply->bytesToWrite(); }
canReadLine() const83   bool canReadLine() const
84   { return baseReply->canReadLine(); }
isSequential() const85   bool isSequential() const
86   { return baseReply->isSequential(); }
waitForReadyRead(int msecs)87   bool waitForReadyRead( int msecs )
88   { return baseReply->waitForReadyRead( msecs ); }
waitForBytesWritten(int msecs)89   bool waitForBytesWritten( int msecs )
90   { return baseReply->waitForBytesWritten( msecs ); }
reset()91   bool reset()
92   { return baseReply->reset(); }
93 
94 public slots:
95 
96   // Own AllowFrameReply slots
97   void applyMetaData();
98   void applyError( QNetworkReply::NetworkError code );
99   void readDataFromBase();
100 
101   // Redirect QNetworkReply slots
abort()102   virtual void abort()
103   { baseReply->abort(); }
ignoreSslErrors()104   virtual void ignoreSslErrors()
105   { baseReply->ignoreSslErrors(); }
106 
107 protected:
108   // QNetworkReply virtual functions
ignoreSslErrorsImplementation(const QList<QSslError> & errors)109   void ignoreSslErrorsImplementation( const QList< QSslError > & errors )
110   { baseReply->ignoreSslErrors( errors ); }
setSslConfigurationImplementation(const QSslConfiguration & configuration)111   void setSslConfigurationImplementation( const QSslConfiguration & configuration )
112   { baseReply->setSslConfiguration( configuration ); }
sslConfigurationImplementation(QSslConfiguration & configuration) const113   void sslConfigurationImplementation( QSslConfiguration & configuration ) const
114   { configuration = baseReply->sslConfiguration(); }
115 
116   // QIODevice virtual functions
117   qint64 readData( char * data, qint64 maxSize );
readLineData(char * data,qint64 maxSize)118   qint64 readLineData( char * data, qint64 maxSize )
119   { return baseReply->readLine( data, maxSize ); }
writeData(const char * data,qint64 maxSize)120   qint64 writeData( const char * data, qint64 maxSize )
121   { return baseReply->write( data, maxSize ); }
122 };
123 #endif
124 
125 class ArticleNetworkAccessManager: public QNetworkAccessManager
126 {
127   vector< sptr< Dictionary::Class > > const & dictionaries;
128   ArticleMaker const & articleMaker;
129   bool const & disallowContentFromOtherSites;
130   bool const & hideGoldenDictHeader;
131 #if QT_VERSION >= 0x050300  // Qt 5.3+
132   Origins allOrigins;
133 #endif
134 public:
135 
ArticleNetworkAccessManager(QObject * parent,vector<sptr<Dictionary::Class>> const & dictionaries_,ArticleMaker const & articleMaker_,bool const & disallowContentFromOtherSites_,bool const & hideGoldenDictHeader_)136   ArticleNetworkAccessManager( QObject * parent,
137                                vector< sptr< Dictionary::Class > > const &
138                                dictionaries_,
139                                ArticleMaker const & articleMaker_,
140                                bool const & disallowContentFromOtherSites_,
141                                bool const & hideGoldenDictHeader_ ):
142     QNetworkAccessManager( parent ), dictionaries( dictionaries_ ),
143     articleMaker( articleMaker_ ),
144     disallowContentFromOtherSites( disallowContentFromOtherSites_ ),
145     hideGoldenDictHeader( hideGoldenDictHeader_ )
146   {}
147 
148   /// Tries handling any kind of internal resources referenced by dictionaries.
149   /// If it succeeds, the result is a dictionary request object. Otherwise, an
150   /// empty pointer is returned.
151   /// The function can optionally set the Content-Type header correspondingly.
152   sptr< Dictionary::DataRequest > getResource( QUrl const & url,
153                                                QString & contentType );
154 
155 protected:
156 
157   virtual QNetworkReply * createRequest( Operation op,
158                                          QNetworkRequest const & req,
159                                          QIODevice * outgoingData );
160 };
161 
162 class ArticleResourceReply: public QNetworkReply
163 {
164   Q_OBJECT
165 
166   sptr< Dictionary::DataRequest > req;
167   qint64 alreadyRead;
168 
169 public:
170 
171   ArticleResourceReply( QObject * parent,
172                         QNetworkRequest const &,
173                         sptr< Dictionary::DataRequest > const &,
174                         QString const & contentType );
175 
176   ~ArticleResourceReply();
177 
178 protected:
179 
180   virtual qint64 bytesAvailable() const;
181 
abort()182   virtual void abort()
183   {}
184   virtual qint64 readData( char * data, qint64 maxSize );
185 
186   // We use the hackery below to work around the fact that we need to emit
187   // ready/finish signals after we've been constructed.
188 signals:
189 
190   void readyReadSignal();
191   void finishedSignal();
192 
193 private slots:
194 
195   void reqUpdated();
196   void reqFinished();
197 
198   void readyReadSlot();
199   void finishedSlot();
200 };
201 
202 class BlockedNetworkReply: public QNetworkReply
203 {
204   Q_OBJECT
205 
206 public:
207 
208   BlockedNetworkReply( QObject * parent );
209 
readData(char *,qint64)210   virtual qint64 readData( char *, qint64 )
211   {
212     return -1;
213   }
214 
abort()215   virtual void abort()
216   {}
217 
218 protected:
219 
220   // We use the hackery below to work around the fact that we need to emit
221   // ready/finish signals after we've been constructed.
222 
223 signals:
224 
225   void finishedSignal();
226 
227 private slots:
228 
229   void finishedSlot();
230 };
231 
232 #endif
233