/* function form(uri: String = null, formData: Object = null): Http Issue a POST method with form data */ static EjsHttp *http_form(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { EjsObj *data; if (argc == 2 && !ejsIs(ejs, argv[1], Null)) { /* Prep here to reset the state. The ensures the current headers will be preserved. Users may have called setHeader to define custom headers. Users must call reset if they want to clear prior headers. */ httpPrepClientConn(hp->conn, 1); mprFlushBuf(hp->requestContent); data = argv[1]; if (ejsGetLength(ejs, data) > 0) { prepForm(ejs, hp, NULL, data); } else { mprPutStringToBuf(hp->requestContent, ejsToMulti(ejs, data)); } mprAddNullToBuf(hp->requestContent); httpSetHeader(hp->conn, "Content-Type", "application/x-www-form-urlencoded"); /* Ensure this gets recomputed */ httpRemoveHeader(hp->conn, "Content-Length"); } return startHttpRequest(ejs, hp, "POST", argc, argv); }
/* function get(uri: String = null, ...data): Http The spec allows GET methods to have body data, but is rarely, if ever, used. */ static EjsHttp *http_get(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { startHttpRequest(ejs, hp, "GET", argc, argv); if (!ejs->exception && hp->conn) { httpFinalize(hp->conn); } return hp; }
/* function put(uri: String = null, form object): Http */ static EjsHttp *http_put(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { return startHttpRequest(ejs, hp, "PUT", argc, argv); }
/* function head(uri: String = null): Http */ static EjsHttp *http_head(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { return startHttpRequest(ejs, hp, "HEAD", argc, argv); }
/* function connect(method: String, url = null, data ...): Http */ static EjsHttp *http_connect(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { hp->method = ejsToMulti(ejs, argv[0]); return startHttpRequest(ejs, hp, NULL, argc - 1, &argv[1]); }
void QNetworkAccessHttpBackend::postRequest() { QThread *thread = 0; if (isSynchronous()) { // A synchronous HTTP request uses its own thread thread = new QThread(); QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); } else if (!manager->httpThread) { // We use the manager-global thread. // At some point we could switch to having multiple threads if it makes sense. manager->httpThread = new QThread(); QObject::connect(manager->httpThread, SIGNAL(finished()), manager->httpThread, SLOT(deleteLater())); manager->httpThread->start(); #ifndef QT_NO_NETWORKPROXY qRegisterMetaType<QNetworkProxy>("QNetworkProxy"); #endif #ifndef QT_NO_OPENSSL qRegisterMetaType<QList<QSslError> >("QList<QSslError>"); qRegisterMetaType<QSslConfiguration>("QSslConfiguration"); #endif qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >("QList<QPair<QByteArray,QByteArray> >"); qRegisterMetaType<QHttpNetworkRequest>("QHttpNetworkRequest"); qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError"); qRegisterMetaType<QSharedPointer<char> >("QSharedPointer<char>"); thread = manager->httpThread; } else { // Asynchronous request, thread already exists thread = manager->httpThread; } QUrl url = request().url(); httpRequest.setUrl(url); bool ssl = url.scheme().toLower() == QLatin1String("https"); setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl); httpRequest.setSsl(ssl); #ifndef QT_NO_NETWORKPROXY QNetworkProxy transparentProxy, cacheProxy; foreach (const QNetworkProxy &p, proxyList()) { // use the first proxy that works // for non-encrypted connections, any transparent or HTTP proxy // for encrypted, only transparent proxies if (!ssl && (p.capabilities() & QNetworkProxy::CachingCapability) && (p.type() == QNetworkProxy::HttpProxy || p.type() == QNetworkProxy::HttpCachingProxy)) { cacheProxy = p; transparentProxy = QNetworkProxy::NoProxy; break; } if (p.isTransparentProxy()) { transparentProxy = p; cacheProxy = QNetworkProxy::NoProxy; break; } } // check if at least one of the proxies if (transparentProxy.type() == QNetworkProxy::DefaultProxy && cacheProxy.type() == QNetworkProxy::DefaultProxy) { // unsuitable proxies QMetaObject::invokeMethod(this, "error", isSynchronous() ? Qt::DirectConnection : Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError), Q_ARG(QString, tr("No suitable proxy found"))); QMetaObject::invokeMethod(this, "finished", isSynchronous() ? Qt::DirectConnection : Qt::QueuedConnection); return; } #endif bool loadedFromCache = false; httpRequest.setPriority(convert(request().priority())); switch (operation()) { case QNetworkAccessManager::GetOperation: httpRequest.setOperation(QHttpNetworkRequest::Get); loadedFromCache = loadFromCacheIfAllowed(httpRequest); break; case QNetworkAccessManager::HeadOperation: httpRequest.setOperation(QHttpNetworkRequest::Head); loadedFromCache = loadFromCacheIfAllowed(httpRequest); break; case QNetworkAccessManager::PostOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Post); createUploadByteDevice(); break; case QNetworkAccessManager::PutOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Put); createUploadByteDevice(); break; case QNetworkAccessManager::DeleteOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Delete); break; case QNetworkAccessManager::CustomOperation: invalidateCache(); // for safety reasons, we don't know what the operation does httpRequest.setOperation(QHttpNetworkRequest::Custom); createUploadByteDevice(); httpRequest.setCustomVerb(request().attribute( QNetworkRequest::CustomVerbAttribute).toByteArray()); break; default: break; // can't happen } if (loadedFromCache) { // commented this out since it will be called later anyway // by copyFinished() //QNetworkAccessBackend::finished(); return; // no need to send the request! :) } QList<QByteArray> headers = request().rawHeaderList(); if (resumeOffset != 0) { if (headers.contains("Range")) { // Need to adjust resume offset for user specified range headers.removeOne("Range"); // We've already verified that requestRange starts with "bytes=", see canResume. QByteArray requestRange = request().rawHeader("Range").mid(6); int index = requestRange.indexOf('-'); quint64 requestStartOffset = requestRange.left(index).toULongLong(); quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong(); requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) + '-' + QByteArray::number(requestEndOffset); httpRequest.setHeaderField("Range", requestRange); } else { httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-'); } } foreach (const QByteArray &header, headers) httpRequest.setHeaderField(header, request().rawHeader(header)); if (request().attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool() == true) httpRequest.setPipeliningAllowed(true); if (static_cast<QNetworkRequest::LoadControl> (request().attribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual) httpRequest.setWithCredentials(false); // Create the HTTP thread delegate QHttpThreadDelegate *delegate = new QHttpThreadDelegate; #ifndef QT_NO_BEARERMANAGEMENT QVariant v(property("_q_networksession")); if (v.isValid()) delegate->networkSession = qvariant_cast<QSharedPointer<QNetworkSession> >(v); #endif // For the synchronous HTTP, this is the normal way the delegate gets deleted // For the asynchronous HTTP this is a safety measure, the delegate deletes itself when HTTP is finished connect(thread, SIGNAL(finished()), delegate, SLOT(deleteLater())); // Set the properties it needs delegate->httpRequest = httpRequest; #ifndef QT_NO_NETWORKPROXY delegate->cacheProxy = cacheProxy; delegate->transparentProxy = transparentProxy; #endif delegate->ssl = ssl; #ifndef QT_NO_OPENSSL if (ssl) delegate->incomingSslConfiguration = request().sslConfiguration(); #endif // Do we use synchronous HTTP? delegate->synchronous = isSynchronous(); // The authentication manager is used to avoid the BlockingQueuedConnection communication // from HTTP thread to user thread in some cases. delegate->authenticationManager = manager->authenticationManager; if (!isSynchronous()) { // Tell our zerocopy policy to the delegate delegate->downloadBufferMaximumSize = request().attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute).toLongLong(); // These atomic integers are used for signal compression delegate->pendingDownloadData = pendingDownloadDataEmissions; delegate->pendingDownloadProgress = pendingDownloadProgressEmissions; // Connect the signals of the delegate to us connect(delegate, SIGNAL(downloadData(QByteArray)), this, SLOT(replyDownloadData(QByteArray)), Qt::QueuedConnection); connect(delegate, SIGNAL(downloadFinished()), this, SLOT(replyFinished()), Qt::QueuedConnection); connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)), this, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)), Qt::QueuedConnection); connect(delegate, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(replyDownloadProgressSlot(qint64,qint64)), Qt::QueuedConnection); connect(delegate, SIGNAL(error(QNetworkReply::NetworkError,QString)), this, SLOT(httpError(QNetworkReply::NetworkError, const QString)), Qt::QueuedConnection); #ifndef QT_NO_OPENSSL connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)), this, SLOT(replySslConfigurationChanged(QSslConfiguration)), Qt::QueuedConnection); #endif // Those need to report back, therefire BlockingQueuedConnection connect(delegate, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)), this, SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)), Qt::BlockingQueuedConnection); #ifndef QT_NO_NETWORKPROXY connect (delegate, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), Qt::BlockingQueuedConnection); #endif #ifndef QT_NO_OPENSSL connect(delegate, SIGNAL(sslErrors(QList<QSslError>,bool*,QList<QSslError>*)), this, SLOT(replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *)), Qt::BlockingQueuedConnection); #endif // This signal we will use to start the request. connect(this, SIGNAL(startHttpRequest()), delegate, SLOT(startRequest())); connect(this, SIGNAL(abortHttpRequest()), delegate, SLOT(abortRequest())); // To throttle the connection. QObject::connect(this, SIGNAL(readBufferSizeChanged(qint64)), delegate, SLOT(readBufferSizeChanged(qint64))); QObject::connect(this, SIGNAL(readBufferFreed(qint64)), delegate, SLOT(readBufferFreed(qint64))); if (uploadByteDevice) { QNonContiguousByteDeviceThreadForwardImpl *forwardUploadDevice = new QNonContiguousByteDeviceThreadForwardImpl(uploadByteDevice->atEnd(), uploadByteDevice->size()); if (uploadByteDevice->isResetDisabled()) forwardUploadDevice->disableReset(); forwardUploadDevice->setParent(delegate); // needed to make sure it is moved on moveToThread() delegate->httpRequest.setUploadByteDevice(forwardUploadDevice); // From main thread to user thread: QObject::connect(this, SIGNAL(haveUploadData(QByteArray, bool, qint64)), forwardUploadDevice, SLOT(haveDataSlot(QByteArray, bool, qint64)), Qt::QueuedConnection); QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()), forwardUploadDevice, SIGNAL(readyRead()), Qt::QueuedConnection); // From http thread to user thread: QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)), this, SLOT(wantUploadDataSlot(qint64))); QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)), this, SLOT(sentUploadDataSlot(qint64))); connect(forwardUploadDevice, SIGNAL(resetData(bool*)), this, SLOT(resetUploadDataSlot(bool*)), Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued! } } else if (isSynchronous()) {