1 #include <zypp/zyppng/media/network/private/networkrequesterror_p.h>
2 #include <zypp/zyppng/media/network/request.h>
3 #include <zypp/media/CurlHelper.h>
4 #include <zypp/base/Gettext.h>
5 #include <zypp/media/MediaUserAuth.h>
10 ZYPP_IMPL_PRIVATE(NetworkRequestError);
12 NetworkRequestErrorPrivate::NetworkRequestErrorPrivate(NetworkRequestError::Type code, std::string &&msg, std::map<std::string, boost::any> &&extraInfo)
14 , _errorMessage( std::move(msg) )
15 , _extraInfo( std::move(extraInfo) )
18 NetworkRequestErrorPrivate *NetworkRequestErrorPrivate::clone() const
20 return new NetworkRequestErrorPrivate( *this );
23 NetworkRequestError NetworkRequestErrorPrivate::customError( NetworkRequestError::Type t, std::string &&errorMsg, std::map<std::string, boost::any> &&extraInfo )
25 return NetworkRequestError( *new NetworkRequestErrorPrivate(t, errorMsg.empty() ? typeToString(t) : std::move(errorMsg), std::move(extraInfo)) );
28 NetworkRequestError NetworkRequestErrorPrivate::fromCurlError( NetworkRequest &req, int nativeCode , const char *errBuf )
32 NetworkRequestError::Type c = NetworkRequestError::NoError;
34 std::map<std::string, boost::any> extraInfo;
36 if ( nativeCode != 0 ) {
38 const char *nativeErr = curl_easy_strerror( static_cast<CURLcode>(nativeCode) );
39 if ( nativeErr != nullptr )
40 extraInfo.insert( { "nativeErrorCodeDesc", std::string( nativeErr ) } );
42 if ( errBuf != nullptr )
43 extraInfo.insert( { "nativeErrorDesc", std::string( errBuf ) } );
45 extraInfo.insert( { "requestUrl", url } );
46 extraInfo.insert( { "curlCode", nativeCode } );
47 extraInfo.insert( { "filepath", req.targetFilePath().asString() } );
48 extraInfo.insert( { "lastRedirect", req.lastRedirectInfo() } );
52 case CURLE_UNSUPPORTED_PROTOCOL:
53 c = NetworkRequestError::UnsupportedProtocol;
54 err = typeToString( c );
55 if ( !req.lastRedirectInfo().empty() )
57 err += " or redirect (";
58 err += req.lastRedirectInfo();
62 case CURLE_URL_MALFORMAT: case CURLE_URL_MALFORMAT_USER:
63 c = NetworkRequestError::MalformedURL;
65 case CURLE_LOGIN_DENIED:
66 c = NetworkRequestError::Unauthorized;
68 case CURLE_HTTP_RETURNED_ERROR: {
69 long httpReturnCode = 0;
70 CURLcode infoRet = curl_easy_getinfo( req.nativeHandle(),
71 CURLINFO_RESPONSE_CODE,
74 if ( infoRet == CURLE_OK ) {
75 extraInfo.insert( { "responseCode", httpReturnCode } );
77 std::string msg = "HTTP response: " + zypp::str::numstring( httpReturnCode );
78 switch ( httpReturnCode )
81 std::string auth_hint;
83 long auth_info = CURLAUTH_NONE;
86 curl_easy_getinfo(req.nativeHandle(), CURLINFO_HTTPAUTH_AVAIL, &auth_info);
88 if(infoRet == CURLE_OK) {
89 extraInfo.insert( { "authHint", zypp::media::CurlAuthData::auth_type_long2str(auth_info) } );
93 //if there is already a user:password entry in the settings the auth simply failed
94 //@TODO write a testcase for this
95 if ( !req.transferSettings().userPassword().empty() ) {
96 c = NetworkRequestError::AuthFailed;
98 c = NetworkRequestError::Unauthorized;
104 case 502: // bad gateway (bnc #1070851)
105 case 503: // service temporarily unavailable (bnc #462545)
106 c = NetworkRequestError::TemporaryProblem;
107 err = zypp::str::form( _("Location '%s' is temporarily unaccessible."), url.asString().c_str() );
109 case 504: // gateway timeout
110 c = NetworkRequestError::Timeout;
111 err = zypp::str::form(_("Timeout exceeded when accessing '%s'."), url.asString().c_str() );
115 if ( url.getHost().find(".suse.com") != std::string::npos )
116 msg403 = _("Visit the SUSE Customer Center to check whether your registration is valid and has not expired.");
117 else if (url.asString().find("novell.com") != std::string::npos)
118 msg403 = _("Visit the Novell Customer Center to check whether your registration is valid and has not expired.");
120 c = NetworkRequestError::Forbidden;
126 c = NetworkRequestError::NotFound;
127 err = zypp::str::form( _("File '%s' not found on medium '%s'"), req.targetFilePath().c_str(), url.asString().c_str() );
131 c = NetworkRequestError::ServerReturnedError;
132 err = zypp::str::form(_("Download (curl) error for '%s':\n"
133 "Error code: %s\n"), url.asString().c_str(), zypp::str::numstring( httpReturnCode ).c_str() ) ;
137 c = NetworkRequestError::ServerReturnedError;
138 err = zypp::str::form(_("Download (curl) error for '%s':\n"
139 "Unable to retrieve HTTP response\n"), url.asString().c_str() ) ;
143 case CURLE_FTP_COULDNT_RETR_FILE:
144 #if CURLVERSION_AT_LEAST(7,16,0)
145 case CURLE_REMOTE_FILE_NOT_FOUND:
147 case CURLE_FTP_ACCESS_DENIED:
148 case CURLE_TFTP_NOTFOUND:
149 c = NetworkRequestError::NotFound;
151 case CURLE_BAD_PASSWORD_ENTERED:
152 case CURLE_FTP_USER_PASSWORD_INCORRECT:
153 c = NetworkRequestError::AuthFailed;
155 case CURLE_COULDNT_RESOLVE_PROXY:
156 case CURLE_COULDNT_RESOLVE_HOST:
157 case CURLE_COULDNT_CONNECT:
158 case CURLE_FTP_CANT_GET_HOST:
159 c = NetworkRequestError::ConnectionFailed;
161 case CURLE_WRITE_ERROR:
162 c = NetworkRequestError::InternalError;
164 case CURLE_PARTIAL_FILE:
165 case CURLE_OPERATION_TIMEDOUT:
166 c = NetworkRequestError::Timeout;
168 case CURLE_ABORTED_BY_CALLBACK:
169 c = NetworkRequestError::Cancelled;
171 case CURLE_PEER_FAILED_VERIFICATION:
172 c = NetworkRequestError::PeerCertificateInvalid;
175 c = NetworkRequestError::ServerReturnedError;
176 err = "Curl error " + zypp::str::numstring( nativeCode );
182 err = typeToString( c );
184 return NetworkRequestError( *new NetworkRequestErrorPrivate(c, std::move(err), std::move(extraInfo)) );
187 NetworkRequestError NetworkRequestErrorPrivate::fromCurlMError( int nativeCode )
189 const char *nativeErr = curl_multi_strerror( static_cast<CURLMcode>(nativeCode) );
191 std::map<std::string, boost::any> extraInfo;
192 extraInfo.insert( { "curlMCode", nativeCode } );
195 if ( nativeErr == nullptr )
196 err = "The dispatcher returned an unknown error";
198 err = std::string( nativeErr );
200 return NetworkRequestError( *new NetworkRequestErrorPrivate(NetworkRequestError::InternalError, std::move(err), std::move(extraInfo)) );
204 NetworkRequestError::NetworkRequestError(zyppng::NetworkRequestErrorPrivate &d )
208 NetworkRequestError::NetworkRequestError()
209 : d_ptr( new NetworkRequestErrorPrivate( NoError, {}, {} ) )
212 NetworkRequestError::Type NetworkRequestError::type() const
214 return d_func()->_errorCode;
217 std::string NetworkRequestError::toString() const
219 return d_func()->_errorMessage;
222 bool NetworkRequestError::isError() const
224 return d_func()->_errorCode != NoError;
227 const std::map<std::string, boost::any> &NetworkRequestError::extraInfo() const
229 return d_func()->_extraInfo;
232 std::string NetworkRequestErrorPrivate::typeToString( NetworkRequestError::Type t )
235 case NetworkRequestError::NoError:
237 case NetworkRequestError::InternalError:
238 return "Internal Error";
239 case NetworkRequestError::Cancelled:
240 return "The request was cancelled";
241 case NetworkRequestError::ExceededMaxLen:
242 return "The request exceeded the maximum download size";
243 case NetworkRequestError::InvalidChecksum:
244 return "The downloaded data did not result in a valid checksum";
245 case NetworkRequestError::PeerCertificateInvalid:
246 return "The peer certificate could not be verified";
247 case NetworkRequestError::ConnectionFailed:
248 return "Connection failed";
249 case NetworkRequestError::UnsupportedProtocol:
250 return "Unsupported protocol";
251 case NetworkRequestError::MalformedURL:
253 case NetworkRequestError::TemporaryProblem:
254 return "Requested location is temporarily unaccessible.";
255 case NetworkRequestError::Timeout:
256 return "Timeout reached";
257 case NetworkRequestError::Forbidden:
258 return "Access to requested URL is forbidden.";
259 case NetworkRequestError::NotFound:
260 return "File not found";
261 case NetworkRequestError::Unauthorized:
262 return "Authentication required but not provided.";
263 case NetworkRequestError::AuthFailed:
264 return "Login failed.";
265 case NetworkRequestError::ServerReturnedError:
266 return "Server returned an error for the given request.";
268 return std::string();
271 std::string NetworkRequestError::nativeErrorString() const
275 auto it = d->_extraInfo.find("nativeErrorDesc");
276 if ( it != d->_extraInfo.end() ) {
278 return boost::any_cast<std::string>( it->second );
279 } catch ( const boost::bad_any_cast &) { }
282 it = d->_extraInfo.find("nativeErrorCodeDesc");
283 if ( it != d->_extraInfo.end() ) {
285 return boost::any_cast<std::string>( it->second );
286 } catch ( const boost::bad_any_cast &) { }
289 return std::string();