Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qhttpnetworkreply.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:critical reason:network-protocol
4
5
#
include
"qhttpnetworkreply_p.h"
6
#
include
"qhttpnetworkconnection_p.h"
7
8
#
ifndef
QT_NO_SSL
9
#
include
<
QtNetwork
/
qsslkey
.
h
>
10
#
include
<
QtNetwork
/
qsslcipher
.
h
>
11
#
include
<
QtNetwork
/
qsslconfiguration
.
h
>
12
#
endif
13
14
#
include
<
private
/
qdecompresshelper_p
.
h
>
15
16
QT_BEGIN_NAMESPACE
17
18
using
namespace
Qt::StringLiterals;
19
20
QHttpNetworkReply::QHttpNetworkReply(
const
QUrl &url, QObject *parent)
21
: QObject(*
new
QHttpNetworkReplyPrivate(url), parent)
22
{
23
}
24
25
QHttpNetworkReply::~QHttpNetworkReply()
26
{
27
Q_D(QHttpNetworkReply);
28
if
(d->connection) {
29
d->connection->d_func()->removeReply(
this
);
30
}
31
}
32
33
QUrl QHttpNetworkReply::url()
const
34
{
35
return
d_func()->url;
36
}
37
void
QHttpNetworkReply::setUrl(
const
QUrl &url)
38
{
39
Q_D(QHttpNetworkReply);
40
d->url = url;
41
}
42
43
QUrl QHttpNetworkReply::redirectUrl()
const
44
{
45
return
d_func()->redirectUrl;
46
}
47
48
void
QHttpNetworkReply::setRedirectUrl(
const
QUrl &url)
49
{
50
Q_D(QHttpNetworkReply);
51
d->redirectUrl = url;
52
}
53
54
bool
QHttpNetworkReply::isHttpRedirect(
int
statusCode)
55
{
56
return
(statusCode == 301 || statusCode == 302 || statusCode == 303
57
|| statusCode == 305 || statusCode == 307 || statusCode == 308);
58
}
59
60
qint64 QHttpNetworkReply::contentLength()
const
61
{
62
return
d_func()->contentLength();
63
}
64
65
void
QHttpNetworkReply::setContentLength(qint64 length)
66
{
67
Q_D(QHttpNetworkReply);
68
d->setContentLength(length);
69
}
70
71
QHttpHeaders QHttpNetworkReply::header()
const
72
{
73
return
d_func()->parser.headers();
74
}
75
76
QByteArray QHttpNetworkReply::headerField(QByteArrayView name,
const
QByteArray &defaultValue)
const
77
{
78
return
d_func()->headerField(name, defaultValue);
79
}
80
81
void
QHttpNetworkReply::setHeaderField(
const
QByteArray &name,
const
QByteArray &data)
82
{
83
Q_D(QHttpNetworkReply);
84
d->setHeaderField(name, data);
85
}
86
87
void
QHttpNetworkReply::appendHeaderField(
const
QByteArray &name,
const
QByteArray &data)
88
{
89
Q_D(QHttpNetworkReply);
90
d->appendHeaderField(name, data);
91
}
92
93
void
QHttpNetworkReply::parseHeader(QByteArrayView header)
94
{
95
Q_D(QHttpNetworkReply);
96
d->parseHeader(header);
97
}
98
99
QHttpNetworkRequest QHttpNetworkReply::request()
const
100
{
101
return
d_func()->request;
102
}
103
104
void
QHttpNetworkReply::setRequest(
const
QHttpNetworkRequest &request)
105
{
106
Q_D(QHttpNetworkReply);
107
d->request = request;
108
d->ssl = request.isSsl();
109
}
110
111
int
QHttpNetworkReply::statusCode()
const
112
{
113
return
d_func()->parser.getStatusCode();
114
}
115
116
void
QHttpNetworkReply::setStatusCode(
int
code)
117
{
118
Q_D(QHttpNetworkReply);
119
d->parser.setStatusCode(code);
120
}
121
122
QString QHttpNetworkReply::errorString()
const
123
{
124
return
d_func()->errorString;
125
}
126
127
QNetworkReply::NetworkError QHttpNetworkReply::errorCode()
const
128
{
129
return
d_func()->httpErrorCode;
130
}
131
132
QString QHttpNetworkReply::reasonPhrase()
const
133
{
134
return
d_func()->parser.getReasonPhrase();
135
}
136
137
void
QHttpNetworkReply::setReasonPhrase(
const
QString &reason)
138
{
139
d_func()->parser.setReasonPhrase(reason);
140
}
141
142
void
QHttpNetworkReply::setErrorString(
const
QString &error)
143
{
144
Q_D(QHttpNetworkReply);
145
d->errorString = error;
146
}
147
148
int
QHttpNetworkReply::majorVersion()
const
149
{
150
return
d_func()->parser.getMajorVersion();
151
}
152
153
int
QHttpNetworkReply::minorVersion()
const
154
{
155
return
d_func()->parser.getMinorVersion();
156
}
157
158
void
QHttpNetworkReply::setMajorVersion(
int
version)
159
{
160
d_func()->parser.setMajorVersion(version);
161
}
162
163
void
QHttpNetworkReply::setMinorVersion(
int
version)
164
{
165
d_func()->parser.setMinorVersion(version);
166
}
167
168
qint64 QHttpNetworkReply::bytesAvailable()
const
169
{
170
Q_D(
const
QHttpNetworkReply);
171
if
(d->connection)
172
return
d->connection->d_func()->uncompressedBytesAvailable(*
this
);
173
else
174
return
-1;
175
}
176
177
qint64 QHttpNetworkReply::bytesAvailableNextBlock()
const
178
{
179
Q_D(
const
QHttpNetworkReply);
180
if
(d->connection)
181
return
d->connection->d_func()->uncompressedBytesAvailableNextBlock(*
this
);
182
else
183
return
-1;
184
}
185
186
bool
QHttpNetworkReply::readAnyAvailable()
const
187
{
188
Q_D(
const
QHttpNetworkReply);
189
return
(d->responseData.bufferCount() > 0);
190
}
191
192
QByteArray QHttpNetworkReply::readAny()
193
{
194
Q_D(QHttpNetworkReply);
195
if
(d->responseData.bufferCount() == 0)
196
return
QByteArray();
197
198
// we'll take the last buffer, so schedule another read from http
199
if
(d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
200
d->connection->d_func()->readMoreLater(
this
);
201
return
d->responseData.read();
202
}
203
204
QByteArray QHttpNetworkReply::readAll()
205
{
206
Q_D(QHttpNetworkReply);
207
return
d->responseData.readAll();
208
}
209
210
QByteArray QHttpNetworkReply::read(qint64 amount)
211
{
212
Q_D(QHttpNetworkReply);
213
return
d->responseData.read(amount);
214
}
215
216
217
qint64 QHttpNetworkReply::sizeNextBlock()
218
{
219
Q_D(QHttpNetworkReply);
220
return
d->responseData.sizeNextBlock();
221
}
222
223
void
QHttpNetworkReply::setDownstreamLimited(
bool
dsl)
224
{
225
Q_D(QHttpNetworkReply);
226
d->downstreamLimited = dsl;
227
d->connection->d_func()->readMoreLater(
this
);
228
}
229
230
void
QHttpNetworkReply::setReadBufferSize(qint64 size)
231
{
232
Q_D(QHttpNetworkReply);
233
d->readBufferMaxSize = size;
234
}
235
236
bool
QHttpNetworkReply::supportsUserProvidedDownloadBuffer()
237
{
238
Q_D(QHttpNetworkReply);
239
return
!d->isChunked() && !d->autoDecompress &&
240
d->bodyLength > 0 && d->parser.getStatusCode() == 200;
241
}
242
243
void
QHttpNetworkReply::setUserProvidedDownloadBuffer(
char
* b)
244
{
245
Q_D(QHttpNetworkReply);
246
if
(supportsUserProvidedDownloadBuffer())
247
d->userProvidedDownloadBuffer = b;
248
}
249
250
char
* QHttpNetworkReply::userProvidedDownloadBuffer()
251
{
252
Q_D(QHttpNetworkReply);
253
return
d->userProvidedDownloadBuffer;
254
}
255
256
void
QHttpNetworkReply::abort()
257
{
258
Q_D(QHttpNetworkReply);
259
d->state = QHttpNetworkReplyPrivate::Aborted;
260
}
261
262
bool
QHttpNetworkReply::isAborted()
const
263
{
264
return
d_func()->state == QHttpNetworkReplyPrivate::Aborted;
265
}
266
267
bool
QHttpNetworkReply::isFinished()
const
268
{
269
return
d_func()->state == QHttpNetworkReplyPrivate::AllDoneState;
270
}
271
272
bool
QHttpNetworkReply::isPipeliningUsed()
const
273
{
274
return
d_func()->pipeliningUsed;
275
}
276
277
bool
QHttpNetworkReply::isHttp2Used()
const
278
{
279
return
d_func()->h2Used;
280
}
281
282
void
QHttpNetworkReply::setHttp2WasUsed(
bool
h2)
283
{
284
d_func()->h2Used = h2;
285
}
286
287
qint64 QHttpNetworkReply::removedContentLength()
const
288
{
289
return
d_func()->removedContentLength;
290
}
291
292
bool
QHttpNetworkReply::isRedirecting()
const
293
{
294
return
d_func()->isRedirecting();
295
}
296
297
QHttpNetworkConnection* QHttpNetworkReply::connection()
298
{
299
return
d_func()->connection;
300
}
301
302
303
QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(
const
QUrl &newUrl)
304
: QHttpNetworkHeaderPrivate(newUrl)
305
, state(NothingDoneState)
306
, ssl(
false
),
307
bodyLength(0), contentRead(0), totalProgress(0),
308
chunkedTransferEncoding(
false
),
309
connectionCloseEnabled(
true
),
310
forceConnectionCloseEnabled(
false
),
311
lastChunkRead(
false
),
312
currentChunkSize(0), currentChunkRead(0), readBufferMaxSize(0),
313
totallyUploadedData(0),
314
removedContentLength(-1),
315
connection(
nullptr
),
316
autoDecompress(
false
), responseData(), requestIsPrepared(
false
)
317
,pipeliningUsed(
false
), h2Used(
false
), downstreamLimited(
false
)
318
,userProvidedDownloadBuffer(
nullptr
)
319
320
{
321
QString scheme = newUrl.scheme();
322
if
(scheme ==
"preconnect-http"_L1
|| scheme ==
"preconnect-https"_L1
)
323
// make sure we do not close the socket after preconnecting
324
connectionCloseEnabled =
false
;
325
}
326
327
QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate() =
default
;
328
329
void
QHttpNetworkReplyPrivate::clearHttpLayerInformation()
330
{
331
state = NothingDoneState;
332
bodyLength = 0;
333
contentRead = 0;
334
totalProgress = 0;
335
currentChunkSize = 0;
336
currentChunkRead = 0;
337
lastChunkRead =
false
;
338
connectionCloseEnabled =
true
;
339
parser.clear();
340
}
341
342
// TODO: Isn't everything HTTP layer related? We don't need to set connection and connectionChannel to 0 at all
343
void
QHttpNetworkReplyPrivate::clear()
344
{
345
connection =
nullptr
;
346
connectionChannel =
nullptr
;
347
autoDecompress =
false
;
348
clearHttpLayerInformation();
349
}
350
351
// QHttpNetworkReplyPrivate
352
qint64 QHttpNetworkReplyPrivate::bytesAvailable()
const
353
{
354
return
(state != ReadingDataState ? 0 : fragment.size());
355
}
356
357
bool
QHttpNetworkReplyPrivate::isCompressed()
const
358
{
359
return
QDecompressHelper::isSupportedEncoding(headerField(
"content-encoding"
));
360
}
361
362
bool
QHttpNetworkReply::isCompressed()
const
363
{
364
Q_D(
const
QHttpNetworkReply);
365
return
d->isCompressed();
366
}
367
368
void
QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
369
{
370
// The header "Content-Encoding = gzip" is retained.
371
// Content-Length is removed since the actual one sent by the server is for compressed data
372
constexpr
auto
name = QByteArrayView(
"content-length"
);
373
QByteArray contentLength = parser.firstHeaderField(name);
374
bool
parseOk =
false
;
375
qint64 value = contentLength.toLongLong(&parseOk);
376
if
(parseOk) {
377
removedContentLength = value;
378
parser.removeHeaderField(name);
379
}
380
}
381
382
qint64 QHttpNetworkReplyPrivate::readStatus(QIODevice *socket)
383
{
384
if
(fragment.isEmpty()) {
385
// reserve bytes for the status line. This is better than always append() which reallocs the byte array
386
fragment.reserve(32);
387
}
388
389
qint64 bytes = 0;
390
char
c;
391
qint64 haveRead = 0;
392
393
do
{
394
haveRead = socket->read(&c, 1);
395
if
(haveRead == -1)
396
return
-1;
// unexpected EOF
397
else
if
(haveRead == 0)
398
break
;
// read more later
399
else
if
(haveRead == 1 && fragment.size() == 0 && (c == 11 || c ==
'\n'
|| c ==
'\r'
|| c ==
' '
|| c == 31))
400
continue
;
// Ignore all whitespace that was trailing froma previous request on that socket
401
402
bytes++;
403
404
// allow both CRLF & LF (only) line endings
405
if
(c ==
'\n'
) {
406
// remove the CR at the end
407
if
(fragment.endsWith(
'\r'
)) {
408
fragment.truncate(fragment.size()-1);
409
}
410
bool
ok = parseStatus(fragment);
411
state = ReadingHeaderState;
412
fragment.clear();
413
if
(!ok) {
414
return
-1;
415
}
416
break
;
417
}
else
{
418
fragment.append(c);
419
}
420
421
// is this a valid reply?
422
if
(fragment.size() == 5 && !fragment.startsWith(
"HTTP/"
)) {
423
fragment.clear();
424
return
-1;
425
}
426
427
// parseStatus() rejects reason phrases longer than MAX_REASON_PHRASE_SIZE anyway,
428
// so anything beyond that plus a generous allowance for the rest of the line
429
// can never be valid.
430
if
(fragment.size() > HeaderConstants::MAX_REASON_PHRASE_SIZE + 64) {
431
fragment.clear();
432
return
-1;
433
}
434
}
while
(haveRead == 1);
435
436
return
bytes;
437
}
438
439
bool
QHttpNetworkReplyPrivate::parseStatus(QByteArrayView status)
440
{
441
return
parser.parseStatus(status);
442
}
443
444
qint64 QHttpNetworkReplyPrivate::readHeader(QIODevice *socket)
445
{
446
if
(fragment.isEmpty()) {
447
// according to http://dev.opera.com/articles/view/mama-http-headers/ the average size of the header
448
// block is 381 bytes.
449
// reserve bytes. This is better than always append() which reallocs the byte array.
450
fragment.reserve(512);
451
}
452
453
qint64 bytes = 0;
454
char
c = 0;
455
bool
allHeaders =
false
;
456
qint64 haveRead = 0;
457
do
{
458
haveRead = socket->read(&c, 1);
459
if
(haveRead == 0) {
460
// read more later
461
break
;
462
}
else
if
(haveRead == -1) {
463
// connection broke down
464
return
-1;
465
}
else
{
466
fragment.append(c);
467
bytes++;
468
469
// Enforce the total header size limit while accumulating.
470
if
(fragment.size() > parser.maxRawHeaderSize()) {
471
fragment.clear();
472
return
-1;
473
}
474
475
if
(c ==
'\n'
) {
476
// check for possible header endings. As per HTTP rfc,
477
// the header endings will be marked by CRLFCRLF. But
478
// we will allow CRLFCRLF, CRLFLF, LFCRLF, LFLF
479
if
(fragment.endsWith(
"\n\r\n"
)
480
|| fragment.endsWith(
"\n\n"
))
481
allHeaders =
true
;
482
483
// there is another case: We have no headers. Then the fragment equals just the line ending
484
if
((fragment.size() == 2 && fragment.endsWith(
"\r\n"
))
485
|| (fragment.size() == 1 && fragment.endsWith(
"\n"
)))
486
allHeaders =
true
;
487
}
488
}
489
}
while
(!allHeaders && haveRead > 0);
490
491
// we received all headers now parse them
492
if
(allHeaders) {
493
parseHeader(fragment);
494
state = ReadingDataState;
495
fragment.clear();
// next fragment
496
bodyLength = contentLength();
// cache the length
497
498
// cache isChunked() since it is called often
499
chunkedTransferEncoding = headerField(
"transfer-encoding"
).toLower().contains(
"chunked"
);
500
501
// cache isConnectionCloseEnabled since it is called often
502
QByteArray connectionHeaderField = headerField(
"connection"
);
503
// check for explicit indication of close or the implicit connection close of HTTP/1.0
504
connectionCloseEnabled = (connectionHeaderField.toLower().contains(
"close"
) ||
505
headerField(
"proxy-connection"
).toLower().contains(
"close"
)) ||
506
(parser.getMajorVersion() == 1 && parser.getMinorVersion() == 0 &&
507
(connectionHeaderField.isEmpty() && !headerField(
"proxy-connection"
).toLower().contains(
"keep-alive"
)));
508
}
509
return
bytes;
510
}
511
512
void
QHttpNetworkReplyPrivate::parseHeader(QByteArrayView header)
513
{
514
parser.parseHeaders(header);
515
}
516
517
void
QHttpNetworkReplyPrivate::appendHeaderField(
const
QByteArray &name,
const
QByteArray &data)
518
{
519
parser.appendHeaderField(name, data);
520
}
521
522
bool
QHttpNetworkReplyPrivate::isChunked()
523
{
524
return
chunkedTransferEncoding;
525
}
526
527
bool
QHttpNetworkReplyPrivate::isConnectionCloseEnabled()
528
{
529
return
connectionCloseEnabled || forceConnectionCloseEnabled;
530
}
531
532
// note this function can only be used for non-chunked, non-compressed with
533
// known content length
534
qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QIODevice *socket,
char
*b)
535
{
536
// This first read is to flush the buffer inside the socket
537
qint64 haveRead = 0;
538
haveRead = socket->read(b, bodyLength - contentRead);
539
if
(haveRead == -1) {
540
return
-1;
541
}
542
contentRead += haveRead;
543
544
if
(contentRead == bodyLength) {
545
state = AllDoneState;
546
}
547
548
return
haveRead;
549
}
550
551
// note this function can only be used for non-chunked, non-compressed with
552
// known content length
553
qint64 QHttpNetworkReplyPrivate::readBodyFast(QIODevice *socket, QByteDataBuffer *rb)
554
{
555
556
qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead);
557
if
(readBufferMaxSize)
558
toBeRead = qMin(toBeRead, readBufferMaxSize);
559
560
if
(!toBeRead)
561
return
0;
562
563
QByteArray bd;
564
bd.resize(toBeRead);
565
qint64 haveRead = socket->read(bd.data(), toBeRead);
566
if
(haveRead == -1) {
567
bd.clear();
568
return
0;
// ### error checking here;
569
}
570
bd.resize(haveRead);
571
572
rb->append(bd);
573
574
if
(contentRead + haveRead == bodyLength) {
575
state = AllDoneState;
576
}
577
578
contentRead += haveRead;
579
return
haveRead;
580
}
581
582
583
qint64 QHttpNetworkReplyPrivate::readBody(QIODevice *socket, QByteDataBuffer *out)
584
{
585
qint64 bytes = 0;
586
587
if
(isChunked()) {
588
// chunked transfer encoding (rfc 2616, sec 3.6)
589
bytes += readReplyBodyChunked(socket, out);
590
}
else
if
(bodyLength > 0) {
591
// we have a Content-Length
592
bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead);
593
if
(contentRead + bytes == bodyLength)
594
state = AllDoneState;
595
}
else
{
596
// no content length. just read what's possible
597
bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable());
598
}
599
contentRead += bytes;
600
return
bytes;
601
}
602
603
qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *socket, QByteDataBuffer *out, qint64 size)
604
{
605
// FIXME get rid of this function and just use readBodyFast and give it socket->bytesAvailable()
606
qint64 bytes = 0;
607
Q_ASSERT(socket);
608
Q_ASSERT(out);
609
610
int
toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, socket->bytesAvailable()));
611
612
if
(readBufferMaxSize)
613
toBeRead = qMin<qint64>(toBeRead, readBufferMaxSize);
614
615
while
(toBeRead > 0) {
616
QByteArray byteData;
617
byteData.resize(toBeRead);
618
qint64 haveRead = socket->read(byteData.data(), byteData.size());
619
if
(haveRead <= 0) {
620
// ### error checking here
621
byteData.clear();
622
return
bytes;
623
}
624
625
byteData.resize(haveRead);
626
out->append(byteData);
627
bytes += haveRead;
628
size -= haveRead;
629
630
toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, socket->bytesAvailable()));
631
}
632
return
bytes;
633
634
}
635
636
qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *socket, QByteDataBuffer *out)
637
{
638
qint64 bytes = 0;
639
while
(socket->bytesAvailable()) {
640
641
if
(readBufferMaxSize && (bytes > readBufferMaxSize))
642
break
;
643
644
if
(!lastChunkRead && currentChunkRead >= currentChunkSize) {
645
// For the first chunk and when we're done with a chunk
646
currentChunkSize = 0;
647
currentChunkRead = 0;
648
if
(bytes) {
649
// After a chunk
650
char
crlf[2];
651
// read the "\r\n" after the chunk
652
qint64 haveRead = socket->read(crlf, 2);
653
// FIXME: This code is slightly broken and not optimal. What if the 2 bytes are not available yet?!
654
// For nice reasons (the toLong in getChunkSize accepting \n at the beginning
655
// it right now still works, but we should definitely fix this.
656
657
if
(haveRead != 2)
658
return
bytes;
// FIXME
659
bytes += haveRead;
660
}
661
// Note that chunk size gets stored in currentChunkSize, what is returned is the bytes read
662
bytes += getChunkSize(socket, ¤tChunkSize);
663
if
(currentChunkSize == -1)
664
break
;
665
}
666
// if the chunk size is 0, end of the stream
667
if
(currentChunkSize == 0 || lastChunkRead) {
668
lastChunkRead =
true
;
669
// try to read the "\r\n" after the chunk
670
char
crlf[2];
671
qint64 haveRead = socket->read(crlf, 2);
672
if
(haveRead > 0)
673
bytes += haveRead;
674
675
if
((haveRead == 2 && crlf[0] ==
'\r'
&& crlf[1] ==
'\n'
) || (haveRead == 1 && crlf[0] ==
'\n'
))
676
state = AllDoneState;
677
else
if
(haveRead == 1 && crlf[0] ==
'\r'
)
678
break
;
// Still waiting for the last \n
679
else
if
(haveRead > 0) {
680
// If we read something else then CRLF, we need to close the channel.
681
forceConnectionCloseEnabled =
true
;
682
state = AllDoneState;
683
}
684
break
;
685
}
686
687
// otherwise, try to begin reading this chunk / to read what is missing for this chunk
688
qint64 haveRead = readReplyBodyRaw (socket, out, currentChunkSize - currentChunkRead);
689
currentChunkRead += haveRead;
690
bytes += haveRead;
691
692
// ### error checking here
693
694
}
695
return
bytes;
696
}
697
698
qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *socket, qint64 *chunkSize)
699
{
700
qint64 bytes = 0;
701
char
crlf[2];
702
*chunkSize = -1;
703
704
int
bytesAvailable = socket->bytesAvailable();
705
// FIXME rewrite to permanent loop without bytesAvailable
706
while
(bytesAvailable > bytes) {
707
qint64 sniffedBytes = socket->peek(crlf, 2);
708
int
fragmentSize = fragment.size();
709
710
// check the next two bytes for a "\r\n", skip blank lines
711
if
((fragmentSize && sniffedBytes == 2 && crlf[0] ==
'\r'
&& crlf[1] ==
'\n'
)
712
||(fragmentSize > 1 && fragment.endsWith(
'\r'
) && crlf[0] ==
'\n'
))
713
{
714
bytes += socket->read(crlf, 1);
// read the \r or \n
715
if
(crlf[0] ==
'\r'
)
716
bytes += socket->read(crlf, 1);
// read the \n
717
bool
ok =
false
;
718
// ignore the chunk-extension
719
const
auto
fragmentView = QByteArrayView(fragment).mid(0, fragment.indexOf(
';'
)).trimmed();
720
*chunkSize = fragmentView.toLong(&ok, 16);
721
fragment.clear();
722
break
;
// size done
723
}
else
{
724
// read the fragment to the buffer
725
char
c = 0;
726
qint64 haveRead = socket->read(&c, 1);
727
if
(haveRead < 0) {
728
return
-1;
// FIXME
729
}
730
bytes += haveRead;
731
fragment.append(c);
732
}
733
}
734
735
return
bytes;
736
}
737
738
bool
QHttpNetworkReplyPrivate::isRedirecting()
const
739
{
740
// We're in the process of redirecting - if the HTTP status code says so and
741
// followRedirect is switched on
742
return
(QHttpNetworkReply::isHttpRedirect(parser.getStatusCode())
743
&& request.isFollowRedirects());
744
}
745
746
bool
QHttpNetworkReplyPrivate::shouldEmitSignals()
747
{
748
// for 401 & 407 don't emit the data signals. Content along with these
749
// responses are sent only if the authentication fails.
750
return
parser.getStatusCode() != 401 && parser.getStatusCode() != 407;
751
}
752
753
bool
QHttpNetworkReplyPrivate::expectContent()
754
{
755
int
statusCode = parser.getStatusCode();
756
// check whether we can expect content after the headers (rfc 2616, sec4.4)
757
if
((statusCode >= 100 && statusCode < 200)
758
|| statusCode == 204 || statusCode == 304)
759
return
false
;
760
if
(request.operation() == QHttpNetworkRequest::Head)
761
return
false
;
// no body expected for HEAD request
762
qint64 expectedContentLength = contentLength();
763
if
(expectedContentLength == 0)
764
return
false
;
765
if
(expectedContentLength == -1 && bodyLength == 0) {
766
// The content-length header was stripped, but its value was 0.
767
// This would be the case for an explicitly zero-length compressed response.
768
return
false
;
769
}
770
return
true
;
771
}
772
773
void
QHttpNetworkReplyPrivate::eraseData()
774
{
775
responseData.clear();
776
}
777
778
779
// SSL support below
780
#
ifndef
QT_NO_SSL
781
782
QSslConfiguration QHttpNetworkReply::sslConfiguration()
const
783
{
784
Q_D(
const
QHttpNetworkReply);
785
786
if
(!d->connectionChannel)
787
return
QSslConfiguration();
788
789
QSslSocket *sslSocket = qobject_cast<QSslSocket*>(d->connectionChannel->socket);
790
if
(!sslSocket)
791
return
QSslConfiguration();
792
793
return
sslSocket->sslConfiguration();
794
}
795
796
void
QHttpNetworkReply::setSslConfiguration(
const
QSslConfiguration &config)
797
{
798
Q_D(QHttpNetworkReply);
799
if
(d->connection)
800
d->connection->setSslConfiguration(config);
801
}
802
803
void
QHttpNetworkReply::ignoreSslErrors()
804
{
805
Q_D(QHttpNetworkReply);
806
if
(d->connection)
807
d->connection->ignoreSslErrors();
808
}
809
810
void
QHttpNetworkReply::ignoreSslErrors(
const
QList<QSslError> &errors)
811
{
812
Q_D(QHttpNetworkReply);
813
if
(d->connection)
814
d->connection->ignoreSslErrors(errors);
815
}
816
817
818
#
endif
//QT_NO_SSL
819
820
821
QT_END_NAMESPACE
822
823
#
include
"moc_qhttpnetworkreply_p.cpp"
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
qtbase
src
network
access
qhttpnetworkreply.cpp
Generated on
for Qt by
1.18.0