Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qnetworkreplywasmimpl.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 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
5#include "qnetworkrequest.h"
6
7#include <QtCore/qtimer.h>
8#include <QtCore/qdatetime.h>
9#include <QtCore/qcoreapplication.h>
10#include <QtCore/qfileinfo.h>
11#include <QtCore/qthread.h>
12#include <QtCore/private/qeventdispatcher_wasm_p.h>
13#include <QtCore/private/qoffsetstringarray_p.h>
14#include <QtCore/private/qtools_p.h>
15
16#include <private/qnetworkaccessmanager_p.h>
17#include <private/qnetworkfile_p.h>
18
19#include <emscripten.h>
20#include <emscripten/fetch.h>
21
23
24using namespace Qt::StringLiterals;
25
26namespace {
27
28static constexpr auto BannedHeaders = qOffsetStringArray(
29 "accept-charset",
30 "accept-encoding",
31 "access-control-request-headers",
32 "access-control-request-method",
33 "connection",
34 "content-length",
35 "cookie",
36 "cookie2",
37 "date",
38 "dnt",
39 "expect",
40 "host",
41 "keep-alive",
42 "origin",
43 "referer",
44 "te",
45 "trailer",
46 "transfer-encoding",
47 "upgrade",
48 "via"
49);
50
51bool isUnsafeHeader(QLatin1StringView header) noexcept
52{
53 return header.startsWith("proxy-"_L1, Qt::CaseInsensitive)
54 || header.startsWith("sec-"_L1, Qt::CaseInsensitive)
55 || BannedHeaders.contains(header, Qt::CaseInsensitive);
56}
57} // namespace
58
61 , managerPrivate(0)
62 , downloadBufferReadPosition(0)
63 , downloadBufferCurrentSize(0)
64 , totalDownloadSize(0)
65 , percentFinished(0)
66 , m_fetch(nullptr)
67 , m_fetchContext(nullptr)
68{
69}
70
89
96
103
104QByteArray QNetworkReplyWasmImpl::methodName() const
105{
106 const Q_D( QNetworkReplyWasmImpl);
107 switch (operation()) {
109 return "HEAD";
111 return "GET";
113 return "PUT";
115 return "POST";
117 return "DELETE";
119 return d->request.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray();
120 default:
121 break;
122 }
123 return QByteArray();
124}
125
127{
129
130 if (d->state != QNetworkReplyPrivate::Aborted &&
132 d->state != QNetworkReplyPrivate::Idle) {
134 d->setCanceled();
135 }
136 emscripten_fetch_close(d->m_fetch);
138}
139
141{
143
145 return;
146
148 d->setCanceled();
149}
150
167
169{
170 Q_D(const QNetworkReplyWasmImpl);
171
172 return QNetworkReply::bytesAvailable() + d->downloadBufferCurrentSize - d->downloadBufferReadPosition;
173}
174
176{
177 return true;
178}
179
184
189{
191
192 qint64 howMuch = qMin(maxlen, (d->downloadBuffer.size() - d->downloadBufferReadPosition));
193 memcpy(data, d->downloadBuffer.constData() + d->downloadBufferReadPosition, howMuch);
194 d->downloadBufferReadPosition += howMuch;
195
196 return howMuch;
197}
198
200{
202
204 request = req;
205 url = request.url();
206 operation = op;
207
208 q->QIODevice::open(QIODevice::ReadOnly);
210 bool bufferingDisallowed =
212
213 if (bufferingDisallowed) {
214 // if a valid content-length header for the request was supplied, we can disable buffering
215 // if not, we will buffer anyway
219 return;
220 }
221 } else {
222 // doSendRequest will be called when the buffering has finished.
225 return;
226 }
227 }
228 // No outgoing data (POST, ..)
230}
231
233{
235 Q_ASSERT(handler);
236
237 handler->q_func()->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
238 if (!statusReason.isEmpty())
239 handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, statusReason);
240}
241
242constexpr int getArraySize (int factor) {
243 return 2 * factor + 1;
244}
245
247{
250
251 emscripten_fetch_attr_t attr;
252 emscripten_fetch_attr_init(&attr);
253 qstrncpy(attr.requestMethod, q->methodName().constData(), 32); // requestMethod is char[32] in emscripten
254
255 attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
256
257 QNetworkRequest::CacheLoadControl CacheLoadControlAttribute =
259
260 if (CacheLoadControlAttribute == QNetworkRequest::AlwaysCache) {
261 attr.attributes += EMSCRIPTEN_FETCH_NO_DOWNLOAD;
262 }
263 if (CacheLoadControlAttribute == QNetworkRequest::PreferCache) {
264 attr.attributes += EMSCRIPTEN_FETCH_APPEND;
265 }
266
267 if (CacheLoadControlAttribute == QNetworkRequest::AlwaysNetwork ||
269 attr.attributes -= EMSCRIPTEN_FETCH_PERSIST_FILE;
270 }
271
272 attr.withCredentials = request.attribute(QNetworkRequest::UseCredentialsAttribute, false).toBool();
276 attr.onreadystatechange = QNetworkReplyWasmImplPrivate::stateChange;
277 attr.timeoutMSecs = request.transferTimeout();
278
279 m_fetchContext = new FetchContext(this);;
280 attr.userData = static_cast<void *>(m_fetchContext);
281 if (outgoingData) { // data from post request
282 m_fetchContext->requestData = outgoingData->readAll(); // is there a size restriction here?
284 attr.requestData = m_fetchContext->requestData.data();
285 attr.requestDataSize = m_fetchContext->requestData.size();
286 }
287 }
288
289 QEventDispatcherWasm::runOnMainThread([attr, fetchContext = m_fetchContext]() mutable {
290 std::unique_lock lock{ fetchContext->mutex };
291 if (fetchContext->state == FetchContext::State::CANCELED) {
292 fetchContext->state = FetchContext::State::FINISHED;
293 return;
294 } else if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) {
295 lock.unlock();
296 delete fetchContext;
297 return;
298 }
299 const auto reply = fetchContext->reply;
300 const auto &request = reply->request;
301
302 QByteArray userName, password;
303 if (!request.url().userInfo().isEmpty()) {
304 userName = request.url().userName().toUtf8();
305 password = request.url().password().toUtf8();
306 attr.userName = userName.constData();
307 attr.password = password.constData();
308 }
309
310 QList<QByteArray> headersData = request.rawHeaderList();
311 int arrayLength = getArraySize(headersData.count());
312 const char *customHeaders[arrayLength];
313 QStringList trimmedHeaders;
314 if (headersData.count() > 0) {
315 int i = 0;
316 for (const auto &headerName : headersData) {
317 if (isUnsafeHeader(QLatin1StringView(headerName.constData()))) {
318 trimmedHeaders.push_back(QString::fromLatin1(headerName));
319 } else {
320 customHeaders[i++] = headerName.constData();
321 customHeaders[i++] = request.rawHeader(headerName).constData();
322 }
323 }
324 if (!trimmedHeaders.isEmpty()) {
325 qWarning() << "Qt has trimmed the following forbidden headers from the request:"
326 << trimmedHeaders.join(QLatin1StringView(", "));
327 }
328 customHeaders[i] = nullptr;
329 attr.requestHeaders = customHeaders;
330 }
331
332 auto url = request.url().toString().toUtf8();
333 QString dPath = "/home/web_user/"_L1 + request.url().fileName();
334 QByteArray destinationPath = dPath.toUtf8();
335 attr.destinationPath = destinationPath.constData();
336 reply->m_fetch = emscripten_fetch(&attr, url.constData());
337 fetchContext->state = FetchContext::State::SENT;
338 });
339 state = Working;
340}
341
343{
345
346 q->setError(errorCode, errorString);
347 emit q->errorOccurred(errorCode);
348}
349
351{
353
354 totalDownloadSize = bytesTotal;
355
356 percentFinished = bytesTotal ? (bytesReceived / bytesTotal) * 100 : 100;
357
358 emit q->downloadProgress(bytesReceived, bytesTotal);
359}
360
362{
364
365 const qsizetype bufferSize = buffer.size();
366 if (bufferSize > 0)
367 q->setReadBufferSize(bufferSize);
368
369 bytesDownloaded = bufferSize;
370
371 if (percentFinished != 100)
372 downloadBufferCurrentSize += bufferSize;
373 else
374 downloadBufferCurrentSize = bufferSize;
375
377
379
380 emit q->readyRead();
381}
382
383//taken from qnetworkrequest.cpp
384static int parseHeaderName(const QByteArray &headerName)
385{
386 if (headerName.isEmpty())
387 return -1;
388
389 auto is = [&](const char *what) {
390 return qstrnicmp(headerName.data(), headerName.size(), what) == 0;
391 };
392
393 switch (QtMiscUtils::toAsciiLower(headerName.front())) {
394 case 'c':
395 if (is("content-type"))
397 else if (is("content-length"))
399 else if (is("cookie"))
401 break;
402
403 case 'l':
404 if (is("location"))
406 else if (is("last-modified"))
408 break;
409
410 case 's':
411 if (is("set-cookie"))
413 else if (is("server"))
415 break;
416
417 case 'u':
418 if (is("user-agent"))
420 break;
421 }
422
423 return -1; // nothing found
424}
425
426
428{
430
431 if (!buffer.isEmpty()) {
432 QList<QByteArray> headers = buffer.split('\n');
433
434 for (int i = 0; i < headers.size(); i++) {
435 if (headers.at(i).contains(':')) { // headers include final \x00, so skip
436 QByteArray headerName = headers.at(i).split(':').at(0).trimmed();
437 QByteArray headersValue = headers.at(i).split(':').at(1).trimmed();
438
439 if (headerName.isEmpty() || headersValue.isEmpty())
440 continue;
441
442 int headerIndex = parseHeaderName(headerName);
443
444 if (headerIndex == -1)
445 q->setRawHeader(headerName, headersValue);
446 else
447 q->setHeader(static_cast<QNetworkRequest::KnownHeaders>(headerIndex), (QVariant)headersValue);
448 }
449 }
450 }
451 emit q->metaDataChanged();
452}
453
455{
457
458 // make sure this is only called once, ever.
459 //_q_bufferOutgoingData may call it or the readChannelFinished emission
460 if (state != Buffering)
461 return;
462
463 // disconnect signals
466
467 // finally, start the request
469}
470
472{
474
475 if (!outgoingDataBuffer) {
476 // first call, create our buffer
477 outgoingDataBuffer = std::make_shared<QRingBuffer>();
478
481 }
482
484 qint64 bytesToBuffer = 0;
485
486 // read data into our buffer
487 forever {
488 bytesToBuffer = outgoingData->bytesAvailable();
489 // unknown? just try 2 kB, this also ensures we always try to read the EOF
490 if (bytesToBuffer <= 0)
491 bytesToBuffer = 2*1024;
492
493 char *dst = outgoingDataBuffer->reserve(bytesToBuffer);
494 bytesBuffered = outgoingData->read(dst, bytesToBuffer);
495
496 if (bytesBuffered == -1) {
497 // EOF has been reached.
498 outgoingDataBuffer->chop(bytesToBuffer);
499
501 break;
502 } else if (bytesBuffered == 0) {
503 // nothing read right now, just wait until we get called again
504 outgoingDataBuffer->chop(bytesToBuffer);
505
506 break;
507 } else {
508 // don't break, try to read() again
509 outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered);
510 }
511 }
512}
513
515{
516 auto fetchContext = static_cast<FetchContext *>(fetch->userData);
517 std::unique_lock lock{ fetchContext->mutex };
518
519 if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) {
520 lock.unlock();
521 delete fetchContext;
522 return;
523 } else if (fetchContext->state == FetchContext::State::CANCELED) {
524 fetchContext->state = FetchContext::State::FINISHED;
525 return;
526 } else if (fetchContext->state == FetchContext::State::SENT) {
527 const auto reply = fetchContext->reply;
528 if (reply->state != QNetworkReplyPrivate::Aborted) {
529 QByteArray buffer(fetch->data, fetch->numBytes);
530 reply->dataReceived(buffer);
531 QByteArray statusText(fetch->statusText);
532 reply->setStatusCode(fetch->status, statusText);
533 reply->setReplyFinished();
534 }
535 reply->m_fetch = nullptr;
536 fetchContext->state = FetchContext::State::FINISHED;
537 }
538}
539
541{
544 q->setFinished(true);
545 emit q->readChannelFinished();
546 emit q->finished();
547}
548
550{
552 q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, status);
553 q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, statusText);
554}
555
556void QNetworkReplyWasmImplPrivate::stateChange(emscripten_fetch_t *fetch)
557{
558 const auto fetchContext = static_cast<FetchContext*>(fetch->userData);
559 const auto reply = fetchContext->reply;
560 if (reply && reply->state != QNetworkReplyPrivate::Aborted) {
561 if (fetch->readyState == /*HEADERS_RECEIVED*/ 2) {
562 size_t headerLength = emscripten_fetch_get_response_headers_length(fetch);
563 QByteArray str(headerLength, Qt::Uninitialized);
564 emscripten_fetch_get_response_headers(fetch, str.data(), str.size());
565 reply->headersReceived(str);
566 }
567 }
568}
569
571{
572 const auto fetchContext = static_cast<FetchContext*>(fetch->userData);
573 const auto reply = fetchContext->reply;
574 if (reply && reply->state != QNetworkReplyPrivate::Aborted) {
575 if (fetch->status < 400) {
576 uint64_t bytes = fetch->dataOffset + fetch->numBytes;
577 uint64_t tBytes = fetch->totalBytes; // totalBytes can be 0 if server not reporting content length
578 if (tBytes == 0)
579 tBytes = bytes;
580 reply->emitDataReadProgress(bytes, tBytes);
581 }
582 }
583}
584
585void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch)
586{
587 const auto fetchContext = static_cast<FetchContext*>(fetch->userData);
588 std::unique_lock lock{ fetchContext->mutex };
589
590 if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) {
591 lock.unlock();
592 delete fetchContext;
593 return;
594 } else if (fetchContext->state == FetchContext::State::CANCELED) {
595 fetchContext->state = FetchContext::State::FINISHED;
596 return;
597 } else if (fetchContext->state == FetchContext::State::SENT) {
598 const auto reply = fetchContext->reply;
599 if (reply->state != QNetworkReplyPrivate::Aborted) {
600 QString reasonStr;
601 if (fetch->status > 600)
602 reasonStr = QStringLiteral("Operation canceled");
603 else
604 reasonStr = QString::fromUtf8(fetch->statusText);
605 QByteArray buffer(fetch->data, fetch->numBytes);
606 reply->dataReceived(buffer);
607 QByteArray statusText(fetch->statusText);
608 reply->setStatusCode(fetch->status, statusText);
609 reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()),
610 reasonStr);
611 reply->setReplyFinished();
612 }
613 reply->m_fetch = nullptr;
614 fetchContext->state = FetchContext::State::FINISHED;
615 }
616}
617
618//taken from qhttpthreaddelegate.cpp
620{
622 // we've got an error
623 switch (httpStatusCode) {
624 case 400: // Bad Request
626 break;
627
628 case 401: // Authorization required
630 break;
631
632 case 403: // Access denied
634 break;
635
636 case 404: // Not Found
638 break;
639
640 case 405: // Method Not Allowed
642 break;
643
644 case 407:
646 break;
647
648 case 409: // Resource Conflict
650 break;
651
652 case 410: // Content no longer available
654 break;
655
656 case 418: // I'm a teapot
658 break;
659
660 case 500: // Internal Server Error
662 break;
663
664 case 501: // Server does not support this functionality
666 break;
667
668 case 503: // Service unavailable
670 break;
671
672 case 65535: //emscripten reply when aborted
674 break;
675 default:
676 if (httpStatusCode > 500) {
677 // some kind of server error
679 } else if (httpStatusCode >= 400) {
680 // content error we did not handle above
682 } else {
683 qWarning("QNetworkAccess: got HTTP status code %d which is not expected from url: \"%s\"",
684 httpStatusCode, qPrintable(url.toString()));
686 }
687 };
688
689 return code;
690}
691
693
694#include "moc_qnetworkreplywasmimpl_p.cpp"
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:107
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static void runOnMainThread(std::function< void(void)> fn)
Q_NETWORK_EXPORT qsizetype size() const noexcept
Returns the number of header entries.
Q_NETWORK_EXPORT bool contains(QAnyStringView name) const
Returns whether the headers contain header with name.
QRingBufferRef buffer
Definition qiodevice_p.h:92
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
Operation
Indicates the operation this reply is processing.
QHttpHeaders headers() const
QNetworkRequest request
QNetworkAccessManager::Operation operation
QNetworkReply::NetworkError errorCode
std::shared_ptr< QRingBuffer > outgoingDataBuffer
static void setReplyAttributes(quintptr data, int statusCode, const QString &statusReason)
void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
static void downloadFailed(emscripten_fetch_t *fetch)
static void downloadSucceeded(emscripten_fetch_t *fetch)
void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &)
void setStatusCode(int status, const QByteArray &statusText)
void headersReceived(const QByteArray &buffer)
static void stateChange(emscripten_fetch_t *fetch)
void emitDataReadProgress(qint64 done, qint64 total)
static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url)
static void downloadProgress(emscripten_fetch_t *fetch)
void dataReceived(const QByteArray &buffer)
qint64 size() const override
For open random-access devices, this function returns the size of the device.
virtual qint64 bytesAvailable() const override
Returns the number of bytes that are available for reading.
virtual qint64 readData(char *data, qint64 maxlen) override
virtual void abort() override
Aborts the operation immediately and close down any network connections still open.
virtual bool isSequential() const override
QNetworkReplyWasmImpl(QObject *parent=nullptr)
virtual void close() override
Closes this device for reading.
The QNetworkReply class contains the data and headers for a request sent with QNetworkAccessManager.
virtual void close() override
Closes this device for reading.
QNetworkAccessManager::Operation operation() const
Returns the operation that was posted for this reply.
bool isRunning() const
NetworkError
Indicates all possible error conditions found during the processing of the request.
@ ContentOperationNotPermittedError
@ OperationNotImplementedError
@ ProtocolInvalidOperationError
@ ProxyAuthenticationRequiredError
@ AuthenticationRequiredError
QNetworkRequest request() const
Returns the request that was posted for this reply.
The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
KnownHeaders
List of known header types that QNetworkRequest parses.
QVariant attribute(Attribute code, const QVariant &defaultValue=QVariant()) const
Returns the attribute associated with the code code.
QVariant header(KnownHeaders header) const
Returns the value of the known network header header if it is present in this request.
QByteArray rawHeader(QAnyStringView headerName) const
Returns the raw form of header headerName.
QList< QByteArray > rawHeaderList() const
Returns a list of all raw headers that are set in this network request.
QUrl url() const
Returns the URL this network request is referring to.
CacheLoadControl
Controls the caching mechanism of QNetworkAccessManager.
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
QByteArray toUtf8() const &
Definition qstring.h:634
\inmodule QtCore
Definition qurl.h:94
QString userInfo(ComponentFormattingOptions options=PrettyDecoded) const
Returns the user info of the URL, or an empty string if the user info is undefined.
Definition qurl.cpp:2129
QString fileName(ComponentFormattingOptions options=FullyDecoded) const
Definition qurl.cpp:2497
QString userName(ComponentFormattingOptions options=FullyDecoded) const
Returns the user name of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2199
QString password(ComponentFormattingOptions=FullyDecoded) const
Returns the password of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2262
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
\inmodule QtCore
Definition qvariant.h:65
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
Definition qvariant.h:714
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
bool toBool() const
Returns the variant as a bool if the variant has userType() Bool.
QString str
[2]
Combined button and popup list for selecting options.
constexpr char toAsciiLower(char ch) noexcept
Definition qtools_p.h:87
@ CaseInsensitive
constexpr Initialization Uninitialized
static int arrayLength(const QString &rawType)
Definition provider.cpp:52
int qstrnicmp(const char *str1, qsizetype len1, const char *str2, qsizetype len2)
Q_CORE_EXPORT char * qstrncpy(char *dst, const char *src, size_t len)
static QString header(const QString &name)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define forever
Definition qforeach.h:78
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr int getArraySize(int factor)
static int parseHeaderName(const QByteArray &headerName)
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
constexpr auto qOffsetStringArray(const char(&...strings)[Nx]) noexcept
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLenum GLenum dst
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
#define emit
size_t quintptr
Definition qtypes.h:167
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
if(qFloatDistance(a, b)<(1<< 7))
[0]
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
QReadWriteLock lock
[0]
QNetworkReply * reply
The FetchContext class ensures the requestData object remains valid while a fetch operation is pendin...
QNetworkReplyWasmImplPrivate * reply