using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Octokit.Internal;
namespace Octokit
{
// NOTE: Every request method must go through the `RunRequest` code path. So if you need to add a new method
// ensure it goes through there. :)
///
/// A connection for making HTTP requests against URI endpoints.
///
public class Connection : IConnection
{
static readonly Uri _defaultGitHubApiUrl = GitHubClient.GitHubApiUrl;
static readonly ICredentialStore _anonymousCredentials = new InMemoryCredentialStore(Credentials.Anonymous);
readonly Authenticator _authenticator;
readonly JsonHttpPipeline _jsonPipeline;
readonly IHttpClient _httpClient;
///
/// Creates a new connection instance used to make requests of the GitHub API.
///
///
/// The name (and optionally version) of the product using this library. This is sent to the server as part of
/// the user agent for analytics purposes.
///
public Connection(ProductHeaderValue productInformation)
: this(productInformation, _defaultGitHubApiUrl, _anonymousCredentials)
{
}
///
/// Creates a new connection instance used to make requests of the GitHub API.
///
///
/// The name (and optionally version) of the product using this library. This is sent to the server as part of
/// the user agent for analytics purposes.
///
///
/// The client to use for executing requests
///
public Connection(ProductHeaderValue productInformation, IHttpClient httpClient)
: this(productInformation, _defaultGitHubApiUrl, _anonymousCredentials, httpClient, new SimpleJsonSerializer())
{
}
///
/// Creates a new connection instance used to make requests of the GitHub API.
///
///
/// The name (and optionally version) of the product using this library. This is sent to the server as part of
/// the user agent for analytics purposes.
///
///
/// The address to point this client to such as https://api.github.com or the URL to a GitHub Enterprise
/// instance
public Connection(ProductHeaderValue productInformation, Uri baseAddress)
: this(productInformation, baseAddress, _anonymousCredentials)
{
}
///
/// Creates a new connection instance used to make requests of the GitHub API.
///
///
/// The name (and optionally version) of the product using this library. This is sent to the server as part of
/// the user agent for analytics purposes.
///
/// Provides credentials to the client when making requests
public Connection(ProductHeaderValue productInformation, ICredentialStore credentialStore)
: this(productInformation, _defaultGitHubApiUrl, credentialStore)
{
}
///
/// Creates a new connection instance used to make requests of the GitHub API.
///
///
/// The name (and optionally version) of the product using this library. This is sent to the server as part of
/// the user agent for analytics purposes.
///
///
/// The address to point this client to such as https://api.github.com or the URL to a GitHub Enterprise
/// instance
/// Provides credentials to the client when making requests
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
public Connection(ProductHeaderValue productInformation, Uri baseAddress, ICredentialStore credentialStore)
: this(productInformation, baseAddress, credentialStore, new HttpClientAdapter(HttpMessageHandlerFactory.CreateDefault), new SimpleJsonSerializer())
{
}
///
/// Creates a new connection instance used to make requests of the GitHub API.
///
///
/// The name (and optionally version) of the product using this library. This is sent to the server as part of
/// the user agent for analytics purposes.
///
///
/// The address to point this client to such as https://api.github.com or the URL to a GitHub Enterprise
/// instance
/// Provides credentials to the client when making requests
/// A raw used to make requests
/// Class used to serialize and deserialize JSON requests
public Connection(
ProductHeaderValue productInformation,
Uri baseAddress,
ICredentialStore credentialStore,
IHttpClient httpClient,
IJsonSerializer serializer)
{
Ensure.ArgumentNotNull(productInformation, "productInformation");
Ensure.ArgumentNotNull(baseAddress, "baseAddress");
Ensure.ArgumentNotNull(credentialStore, "credentialStore");
Ensure.ArgumentNotNull(httpClient, "httpClient");
Ensure.ArgumentNotNull(serializer, "serializer");
if (!baseAddress.IsAbsoluteUri)
{
throw new ArgumentException(
string.Format(CultureInfo.InvariantCulture, "The base address '{0}' must be an absolute URI",
baseAddress), "baseAddress");
}
UserAgent = FormatUserAgent(productInformation);
BaseAddress = baseAddress;
_authenticator = new Authenticator(credentialStore);
_httpClient = httpClient;
_jsonPipeline = new JsonHttpPipeline(serializer);
}
///
/// Gets the latest API Info - this will be null if no API calls have been made
///
/// representing the information returned as part of an Api call
public ApiInfo GetLastApiInfo()
{
// We've chosen to not wrap the _lastApiInfo in a lock. Originally the code was returning a reference - so there was a danger of
// on thread writing to the object while another was reading. Now we are cloning the ApiInfo on request - thus removing the need (or overhead)
// of putting locks in place.
// See https://github.com/octokit/octokit.net/pull/855#discussion_r36774884
return _lastApiInfo == null ? null : _lastApiInfo.Clone();
}
private ApiInfo _lastApiInfo;
public Task> Get(Uri uri, IDictionary parameters, string accepts)
{
Ensure.ArgumentNotNull(uri, "uri");
return SendData(uri.ApplyParameters(parameters), HttpMethod.Get, null, accepts, null, CancellationToken.None);
}
public Task> Get(Uri uri, IDictionary parameters, string accepts, CancellationToken cancellationToken)
{
Ensure.ArgumentNotNull(uri, "uri");
return SendData(uri.ApplyParameters(parameters), HttpMethod.Get, null, accepts, null, cancellationToken);
}
public Task> Get(Uri uri, TimeSpan timeout)
{
Ensure.ArgumentNotNull(uri, "uri");
return SendData(uri, HttpMethod.Get, null, null, null, timeout, CancellationToken.None);
}
///
/// Performs an asynchronous HTTP GET request that expects a containing HTML.
///
/// URI endpoint to send request to
/// Querystring parameters for the request
/// representing the received HTTP response
public Task> GetHtml(Uri uri, IDictionary parameters)
{
Ensure.ArgumentNotNull(uri, "uri");
return GetHtml(new Request
{
Method = HttpMethod.Get,
BaseAddress = BaseAddress,
Endpoint = uri.ApplyParameters(parameters)
});
}
public Task> Patch(Uri uri, object body)
{
Ensure.ArgumentNotNull(uri, "uri");
Ensure.ArgumentNotNull(body, "body");
return SendData(uri, HttpVerb.Patch, body, null, null, CancellationToken.None);
}
public Task> Patch(Uri uri, object body, string accepts)
{
Ensure.ArgumentNotNull(uri, "uri");
Ensure.ArgumentNotNull(body, "body");
Ensure.ArgumentNotNull(accepts, "accepts");
return SendData(uri, HttpVerb.Patch, body, accepts, null, CancellationToken.None);
}
///
/// Performs an asynchronous HTTP POST request.
///
/// URI endpoint to send request to
/// representing the received HTTP response
public async Task Post(Uri uri)
{
Ensure.ArgumentNotNull(uri, "uri");
var response = await SendData