1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qhttpnetworkrequest_p.h"
43 #include "private/qnoncontiguousbytedevice_p.h"
44 
45 #ifndef QT_NO_HTTP
46 
47 QT_BEGIN_NAMESPACE
48 
QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op,QHttpNetworkRequest::Priority pri,const QUrl & newUrl)49 QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op,
50         QHttpNetworkRequest::Priority pri, const QUrl &newUrl)
51     : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0),
52       autoDecompress(false), pipeliningAllowed(false), withCredentials(true)
53 {
54 }
55 
QHttpNetworkRequestPrivate(const QHttpNetworkRequestPrivate & other)56 QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequestPrivate &other)
57     : QHttpNetworkHeaderPrivate(other)
58 {
59     operation = other.operation;
60     priority = other.priority;
61     uploadByteDevice = other.uploadByteDevice;
62     autoDecompress = other.autoDecompress;
63     pipeliningAllowed = other.pipeliningAllowed;
64     customVerb = other.customVerb;
65     withCredentials = other.withCredentials;
66     ssl = other.ssl;
67 }
68 
~QHttpNetworkRequestPrivate()69 QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate()
70 {
71 }
72 
operator ==(const QHttpNetworkRequestPrivate & other) const73 bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &other) const
74 {
75     return QHttpNetworkHeaderPrivate::operator==(other)
76         && (operation == other.operation)
77         && (ssl == other.ssl)
78         && (uploadByteDevice == other.uploadByteDevice);
79 }
80 
methodName() const81 QByteArray QHttpNetworkRequestPrivate::methodName() const
82 {
83     switch (operation) {
84     case QHttpNetworkRequest::Get:
85         return "GET";
86         break;
87     case QHttpNetworkRequest::Head:
88         return "HEAD";
89         break;
90     case QHttpNetworkRequest::Post:
91         return "POST";
92         break;
93     case QHttpNetworkRequest::Options:
94         return "OPTIONS";
95         break;
96     case QHttpNetworkRequest::Put:
97         return "PUT";
98         break;
99     case QHttpNetworkRequest::Delete:
100         return "DELETE";
101         break;
102     case QHttpNetworkRequest::Trace:
103         return "TRACE";
104         break;
105     case QHttpNetworkRequest::Connect:
106         return "CONNECT";
107         break;
108     case QHttpNetworkRequest::Custom:
109         return customVerb;
110         break;
111     default:
112         break;
113     }
114     return QByteArray();
115 }
116 
uri(bool throughProxy) const117 QByteArray QHttpNetworkRequestPrivate::uri(bool throughProxy) const
118 {
119     QUrl::FormattingOptions format(QUrl::RemoveFragment);
120 
121     // for POST, query data is send as content
122     if (operation == QHttpNetworkRequest::Post && !uploadByteDevice)
123         format |= QUrl::RemoveQuery;
124     // for requests through proxy, the Request-URI contains full url
125     if (throughProxy)
126         format |= QUrl::RemoveUserInfo;
127     else
128         format |= QUrl::RemoveScheme | QUrl::RemoveAuthority;
129     QByteArray uri = url.toEncoded(format);
130     if (uri.isEmpty() || (throughProxy && url.path().isEmpty()))
131         uri += '/';
132     return uri;
133 }
134 
header(const QHttpNetworkRequest & request,bool throughProxy)135 QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request, bool throughProxy)
136 {
137     QList<QPair<QByteArray, QByteArray> > fields = request.header();
138     QByteArray ba;
139     ba.reserve(40 + fields.length()*25); // very rough lower bound estimation
140 
141     ba += request.d->methodName();
142     ba += ' ';
143     ba += request.d->uri(throughProxy);
144 
145     ba += " HTTP/";
146     ba += QByteArray::number(request.majorVersion());
147     ba += '.';
148     ba += QByteArray::number(request.minorVersion());
149     ba += "\r\n";
150 
151     QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
152     QList<QPair<QByteArray, QByteArray> >::const_iterator endIt = fields.constEnd();
153     for (; it != endIt; ++it) {
154         ba += it->first;
155         ba += ": ";
156         ba += it->second;
157         ba += "\r\n";
158     }
159     if (request.d->operation == QHttpNetworkRequest::Post) {
160         // add content type, if not set in the request
161         if (request.headerField("content-type").isEmpty()) {
162             //Content-Type is mandatory. We can't say anything about the encoding, but x-www-form-urlencoded is the most likely to work.
163             //This warning indicates a bug in application code not setting a required header.
164             //Note that if using QHttpMultipart, the content-type is set in QNetworkAccessManagerPrivate::prepareMultipart already
165             qWarning("content-type missing in HTTP POST, defaulting to application/x-www-form-urlencoded. Use QNetworkRequest::setHeader() to fix this problem.");
166             ba += "Content-Type: application/x-www-form-urlencoded\r\n";
167         }
168         if (!request.d->uploadByteDevice && request.d->url.hasQuery()) {
169             QByteArray query = request.d->url.encodedQuery();
170             ba += "Content-Length: ";
171             ba += QByteArray::number(query.size());
172             ba += "\r\n\r\n";
173             ba += query;
174         } else {
175             ba += "\r\n";
176         }
177     } else {
178         ba += "\r\n";
179     }
180      return ba;
181 }
182 
183 
184 // QHttpNetworkRequest
185 
QHttpNetworkRequest(const QUrl & url,Operation operation,Priority priority)186 QHttpNetworkRequest::QHttpNetworkRequest(const QUrl &url, Operation operation, Priority priority)
187     : d(new QHttpNetworkRequestPrivate(operation, priority, url))
188 {
189 }
190 
QHttpNetworkRequest(const QHttpNetworkRequest & other)191 QHttpNetworkRequest::QHttpNetworkRequest(const QHttpNetworkRequest &other)
192     : QHttpNetworkHeader(other), d(other.d)
193 {
194 }
195 
~QHttpNetworkRequest()196 QHttpNetworkRequest::~QHttpNetworkRequest()
197 {
198 }
199 
url() const200 QUrl QHttpNetworkRequest::url() const
201 {
202     return d->url;
203 }
setUrl(const QUrl & url)204 void QHttpNetworkRequest::setUrl(const QUrl &url)
205 {
206     d->url = url;
207 }
208 
isSsl() const209 bool QHttpNetworkRequest::isSsl() const
210 {
211     return d->ssl;
212 }
setSsl(bool s)213 void QHttpNetworkRequest::setSsl(bool s)
214 {
215     d->ssl = s;
216 }
217 
contentLength() const218 qint64 QHttpNetworkRequest::contentLength() const
219 {
220     return d->contentLength();
221 }
222 
setContentLength(qint64 length)223 void QHttpNetworkRequest::setContentLength(qint64 length)
224 {
225     d->setContentLength(length);
226 }
227 
header() const228 QList<QPair<QByteArray, QByteArray> > QHttpNetworkRequest::header() const
229 {
230     return d->fields;
231 }
232 
headerField(const QByteArray & name,const QByteArray & defaultValue) const233 QByteArray QHttpNetworkRequest::headerField(const QByteArray &name, const QByteArray &defaultValue) const
234 {
235     return d->headerField(name, defaultValue);
236 }
237 
setHeaderField(const QByteArray & name,const QByteArray & data)238 void QHttpNetworkRequest::setHeaderField(const QByteArray &name, const QByteArray &data)
239 {
240     d->setHeaderField(name, data);
241 }
242 
operator =(const QHttpNetworkRequest & other)243 QHttpNetworkRequest &QHttpNetworkRequest::operator=(const QHttpNetworkRequest &other)
244 {
245     d = other.d;
246     return *this;
247 }
248 
operator ==(const QHttpNetworkRequest & other) const249 bool QHttpNetworkRequest::operator==(const QHttpNetworkRequest &other) const
250 {
251     return d->operator==(*other.d);
252 }
253 
operation() const254 QHttpNetworkRequest::Operation QHttpNetworkRequest::operation() const
255 {
256     return d->operation;
257 }
258 
setOperation(Operation operation)259 void QHttpNetworkRequest::setOperation(Operation operation)
260 {
261     d->operation = operation;
262 }
263 
customVerb() const264 QByteArray QHttpNetworkRequest::customVerb() const
265 {
266     return d->customVerb;
267 }
268 
setCustomVerb(const QByteArray & customVerb)269 void QHttpNetworkRequest::setCustomVerb(const QByteArray &customVerb)
270 {
271     d->customVerb = customVerb;
272 }
273 
priority() const274 QHttpNetworkRequest::Priority QHttpNetworkRequest::priority() const
275 {
276     return d->priority;
277 }
278 
setPriority(Priority priority)279 void QHttpNetworkRequest::setPriority(Priority priority)
280 {
281     d->priority = priority;
282 }
283 
isPipeliningAllowed() const284 bool QHttpNetworkRequest::isPipeliningAllowed() const
285 {
286     return d->pipeliningAllowed;
287 }
288 
setPipeliningAllowed(bool b)289 void QHttpNetworkRequest::setPipeliningAllowed(bool b)
290 {
291     d->pipeliningAllowed = b;
292 }
293 
withCredentials() const294 bool QHttpNetworkRequest::withCredentials() const
295 {
296     return d->withCredentials;
297 }
298 
setWithCredentials(bool b)299 void QHttpNetworkRequest::setWithCredentials(bool b)
300 {
301     d->withCredentials = b;
302 }
303 
setUploadByteDevice(QNonContiguousByteDevice * bd)304 void QHttpNetworkRequest::setUploadByteDevice(QNonContiguousByteDevice *bd)
305 {
306     d->uploadByteDevice = bd;
307 }
308 
uploadByteDevice() const309 QNonContiguousByteDevice* QHttpNetworkRequest::uploadByteDevice() const
310 {
311     return d->uploadByteDevice;
312 }
313 
majorVersion() const314 int QHttpNetworkRequest::majorVersion() const
315 {
316     return 1;
317 }
318 
minorVersion() const319 int QHttpNetworkRequest::minorVersion() const
320 {
321     return 1;
322 }
323 
324 
325 QT_END_NAMESPACE
326 
327 #endif
328 
329