using System;
using System.Diagnostics.CodeAnalysis;
using System.Net;
#if !NO_SERIALIZABLE
using System.Runtime.Serialization;
#endif
using System.Security;
using Octokit.Internal;
namespace Octokit
{
///
/// Represents errors that occur from the GitHub API.
///
#if !NO_SERIALIZABLE
[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, nameof(response));
StatusCode = response.StatusCode;
ApiError = GetApiErrorFromExceptionMessage(response);
HttpResponse = response;
}
///
/// Constructs an instance of ApiException
///
/// The inner exception
protected ApiException(ApiException innerException)
{
Ensure.ArgumentNotNull(innerException, nameof(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, nameof(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 response
///
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 !NO_SERIALIZABLE
///
/// 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));
}
[SecurityCritical]
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
{
if (ApiError != null && !string.IsNullOrWhiteSpace(ApiError.Message))
{
return ApiError.Message;
}
return 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;
}
}
}