NSUrlConnection backend for QNetworkAccessManager
Add support for QNetworkAccessManager https REST on iOS, without adding a dependency on OpenSSL. The current limitations are: - Overriding server certificate trust issues (for example expired certificates) is not supported. - Usage on non-gui threads is not supported. NSurlConnection needs a CoreFoundation-based event loop, which Qt currently only provides when using QGuiApplication on the main thread. Change-Id: Ic6f74591d40c3b2248ab81db12647e432377cd4f Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
This commit is contained in:
parent
2d1bb6d61d
commit
fbcad545ce
@ -64,6 +64,14 @@ SOURCES += \
|
||||
access/qhttpthreaddelegate.cpp \
|
||||
access/qhttpmultipart.cpp
|
||||
|
||||
include($$PWD/../../3rdparty/zlib_dependency.pri)
|
||||
mac: LIBS_PRIVATE += -framework Security
|
||||
|
||||
mac:LIBS_PRIVATE += -framework Security
|
||||
ios {
|
||||
HEADERS += \
|
||||
access/qnetworkreplynsurlconnectionimpl_p.h
|
||||
|
||||
OBJECTIVE_SOURCES += \
|
||||
access/qnetworkreplynsurlconnectionimpl.mm
|
||||
}
|
||||
|
||||
include($$PWD/../../3rdparty/zlib_dependency.pri)
|
||||
|
@ -58,6 +58,10 @@
|
||||
#include "qnetworkreplydataimpl_p.h"
|
||||
#include "qnetworkreplyfileimpl_p.h"
|
||||
|
||||
#if defined(Q_OS_IOS) && defined(QT_NO_SSL)
|
||||
#include "qnetworkreplynsurlconnectionimpl_p.h"
|
||||
#endif
|
||||
|
||||
#include "QtCore/qbuffer.h"
|
||||
#include "QtCore/qurl.h"
|
||||
#include "QtCore/qvector.h"
|
||||
@ -1159,6 +1163,12 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
|
||||
}
|
||||
}
|
||||
|
||||
// Use NSURLConnection for https on iOS when OpenSSL is disabled.
|
||||
#if defined(Q_OS_IOS) && defined(QT_NO_SSL)
|
||||
if (scheme == QLatin1String("https"))
|
||||
return new QNetworkReplyNSURLConnectionImpl(this, request, op, outgoingData);
|
||||
#endif
|
||||
|
||||
#ifndef QT_NO_HTTP
|
||||
// Since Qt 5 we use the new QNetworkReplyHttpImpl
|
||||
if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http")
|
||||
|
449
src/network/access/qnetworkreplynsurlconnectionimpl.mm
Normal file
449
src/network/access/qnetworkreplynsurlconnectionimpl.mm
Normal file
@ -0,0 +1,449 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qnetworkreplynsurlconnectionimpl_p.h"
|
||||
|
||||
#include "QtCore/qdatetime.h"
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// Network reply implementation using NSUrlConnection.
|
||||
//
|
||||
// Class/object structure:
|
||||
//
|
||||
// QNetworkReplyNSURLConnectionImpl
|
||||
// |- QNetworkReplyNSURLConnectionImplPrivate
|
||||
// |- (bytes read)
|
||||
// |- (QIODevice and CFStream for async POST data transfer)
|
||||
// |- NSURLConnection
|
||||
// |- QtNSURLConnectionDelegate <NSURLConnectionDataDelegate>
|
||||
// |- NSURLResponse/NSHTTPURLResponse
|
||||
// |- (response data)
|
||||
//
|
||||
// The main entry point is the QNetworkReplyNSURLConnectionImpl constructor, which
|
||||
// receives a network request from QNetworkAccessManager. The constructor
|
||||
// creates a NSURLRequest and initiates a NSURLConnection with a QtNSURLConnectionDelegate.
|
||||
// The delegate callbacks are then called asynchronously as the request completes.
|
||||
//
|
||||
|
||||
@class QtNSURLConnectionDelegate;
|
||||
class QNetworkReplyNSURLConnectionImplPrivate: public QNetworkReplyPrivate
|
||||
{
|
||||
public:
|
||||
QNetworkReplyNSURLConnectionImplPrivate();
|
||||
virtual ~QNetworkReplyNSURLConnectionImplPrivate();
|
||||
|
||||
Q_DECLARE_PUBLIC(QNetworkReplyNSURLConnectionImpl)
|
||||
NSURLConnection * urlConnection;
|
||||
QtNSURLConnectionDelegate *urlConnectionDelegate;
|
||||
qint64 bytesRead;
|
||||
|
||||
// Sequental outgiong data streaming
|
||||
QIODevice *outgoingData;
|
||||
CFReadStreamRef readStream;
|
||||
CFWriteStreamRef writeStream;
|
||||
CFIndex transferBufferSize;
|
||||
|
||||
// Forwarding functions to the public class.
|
||||
void setFinished();
|
||||
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
|
||||
void setRawHeader(const QByteArray &headerName, const QByteArray &value);
|
||||
void setError(QNetworkReply::NetworkError errorCode, const QString &errorString);
|
||||
};
|
||||
|
||||
@interface QtNSURLConnectionDelegate : NSObject
|
||||
{
|
||||
NSURLResponse *response;
|
||||
NSMutableData *responseData;
|
||||
QNetworkReplyNSURLConnectionImplPrivate * replyprivate;
|
||||
}
|
||||
|
||||
- (id)initWithQNetworkReplyNSURLConnectionImplPrivate:(QNetworkReplyNSURLConnectionImplPrivate *)a_replyPrivate ;
|
||||
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_3_0)
|
||||
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
|
||||
#endif
|
||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError*)error;
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response;
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data;
|
||||
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten
|
||||
totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
|
||||
- (NSCachedURLResponse*)connection:(NSURLConnection*)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse;
|
||||
- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse;
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection*)connection;
|
||||
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection*)connection;
|
||||
|
||||
@end
|
||||
|
||||
QNetworkReplyNSURLConnectionImplPrivate::QNetworkReplyNSURLConnectionImplPrivate()
|
||||
: QNetworkReplyPrivate()
|
||||
, urlConnection(0)
|
||||
, urlConnectionDelegate(0)
|
||||
, bytesRead(0)
|
||||
, readStream(0)
|
||||
, writeStream(0)
|
||||
, transferBufferSize(4096)
|
||||
{
|
||||
}
|
||||
|
||||
QNetworkReplyNSURLConnectionImplPrivate::~QNetworkReplyNSURLConnectionImplPrivate()
|
||||
{
|
||||
[urlConnection release];
|
||||
[urlConnectionDelegate release];
|
||||
if (readStream)
|
||||
CFRelease(readStream);
|
||||
if (writeStream)
|
||||
CFRelease(writeStream);
|
||||
}
|
||||
|
||||
void QNetworkReplyNSURLConnectionImplPrivate::setFinished()
|
||||
{
|
||||
q_func()->setFinished(true);
|
||||
}
|
||||
|
||||
void QNetworkReplyNSURLConnectionImplPrivate::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
|
||||
{
|
||||
q_func()->setHeader(header, value);
|
||||
}
|
||||
|
||||
void QNetworkReplyNSURLConnectionImplPrivate::setRawHeader(const QByteArray &headerName, const QByteArray &value)
|
||||
{
|
||||
q_func()->setRawHeader(headerName, value);
|
||||
}
|
||||
|
||||
void QNetworkReplyNSURLConnectionImplPrivate::setError(QNetworkReply::NetworkError errorCode, const QString &errorString)
|
||||
{
|
||||
q_func()->setError(errorCode, errorString);
|
||||
}
|
||||
|
||||
void QNetworkReplyNSURLConnectionImpl::readyReadOutgoingData()
|
||||
{
|
||||
Q_D(QNetworkReplyNSURLConnectionImpl);
|
||||
int bytesRead = 0;
|
||||
do {
|
||||
char data[d->transferBufferSize];
|
||||
bytesRead = d->outgoingData->read(data, d->transferBufferSize);
|
||||
if (bytesRead <= 0)
|
||||
break;
|
||||
CFIndex bytesWritten = CFWriteStreamWrite(d->writeStream, reinterpret_cast<unsigned char *>(data), bytesRead);
|
||||
if (bytesWritten != bytesRead) {
|
||||
CFErrorRef err = CFWriteStreamCopyError(d->writeStream);
|
||||
qWarning() << "QNetworkReplyNSURLConnectionImpl: CFWriteStreamWrite error"
|
||||
<< (err ? QString::number(CFErrorGetCode(err)) : QStringLiteral(""));
|
||||
}
|
||||
} while (bytesRead > 0);
|
||||
|
||||
if (d->outgoingData->atEnd())
|
||||
CFWriteStreamClose(d->writeStream);
|
||||
}
|
||||
|
||||
@interface QtNSURLConnectionDelegate ()
|
||||
|
||||
@property (nonatomic, retain) NSURLResponse* response;
|
||||
@property (nonatomic, retain) NSMutableData* responseData;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QtNSURLConnectionDelegate
|
||||
|
||||
@synthesize response;
|
||||
@synthesize responseData;
|
||||
|
||||
- (id)initWithQNetworkReplyNSURLConnectionImplPrivate:(QNetworkReplyNSURLConnectionImplPrivate *)a_replyPrivate
|
||||
{
|
||||
if (self = [super init])
|
||||
replyprivate = a_replyPrivate;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[response release];
|
||||
[responseData release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_3_0)
|
||||
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
Q_UNUSED(challenge)
|
||||
|
||||
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
|
||||
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
|
||||
SecTrustResultType resultType;
|
||||
SecTrustEvaluate(serverTrust, &resultType);
|
||||
if (resultType == kSecTrustResultUnspecified) {
|
||||
// All good
|
||||
[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
|
||||
} else if (resultType == kSecTrustResultRecoverableTrustFailure) {
|
||||
// Certificate verification error, ask user
|
||||
// ### TODO actually ask user
|
||||
// (test site: https://testssl-expire.disig.sk/index.en.html)
|
||||
qWarning() << "QNetworkReplyNSURLConnection: Certificate verification error handlig is"
|
||||
<< "not implemented. Connection will time out.";
|
||||
} else {
|
||||
// other error, which the default handler will handle
|
||||
[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
|
||||
}
|
||||
}
|
||||
|
||||
[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
|
||||
QNetworkReply::NetworkError qtError = QNetworkReply::UnknownNetworkError;
|
||||
if ([error domain] == NSURLErrorDomain) {
|
||||
switch ([error code]) {
|
||||
case NSURLErrorTimedOut: qtError = QNetworkReply::TimeoutError; break;
|
||||
case NSURLErrorUnsupportedURL: qtError = QNetworkReply::ProtocolUnknownError; break;
|
||||
case NSURLErrorCannotFindHost: qtError = QNetworkReply::HostNotFoundError; break;
|
||||
case NSURLErrorCannotConnectToHost: qtError = QNetworkReply::ConnectionRefusedError; break;
|
||||
case NSURLErrorNetworkConnectionLost: qtError = QNetworkReply::NetworkSessionFailedError; break;
|
||||
case NSURLErrorDNSLookupFailed: qtError = QNetworkReply::HostNotFoundError; break;
|
||||
case NSURLErrorNotConnectedToInternet: qtError = QNetworkReply::NetworkSessionFailedError; break;
|
||||
case NSURLErrorUserAuthenticationRequired: qtError = QNetworkReply::AuthenticationRequiredError; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
replyprivate->setError(qtError, QString::fromNSString([error localizedDescription]));
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)aResponse
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
self.response = aResponse;
|
||||
self.responseData = [NSMutableData data];
|
||||
|
||||
// copy headers
|
||||
if ([aResponse isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)aResponse;
|
||||
NSDictionary *headers = [httpResponse allHeaderFields];
|
||||
for (NSString *key in headers) {
|
||||
NSString *value = [headers objectForKey:key];
|
||||
replyprivate->setRawHeader(QString::fromNSString(key).toUtf8(), QString::fromNSString(value).toUtf8());
|
||||
}
|
||||
} else {
|
||||
if ([aResponse expectedContentLength] != NSURLResponseUnknownLength)
|
||||
replyprivate->setHeader(QNetworkRequest::ContentLengthHeader, [aResponse expectedContentLength]);
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(replyprivate->q_func(), "metaDataChanged", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
[responseData appendData:data];
|
||||
|
||||
if ([response expectedContentLength] != NSURLResponseUnknownLength) {
|
||||
QMetaObject::invokeMethod(replyprivate->q_func(), "downloadProgress", Qt::QueuedConnection,
|
||||
Q_ARG(qint64, qint64([responseData length])),
|
||||
Q_ARG(qint64, qint64([response expectedContentLength])));
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(replyprivate->q_func(), "readyRead", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection*)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten
|
||||
totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
Q_UNUSED(bytesWritten)
|
||||
QMetaObject::invokeMethod(replyprivate->q_func(), "uploadProgress", Qt::QueuedConnection,
|
||||
Q_ARG(qint64, qint64(totalBytesWritten)),
|
||||
Q_ARG(qint64, qint64(totalBytesExpectedToWrite)));
|
||||
}
|
||||
|
||||
- (NSCachedURLResponse*)connection:(NSURLConnection*)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
Q_UNUSED(redirectResponse)
|
||||
return request;
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
replyprivate->setFinished();
|
||||
QMetaObject::invokeMethod(replyprivate->q_func(), "finished", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection*)connection
|
||||
{
|
||||
Q_UNUSED(connection)
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
QNetworkReplyNSURLConnectionImpl::~QNetworkReplyNSURLConnectionImpl()
|
||||
{
|
||||
}
|
||||
|
||||
QNetworkReplyNSURLConnectionImpl::QNetworkReplyNSURLConnectionImpl(QObject *parent,
|
||||
const QNetworkRequest &request, const QNetworkAccessManager::Operation operation, QIODevice* outgoingData)
|
||||
: QNetworkReply(*new QNetworkReplyNSURLConnectionImplPrivate(), parent)
|
||||
{
|
||||
setRequest(request);
|
||||
setUrl(request.url());
|
||||
setOperation(operation);
|
||||
QNetworkReply::open(QIODevice::ReadOnly);
|
||||
|
||||
QNetworkReplyNSURLConnectionImplPrivate *d = (QNetworkReplyNSURLConnectionImplPrivate*) d_func();
|
||||
|
||||
QUrl url = request.url();
|
||||
if (url.host() == QLatin1String("localhost"))
|
||||
url.setHost(QString());
|
||||
|
||||
if (url.path().isEmpty())
|
||||
url.setPath(QLatin1String("/"));
|
||||
setUrl(url);
|
||||
|
||||
// Create a NSMutableURLRequest from QNetworkRequest
|
||||
NSMutableURLRequest *nsRequest = [NSMutableURLRequest requestWithURL:request.url().toNSURL()
|
||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval:60.0];
|
||||
// copy headers
|
||||
foreach (const QByteArray &header, request.rawHeaderList()) {
|
||||
QByteArray headerValue = request.rawHeader(header);
|
||||
[nsRequest addValue:QString::fromUtf8(headerValue).toNSString()
|
||||
forHTTPHeaderField:QString::fromUtf8(header).toNSString()];
|
||||
}
|
||||
|
||||
if (operation == QNetworkAccessManager::GetOperation)
|
||||
[nsRequest setHTTPMethod:@"GET"];
|
||||
else if (operation == QNetworkAccessManager::PostOperation)
|
||||
[nsRequest setHTTPMethod:@"POST"];
|
||||
else if (operation == QNetworkAccessManager::PutOperation)
|
||||
[nsRequest setHTTPMethod:@"PUT"];
|
||||
else if (operation == QNetworkAccessManager::DeleteOperation)
|
||||
[nsRequest setHTTPMethod:@"DELETE"];
|
||||
else
|
||||
qWarning() << "QNetworkReplyNSURLConnection: Unsupported netork operation" << operation;
|
||||
|
||||
if (outgoingData) {
|
||||
d->outgoingData = outgoingData;
|
||||
if (outgoingData->isSequential()) {
|
||||
// set up streaming from outgoingData iodevice to request
|
||||
CFStreamCreateBoundPair(kCFAllocatorDefault, &d->readStream, &d->writeStream, d->transferBufferSize);
|
||||
CFWriteStreamOpen(d->writeStream);
|
||||
[nsRequest setHTTPBodyStream:reinterpret_cast<NSInputStream *>(d->readStream)];
|
||||
connect(outgoingData, SIGNAL(readyRead()), this, SLOT(readyReadOutgoingData()));
|
||||
readyReadOutgoingData();
|
||||
} else {
|
||||
// move all data at once
|
||||
QByteArray data = outgoingData->readAll();
|
||||
[nsRequest setHTTPBody:[NSData dataWithBytes:data.constData() length:data.length()]];
|
||||
}
|
||||
}
|
||||
|
||||
// Create connection
|
||||
d->urlConnectionDelegate = [[QtNSURLConnectionDelegate alloc] initWithQNetworkReplyNSURLConnectionImplPrivate:d];
|
||||
d->urlConnection = [[NSURLConnection alloc] initWithRequest:nsRequest delegate:d->urlConnectionDelegate];
|
||||
if (!d->urlConnection) {
|
||||
// ### what type of error is an initWithRequest fail?
|
||||
setError(QNetworkReply::ProtocolUnknownError, QStringLiteral("QNetworkReplyNSURLConnection internal error"));
|
||||
}
|
||||
}
|
||||
|
||||
void QNetworkReplyNSURLConnectionImpl::close()
|
||||
{
|
||||
// No-op? Network ops should continue (especially POSTs)
|
||||
QNetworkReply::close();
|
||||
}
|
||||
|
||||
void QNetworkReplyNSURLConnectionImpl::abort()
|
||||
{
|
||||
Q_D(QNetworkReplyNSURLConnectionImpl);
|
||||
[d->urlConnection cancel];
|
||||
QNetworkReply::close();
|
||||
}
|
||||
|
||||
qint64 QNetworkReplyNSURLConnectionImpl::bytesAvailable() const
|
||||
{
|
||||
Q_D(const QNetworkReplyNSURLConnectionImpl);
|
||||
qint64 available = QNetworkReply::bytesAvailable() +
|
||||
[[d->urlConnectionDelegate responseData] length] -
|
||||
d->bytesRead;
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
bool QNetworkReplyNSURLConnectionImpl::isSequential() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
qint64 QNetworkReplyNSURLConnectionImpl::size() const
|
||||
{
|
||||
Q_D(const QNetworkReplyNSURLConnectionImpl);
|
||||
return [[d->urlConnectionDelegate responseData] length];
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
qint64 QNetworkReplyNSURLConnectionImpl::readData(char *data, qint64 maxlen)
|
||||
{
|
||||
Q_D(QNetworkReplyNSURLConnectionImpl);
|
||||
qint64 dataSize = [[d->urlConnectionDelegate responseData] length];
|
||||
qint64 canRead = qMin(maxlen, dataSize - d->bytesRead);
|
||||
const char *sourceBase = static_cast<const char *>([[d->urlConnectionDelegate responseData] bytes]);
|
||||
memcpy(data, sourceBase + d->bytesRead, canRead);
|
||||
d->bytesRead += canRead;
|
||||
return canRead;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
89
src/network/access/qnetworkreplynsurlconnectionimpl_p.h
Normal file
89
src/network/access/qnetworkreplynsurlconnectionimpl_p.h
Normal file
@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QNETWORKREPLYNSURLCONNECTIONIMPL_H
|
||||
#define QNETWORKREPLYNSURLCONNECTIONIMPL_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of the Network Access API. This header file may change from
|
||||
// version to version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "qnetworkreply.h"
|
||||
#include "qnetworkreply_p.h"
|
||||
#include "qnetworkaccessmanager.h"
|
||||
#include <QFile>
|
||||
#include <private/qabstractfileengine_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
class QNetworkReplyNSURLConnectionImplPrivate;
|
||||
class QNetworkReplyNSURLConnectionImpl: public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QNetworkReplyNSURLConnectionImpl(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op, QIODevice* outgoingData);
|
||||
virtual ~QNetworkReplyNSURLConnectionImpl();
|
||||
virtual void abort();
|
||||
|
||||
// reimplemented from QNetworkReply
|
||||
virtual void close();
|
||||
virtual qint64 bytesAvailable() const;
|
||||
virtual bool isSequential () const;
|
||||
qint64 size() const;
|
||||
|
||||
virtual qint64 readData(char *data, qint64 maxlen);
|
||||
public Q_SLOTS:
|
||||
void readyReadOutgoingData();
|
||||
|
||||
Q_DECLARE_PRIVATE(QNetworkReplyNSURLConnectionImpl)
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QNetworkReplyNSURLConnectionImpl_H
|
Loading…
Reference in New Issue
Block a user