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 <deque>
#include <Certificate.h>
#include <HttpForm.h> #include <HttpForm.h>
#include <HttpHeaders.h> #include <HttpHeaders.h>
#include <HttpResult.h> #include <HttpResult.h>
@@ -74,6 +75,12 @@ private:
void _SetResultStatusCode(int32 statusCode); void _SetResultStatusCode(int32 statusCode);
BString& _ResultStatusText(); BString& _ResultStatusText();
// SSL failure management
friend class CheckedSecureSocket;
bool _CertificateVerificationFailed(
BCertificate& certificate,
const char* message);
// Utility methods // Utility methods
bool _IsDefaultPort(); bool _IsDefaultPort();
@@ -26,7 +26,8 @@ enum {
B_URL_PROTOCOL_DATA_RECEIVED, B_URL_PROTOCOL_DATA_RECEIVED,
B_URL_PROTOCOL_DOWNLOAD_PROGRESS, B_URL_PROTOCOL_DOWNLOAD_PROGRESS,
B_URL_PROTOCOL_UPLOAD_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); ssize_t bytesSent, ssize_t bytesTotal);
virtual void RequestCompleted(BUrlRequest* caller, virtual void RequestCompleted(BUrlRequest* caller,
bool success); bool success);
virtual bool CertificateVerificationFailed(
BUrlRequest* caller,
BCertificate& certificate,
const char* message);
private: private:
void _SendMessage(BMessage* message, void _SendMessage(BMessage* message,
int8 notification, BUrlRequest* caller); int8 notification, BUrlRequest* caller);
private: private:
+42 -27
View File
@@ -9,6 +9,8 @@
#include <stddef.h> #include <stddef.h>
#include <cstdlib> #include <cstdlib>
class BCertificate;
class BUrlRequest; class BUrlRequest;
@@ -27,96 +29,109 @@ public:
/** /**
ConnectionOpened() ConnectionOpened()
Frequency: Once Frequency: Once
Called when the socket is opened. Called when the socket is opened.
*/ */
virtual void ConnectionOpened(BUrlRequest* caller); virtual void ConnectionOpened(BUrlRequest* caller);
/** /**
HostnameResolved(ip) HostnameResolved(ip)
Frequency: Once Frequency: Once
Parameters: ip String representing the IP address of the resource Parameters: ip String representing the IP address of the resource
host. host.
Called when the final IP is discovered Called when the final IP is discovered
*/ */
virtual void HostnameResolved(BUrlRequest* caller, virtual void HostnameResolved(BUrlRequest* caller,
const char* ip); const char* ip);
/** /**
ReponseStarted() ReponseStarted()
Frequency: Once 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. reply. Typically when the HTTP status code is received.
*/ */
virtual void ResponseStarted(BUrlRequest* caller); virtual void ResponseStarted(BUrlRequest* caller);
/** /**
HeadersReceived() HeadersReceived()
Frequency: Once 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. been read and parsed.
*/ */
virtual void HeadersReceived(BUrlRequest* caller); virtual void HeadersReceived(BUrlRequest* caller);
/** /**
DataReceived(data, position, size) DataReceived(data, position, size)
Frequency: Zero or more Frequency: Zero or more
Parameters: data Pointer to the data block in memory Parameters: data Pointer to the data block in memory
position Offset of the data in the stream position Offset of the data in the stream
size Size of the data block size Size of the data block
Called each time a full block of data is received. Called each time a full block of data is received.
*/ */
virtual void DataReceived(BUrlRequest* caller, virtual void DataReceived(BUrlRequest* caller,
const char* data, off_t position, const char* data, off_t position,
ssize_t size); ssize_t size);
/** /**
DownloadProgress(bytesReceived, bytesTotal) DownloadProgress(bytesReceived, bytesTotal)
Frequency: Once or more Frequency: Once or more
Parameters: bytesReceived Number of data bytes received Parameters: bytesReceived Number of data bytes received
bytesTotal Total number of data bytes expected 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, virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal); ssize_t bytesReceived, ssize_t bytesTotal);
/** /**
UploadProgress(bytesSent, bytesTotal) UploadProgress(bytesSent, bytesTotal)
Frequency: Once or more Frequency: Once or more
Parameters: bytesSent Number of data bytes sent Parameters: bytesSent Number of data bytes sent
bytesTotal Total number of data bytes expected 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, virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal); ssize_t bytesSent, ssize_t bytesTotal);
/** /**
RequestCompleted(success) RequestCompleted(success)
Frequency: Once Frequency: Once
Parameters: success true if the resource have been successfully Parameters: success true if the resource have been successfully
false if not false if not
Called once the request is complete. Called once the request is complete.
*/ */
virtual void RequestCompleted(BUrlRequest* caller, virtual void RequestCompleted(BUrlRequest* caller,
bool success); bool success);
/** /**
DebugMessage(type, text) DebugMessage(type, text)
Frequency: zero or more Frequency: zero or more
Parameters: type Type of the verbose message (see BUrlProtocolDebug) 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, virtual void DebugMessage(BUrlRequest* caller,
BUrlProtocolDebugMessage type, BUrlProtocolDebugMessage type,
const char* text); 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_ #endif // _B_URL_PROTOCOL_LISTENER_H_
+49 -5
View File
@@ -19,6 +19,7 @@
#include <new> #include <new>
#include <AutoDeleter.h> #include <AutoDeleter.h>
#include <Certificate.h>
#include <Debug.h> #include <Debug.h>
#include <DynamicBuffer.h> #include <DynamicBuffer.h>
#include <File.h> #include <File.h>
@@ -31,6 +32,35 @@
static const int32 kHttpBufferSize = 4096; 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, BHttpRequest::BHttpRequest(const BUrl& url, bool ssl, const char* protocolName,
BUrlProtocolListener* listener, BUrlContext* context) BUrlProtocolListener* listener, BUrlContext* context)
: :
@@ -50,7 +80,7 @@ BHttpRequest::BHttpRequest(const BUrl& url, bool ssl, const char* protocolName,
{ {
_ResetOptions(); _ResetOptions();
if (fSSL) if (fSSL)
fSocket = new(std::nothrow) BSecureSocket(); fSocket = new(std::nothrow) CheckedSecureSocket(this);
else else
fSocket = new(std::nothrow) BSocket(); fSocket = new(std::nothrow) BSocket();
} }
@@ -76,7 +106,7 @@ BHttpRequest::BHttpRequest(const BHttpRequest& other)
_ResetOptions(); _ResetOptions();
// FIXME some options may be copied from other instead. // FIXME some options may be copied from other instead.
if (fSSL) if (fSSL)
fSocket = new(std::nothrow) BSecureSocket(); fSocket = new(std::nothrow) CheckedSecureSocket(this);
else else
fSocket = new(std::nothrow) BSocket(); fSocket = new(std::nothrow) BSocket();
} }
@@ -791,7 +821,7 @@ BHttpRequest::_SendHeaders()
BString host = Url().Host(); BString host = Url().Host();
if (Url().HasPort() && !_IsDefaultPort()) if (Url().HasPort() && !_IsDefaultPort())
host << ':' << Url().Port(); host << ':' << Url().Port();
outputHeaders.AddHeader("Host", host); outputHeaders.AddHeader("Host", host);
outputHeaders.AddHeader("Accept", "*/*"); outputHeaders.AddHeader("Accept", "*/*");
@@ -887,7 +917,7 @@ BHttpRequest::_SendHeaders()
break; break;
cookieString << "; "; cookieString << "; ";
} }
outputHeaders.AddHeader("Cookie", 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) if (fSSL && Url().Port() == 443)
return true; return true;
@@ -142,6 +142,20 @@ BUrlProtocolAsynchronousListener::MessageReceived(BMessage* message)
} }
break; 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: default:
PRINT(("BUrlProtocolAsynchronousListener: Unknown notification %d\n", PRINT(("BUrlProtocolAsynchronousListener: Unknown notification %d\n",
notification)); 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 void
BUrlProtocolDispatchingListener::_SendMessage(BMessage* message, BUrlProtocolDispatchingListener::_SendMessage(BMessage* message,
int8 notification, BUrlRequest* caller) 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 void
BUrlProtocolListener::ResponseStarted(BUrlRequest*) BUrlProtocolListener::ResponseStarted(BUrlRequest*)
{ {