diff --git a/docs/user/netservices/NetServicesDefs.dox b/docs/user/netservices/NetServicesDefs.dox index f6ea6a2541..767822ba59 100644 --- a/docs/user/netservices/NetServicesDefs.dox +++ b/docs/user/netservices/NetServicesDefs.dox @@ -212,15 +212,31 @@ namespace Network { /*! \fn BNetworkRequestError::BNetworkRequestError(const char *origin, ErrorType type, - status_t errorCode=B_OK) + status_t errorCode, const BString& customMessage = BString()) \brief Create a new network request error. \param origin A string representing where this error occured. It is advised to initialize it to \c __PRETTY_FUNCTION__ by default. \param type The error type that describes what the issue was that prevented the completion of the request. - \param errorCode Optional underlying system error. See the \ref BNetworkRequestError::ErrorType + \param errorCode The underlying system error. See the \ref BNetworkRequestError::ErrorType documentation on which error types expect a system error. + \param customMessage Optional custom message describing the reason or cause for the error. + + \since Haiku R1 +*/ + + +/*! + \fn BNetworkRequestError::BNetworkRequestError(const char *origin, ErrorType type, + const BString& customMessage = BString()) + \brief Create a new network request error. + + \param origin A string representing where this error occured. It is advised + to initialize it to \c __PRETTY_FUNCTION__ by default. + \param type The error type that describes what the issue was that prevented the completion of + the request. + \param customMessage Optional custom message describing the reason or cause for the error. \since Haiku R1 */ @@ -248,6 +264,16 @@ namespace Network { */ +/*! + \fn const char* BNetworkRequestError::CustomMessage() const noexcept + \brief Get the custom error message. + + \return Get the custom error message. This may be an empty string if it was not set. + + \since Haiku R1 +*/ + + /*! \fn BString encode_to_base64(const BString& string) \brief Utility function that encodes a \a string to base64 and returns the result. diff --git a/headers/private/netservices2/NetServicesDefs.h b/headers/private/netservices2/NetServicesDefs.h index 62202cb712..8e3f2f4854 100644 --- a/headers/private/netservices2/NetServicesDefs.h +++ b/headers/private/netservices2/NetServicesDefs.h @@ -61,7 +61,9 @@ public: }; BNetworkRequestError(const char* origin, ErrorType type, - status_t errorCode = B_OK); + status_t errorCode, const BString& customMessage = BString()); + BNetworkRequestError(const char* origin, ErrorType type, + const BString& customMessage = BString()); virtual const char* Message() const noexcept override; virtual BString DebugMessage() const override; @@ -69,9 +71,12 @@ public: ErrorType Type() const noexcept; status_t ErrorCode() const noexcept; + const char* CustomMessage() const noexcept; + private: ErrorType fErrorType; status_t fErrorCode = B_OK; + BString fCustomMessage; }; diff --git a/src/kits/network/libnetservices2/HttpBuffer.cpp b/src/kits/network/libnetservices2/HttpBuffer.cpp index c0cb8123c8..f737082dbc 100644 --- a/src/kits/network/libnetservices2/HttpBuffer.cpp +++ b/src/kits/network/libnetservices2/HttpBuffer.cpp @@ -204,8 +204,10 @@ HttpBuffer::Data() const noexcept HttpBuffer& HttpBuffer::operator<<(const std::string_view& data) { - if (data.size() > (fBuffer.capacity() - fBuffer.size())) - throw BNetworkRequestError(__PRETTY_FUNCTION__, BNetworkRequestError::ProtocolError); + if (data.size() > (fBuffer.capacity() - fBuffer.size())) { + throw BNetworkRequestError(__PRETTY_FUNCTION__, BNetworkRequestError::ProtocolError, + "No capacity left in buffer to append data."); + } for (const auto& character: data) fBuffer.push_back(static_cast(character)); diff --git a/src/kits/network/libnetservices2/HttpSession.cpp b/src/kits/network/libnetservices2/HttpSession.cpp index 1181f710de..511df6233d 100644 --- a/src/kits/network/libnetservices2/HttpSession.cpp +++ b/src/kits/network/libnetservices2/HttpSession.cpp @@ -954,13 +954,18 @@ BHttpSession::Request::ReceiveResult() auto locationField = fFields.FindField("Location"); if (locationField == fFields.end()) { throw BNetworkRequestError(__PRETTY_FUNCTION__, - BNetworkRequestError::ProtocolError); + BNetworkRequestError::ProtocolError, + "Redirect; the Location field must be present and cannot be found"); } auto locationString = BString((*locationField).Value().data(), (*locationField).Value().size()); - auto redirect = BHttpSession::Redirect{BUrl(fRequest.Url(), locationString), redirectToGet}; - if (!redirect.url.IsValid()) - throw BNetworkRequestError(__PRETTY_FUNCTION__, BNetworkRequestError::ProtocolError); + auto redirect = + BHttpSession::Redirect{BUrl(fRequest.Url(), locationString), redirectToGet}; + if (!redirect.url.IsValid()) { + throw BNetworkRequestError(__PRETTY_FUNCTION__, + BNetworkRequestError::ProtocolError, + "Redirect; invalid URL in the Location field"); + } // Notify of redirect SendMessage(UrlEvent::HttpRedirect, [&locationString](BMessage& msg) { @@ -1009,12 +1014,16 @@ BHttpSession::Request::ReceiveResult() fNoContent = true; fParser.SetContentLength(bodyBytesTotal); } catch (const std::logic_error& e) { - throw BNetworkRequestError(__PRETTY_FUNCTION__, BNetworkRequestError::ProtocolError); + throw BNetworkRequestError(__PRETTY_FUNCTION__, + BNetworkRequestError::ProtocolError, + "Cannot parse Content-Length field value (logic_error)"); } } - if (bodyBytesTotal == std::nullopt) - throw BNetworkRequestError(__PRETTY_FUNCTION__, BNetworkRequestError::ProtocolError); + if (bodyBytesTotal == std::nullopt) { + throw BNetworkRequestError(__PRETTY_FUNCTION__, + BNetworkRequestError::ProtocolError, "Expected Content-Length field"); + } } // Move headers to the result and inform listener diff --git a/src/kits/network/libnetservices2/NetServicesMisc.cpp b/src/kits/network/libnetservices2/NetServicesMisc.cpp index b6e626eb92..2d29655a7f 100644 --- a/src/kits/network/libnetservices2/NetServicesMisc.cpp +++ b/src/kits/network/libnetservices2/NetServicesMisc.cpp @@ -98,8 +98,17 @@ BInvalidUrl::Url() const // #pragma mark -- BNetworkRequestError -BNetworkRequestError::BNetworkRequestError(const char* origin, ErrorType type, status_t errorCode) - : BError(origin), fErrorType(type), fErrorCode(errorCode) +BNetworkRequestError::BNetworkRequestError(const char* origin, ErrorType type, status_t errorCode, + const BString& customMessage) + : BError(origin), fErrorType(type), fErrorCode(errorCode), fCustomMessage(customMessage) +{ + +} + + +BNetworkRequestError::BNetworkRequestError(const char* origin, ErrorType type, + const BString& customMessage) + : BError(origin), fErrorType(type), fCustomMessage(customMessage) { } @@ -134,6 +143,9 @@ BNetworkRequestError::DebugMessage() const debugMessage << "\n\tUnderlying System Error: " << fErrorCode << " (" << strerror(fErrorCode) << ")"; } + if (fCustomMessage.Length() > 0) { + debugMessage << "\n\tAdditional Info: " << fCustomMessage; + } return debugMessage; } @@ -152,6 +164,13 @@ BNetworkRequestError::ErrorCode() const noexcept } +const char* +BNetworkRequestError::CustomMessage() const noexcept +{ + return fCustomMessage.String(); +} + + // #pragma mark -- Public functions