BHttpRequest: propagate SSL errors to listener

This way it's possible to handle them in applications.
This commit is contained in:
Adrien Destugues
2014-11-06 15:02:00 +01:00
parent c86ad7f93b
commit 5ee2151e2c
7 changed files with 146 additions and 34 deletions
+7
View File
@@ -8,6 +8,7 @@
#include <deque>
#include <Certificate.h>
#include <HttpForm.h>
#include <HttpHeaders.h>
#include <HttpResult.h>
@@ -74,6 +75,12 @@ private:
void _SetResultStatusCode(int32 statusCode);
BString& _ResultStatusText();
// SSL failure management
friend class CheckedSecureSocket;
bool _CertificateVerificationFailed(
BCertificate& certificate,
const char* message);
// Utility methods
bool _IsDefaultPort();
@@ -26,7 +26,8 @@ enum {
B_URL_PROTOCOL_DATA_RECEIVED,
B_URL_PROTOCOL_DOWNLOAD_PROGRESS,
B_URL_PROTOCOL_UPLOAD_PROGRESS,
B_URL_PROTOCOL_REQUEST_COMPLETED
B_URL_PROTOCOL_REQUEST_COMPLETED,
B_URL_PROTOCOL_CERTIFICATE_VERIFICATION_FAILED
};
@@ -52,9 +53,13 @@ public:
ssize_t bytesSent, ssize_t bytesTotal);
virtual void RequestCompleted(BUrlRequest* caller,
bool success);
virtual bool CertificateVerificationFailed(
BUrlRequest* caller,
BCertificate& certificate,
const char* message);
private:
void _SendMessage(BMessage* message,
void _SendMessage(BMessage* message,
int8 notification, BUrlRequest* caller);
private:
+42 -27
View File
@@ -9,6 +9,8 @@
#include <stddef.h>
#include <cstdlib>
class BCertificate;
class BUrlRequest;
@@ -27,96 +29,109 @@ public:
/**
ConnectionOpened()
Frequency: Once
Called when the socket is opened.
Called when the socket is opened.
*/
virtual void ConnectionOpened(BUrlRequest* caller);
/**
HostnameResolved(ip)
Frequency: Once
Parameters: ip String representing the IP address of the resource
host.
Called when the final IP is discovered
Called when the final IP is discovered
*/
virtual void HostnameResolved(BUrlRequest* caller,
const char* ip);
/**
ReponseStarted()
Frequency: Once
Called when the request has been emitted and the server begins to
Called when the request has been emitted and the server begins to
reply. Typically when the HTTP status code is received.
*/
virtual void ResponseStarted(BUrlRequest* caller);
/**
HeadersReceived()
Frequency: Once
Called when all the server response metadata (such as headers) have
Called when all the server response metadata (such as headers) have
been read and parsed.
*/
virtual void HeadersReceived(BUrlRequest* caller);
/**
DataReceived(data, position, size)
Frequency: Zero or more
Parameters: data Pointer to the data block in memory
position Offset of the data in the stream
size Size of the data block
Called each time a full block of data is received.
size Size of the data block
Called each time a full block of data is received.
*/
virtual void DataReceived(BUrlRequest* caller,
const char* data, off_t position,
ssize_t size);
/**
DownloadProgress(bytesReceived, bytesTotal)
Frequency: Once or more
Parameters: bytesReceived Number of data bytes received
bytesTotal Total number of data bytes expected
Called each time a data block is received.
Called each time a data block is received.
*/
virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal);
/**
UploadProgress(bytesSent, bytesTotal)
Frequency: Once or more
Parameters: bytesSent Number of data bytes sent
bytesTotal Total number of data bytes expected
Called each time a data block is emitted.
Called each time a data block is emitted.
*/
virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal);
/**
RequestCompleted(success)
Frequency: Once
Parameters: success true if the resource have been successfully
false if not
Called once the request is complete.
Called once the request is complete.
*/
virtual void RequestCompleted(BUrlRequest* caller,
bool success);
/**
DebugMessage(type, text)
Frequency: zero or more
Parameters: type Type of the verbose message (see BUrlProtocolDebug)
Called each time a debug message is emitted
Called each time a debug message is emitted
*/
virtual void DebugMessage(BUrlRequest* caller,
BUrlProtocolDebugMessage type,
const char* text);
/**
CertificateVerificationFailed(certificate, message)
Frequency: Once
Parameters: certificate SSL certificate which coulnd't be validated
message error message describing the problem
Return true to proceed anyway, false to abort the connection
*/
virtual bool CertificateVerificationFailed(
BUrlRequest* caller,
BCertificate& certificate,
const char* message);
};
#endif // _B_URL_PROTOCOL_LISTENER_H_
+49 -5
View File
@@ -19,6 +19,7 @@
#include <new>
#include <AutoDeleter.h>
#include <Certificate.h>
#include <Debug.h>
#include <DynamicBuffer.h>
#include <File.h>
@@ -31,6 +32,35 @@
static const int32 kHttpBufferSize = 4096;
class CheckedSecureSocket: public BSecureSocket
{
public:
CheckedSecureSocket(BHttpRequest* request);
bool CertificateVerificationFailed(BCertificate& certificate,
const char* message);
private:
BHttpRequest* fRequest;
};
CheckedSecureSocket::CheckedSecureSocket(BHttpRequest* request)
:
BSecureSocket(),
fRequest(request)
{
}
bool
CheckedSecureSocket::CertificateVerificationFailed(BCertificate& certificate,
const char* message)
{
return fRequest->_CertificateVerificationFailed(certificate, message);
}
BHttpRequest::BHttpRequest(const BUrl& url, bool ssl, const char* protocolName,
BUrlProtocolListener* listener, BUrlContext* context)
:
@@ -50,7 +80,7 @@ BHttpRequest::BHttpRequest(const BUrl& url, bool ssl, const char* protocolName,
{
_ResetOptions();
if (fSSL)
fSocket = new(std::nothrow) BSecureSocket();
fSocket = new(std::nothrow) CheckedSecureSocket(this);
else
fSocket = new(std::nothrow) BSocket();
}
@@ -76,7 +106,7 @@ BHttpRequest::BHttpRequest(const BHttpRequest& other)
_ResetOptions();
// FIXME some options may be copied from other instead.
if (fSSL)
fSocket = new(std::nothrow) BSecureSocket();
fSocket = new(std::nothrow) CheckedSecureSocket(this);
else
fSocket = new(std::nothrow) BSocket();
}
@@ -791,7 +821,7 @@ BHttpRequest::_SendHeaders()
BString host = Url().Host();
if (Url().HasPort() && !_IsDefaultPort())
host << ':' << Url().Port();
outputHeaders.AddHeader("Host", host);
outputHeaders.AddHeader("Accept", "*/*");
@@ -887,7 +917,7 @@ BHttpRequest::_SendHeaders()
break;
cookieString << "; ";
}
outputHeaders.AddHeader("Cookie", cookieString);
}
}
@@ -1022,7 +1052,21 @@ BHttpRequest::_ResultStatusText()
}
bool BHttpRequest::_IsDefaultPort()
bool
BHttpRequest::_CertificateVerificationFailed(BCertificate& certificate,
const char* message)
{
if (fListener != NULL) {
return fListener->CertificateVerificationFailed(this, certificate,
message);
}
return false;
}
bool
BHttpRequest::_IsDefaultPort()
{
if (fSSL && Url().Port() == 443)
return true;
@@ -142,6 +142,20 @@ BUrlProtocolAsynchronousListener::MessageReceived(BMessage* message)
}
break;
case B_URL_PROTOCOL_CERTIFICATE_VERIFICATION_FAILED:
{
const char* error = message->FindString("url:error");
BCertificate* certificate;
message->FindPointer("url:certificate", (void**)&certificate);
bool result = CertificateVerificationFailed(caller,
*certificate, error);
BMessage reply;
reply.AddBool("url:continue", result);
message->SendReply(&reply);
}
break;
default:
PRINT(("BUrlProtocolAsynchronousListener: Unknown notification %d\n",
notification));
@@ -125,6 +125,25 @@ BUrlProtocolDispatchingListener::RequestCompleted(BUrlRequest* caller,
}
bool
BUrlProtocolDispatchingListener::CertificateVerificationFailed(
BUrlRequest* caller, BCertificate& certificate, const char* error)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
message.AddString("url:error", error);
message.AddPointer("url:certificate", &certificate);
message.AddInt8(kUrlProtocolMessageType,
B_URL_PROTOCOL_CERTIFICATE_VERIFICATION_FAILED);
message.AddPointer(kUrlProtocolCaller, caller);
// Warning: synchronous reply
BMessage reply;
fMessenger.SendMessage(&message, &reply);
return reply.FindBool("url:continue");
}
void
BUrlProtocolDispatchingListener::_SendMessage(BMessage* message,
int8 notification, BUrlRequest* caller)
@@ -27,6 +27,14 @@ BUrlProtocolListener::HostnameResolved(BUrlRequest*, const char*)
}
bool
BUrlProtocolListener::CertificateVerificationFailed(BUrlRequest* caller,
BCertificate& certificate, const char* message)
{
return false;
}
void
BUrlProtocolListener::ResponseStarted(BUrlRequest*)
{