using System; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Runtime.Serialization; using Octokit.Internal; namespace Octokit { /// /// Represents errors that occur from the GitHub API. /// #if !NETFX_CORE [Serializable] #endif [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "These exceptions are specific to the GitHub API and not general purpose exceptions")] public class ApiException : Exception { // This needs to be hard-coded for translating GitHub error messages. static readonly IJsonSerializer _jsonSerializer = new SimpleJsonSerializer(); /// /// Constructs an instance of ApiException /// public ApiException() : this(new Response()) { } /// /// Constructs an instance of ApiException /// /// The error message /// The HTTP status code from the response public ApiException(string message, HttpStatusCode httpStatusCode) : this(GetApiErrorFromExceptionMessage(message), httpStatusCode, null) { } /// /// Constructs an instance of ApiException /// /// The error message /// The inner exception public ApiException(string message, Exception innerException) : this(GetApiErrorFromExceptionMessage(message), 0, innerException) { } /// /// Constructs an instance of ApiException /// /// The HTTP payload from the server public ApiException(IResponse response) : this(response, null) { } /// /// Constructs an instance of ApiException /// /// The HTTP payload from the server /// The inner exception public ApiException(IResponse response, Exception innerException) : base(null, innerException) { Ensure.ArgumentNotNull(response, "response"); StatusCode = response.StatusCode; ApiError = GetApiErrorFromExceptionMessage(response); HttpResponse = response; } /// /// Constructs an instance of ApiException /// /// The inner exception protected ApiException(ApiException innerException) { Ensure.ArgumentNotNull(innerException, "innerException"); StatusCode = innerException.StatusCode; ApiError = innerException.ApiError; } protected ApiException(HttpStatusCode statusCode, Exception innerException) : base(null, innerException) { ApiError = new ApiError(); StatusCode = statusCode; } protected ApiException(ApiError apiError, HttpStatusCode statusCode, Exception innerException) : base(null, innerException) { Ensure.ArgumentNotNull(apiError, "apiError"); ApiError = apiError; StatusCode = statusCode; } public IResponse HttpResponse { get; private set; } public override string Message { get { return ApiErrorMessageSafe ?? "An error occurred with this API request"; } } /// /// The HTTP status code associated with the repsonse /// public HttpStatusCode StatusCode { get; private set; } /// /// The raw exception payload from the response /// public ApiError ApiError { get; private set; } static ApiError GetApiErrorFromExceptionMessage(IResponse response) { string responseBody = response != null ? response.Body as string : null; return GetApiErrorFromExceptionMessage(responseBody); } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] static ApiError GetApiErrorFromExceptionMessage(string responseContent) { try { if (!string.IsNullOrEmpty(responseContent)) { return _jsonSerializer.Deserialize(responseContent) ?? new ApiError(responseContent); } } catch (Exception) { } return new ApiError(responseContent); } #if !NETFX_CORE /// /// Constructs an instance of ApiException. /// /// /// The that holds the /// serialized object data about the exception being thrown. /// /// /// The that contains /// contextual information about the source or destination. /// protected ApiException(SerializationInfo info, StreamingContext context) : base(info, context) { if (info == null) return; StatusCode = (HttpStatusCode)(info.GetInt32("HttpStatusCode")); ApiError = (ApiError)(info.GetValue("ApiError", typeof(ApiError))); } public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("HttpStatusCode", StatusCode); info.AddValue("ApiError", ApiError); } #endif /// /// Get the inner error message from the API response /// /// /// Returns null if ApiError is not populated /// protected string ApiErrorMessageSafe { get { return ApiError != null ? ApiError.Message : null; } } /// /// Get the inner http response body from the API response /// /// /// Returns empty string if HttpResponse is not populated or if /// response body is not a string /// protected string HttpResponseBodySafe { get { return HttpResponse != null && !HttpResponse.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase) && HttpResponse.Body is string ? (string)HttpResponse.Body : string.Empty; } } public override string ToString() { var original = base.ToString(); return original + Environment.NewLine + HttpResponseBodySafe ; } } }