Skip to content

Commit

Permalink
Throw exception in CDNClient if http request is not successful (#672)
Browse files Browse the repository at this point in the history
Provides a WebAPIRequestException subclass for source compatibility. Fixes #650
  • Loading branch information
yaakov-h authored and azuisleet committed May 9, 2019
1 parent 51e54e0 commit ada2c52
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 28 deletions.
19 changes: 19 additions & 0 deletions SteamKit2/SteamKit2/Steam/CDNClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ public CDNClient( SteamClient steamClient, byte[] appTicket = null )
/// No Steam CS servers available, or the suggested CellID is unavailable.
/// Check that the <see cref="SteamClient"/> associated with this <see cref="CDNClient"/> instance is logged onto Steam.
/// </exception>
/// <exception cref="HttpRequestException">An network error occurred when performing the request.</exception>
/// <exception cref="SteamKitWebRequestException">A network error occurred when performing the request.</exception>
public async Task<IList<Server>> FetchServerListAsync( IPEndPoint csServer = null, uint? cellId = null, int maxServers = 20 )
{
DebugLog.Assert( steamClient.IsConnected, "CDNClient", "CMClient is not connected!" );
Expand Down Expand Up @@ -356,6 +358,8 @@ public async Task<IList<Server>> FetchServerListAsync( IPEndPoint csServer = nul
/// </summary>
/// <param name="csServer">The content server to connect to.</param>
/// <exception cref="System.ArgumentNullException">csServer was null.</exception>
/// <exception cref="HttpRequestException">An network error occurred when performing the request.</exception>
/// <exception cref="SteamKitWebRequestException">A network error occurred when performing the request.</exception>
public async Task ConnectAsync( Server csServer )
{
DebugLog.Assert( steamClient.IsConnected, "CDNClient", "CMClient is not connected!" );
Expand Down Expand Up @@ -411,6 +415,8 @@ public async Task ConnectAsync( Server csServer )
/// This is used for decrypting filenames (if needed) in depot manifests, and processing depot chunks.
/// </param>
/// <param name="cdnAuthToken">CDN auth token for CDN content server endpoints.</param>
/// <exception cref="HttpRequestException">An network error occurred when performing the request.</exception>
/// <exception cref="SteamKitWebRequestException">A network error occurred when performing the request.</exception>
public async Task AuthenticateDepotAsync( uint depotid, byte[] depotKey = null, string cdnAuthToken = null )
{
if ( depotIds.ContainsKey( depotid ) )
Expand Down Expand Up @@ -446,6 +452,8 @@ public async Task AuthenticateDepotAsync( uint depotid, byte[] depotKey = null,
/// <param name="depotId">The id of the depot being accessed.</param>
/// <param name="manifestId">The unique identifier of the manifest to be downloaded.</param>
/// <returns>A <see cref="DepotManifest"/> instance that contains information about the files present within a depot.</returns>
/// <exception cref="HttpRequestException">An network error occurred when performing the request.</exception>
/// <exception cref="SteamKitWebRequestException">A network error occurred when performing the request.</exception>
public async Task<DepotManifest> DownloadManifestAsync( uint depotId, ulong manifestId )
{
depotCdnAuthKeys.TryGetValue( depotId, out var cdnToken );
Expand All @@ -466,6 +474,8 @@ public async Task<DepotManifest> DownloadManifestAsync( uint depotId, ulong mani
/// This is used for decrypting filenames (if needed) in depot manifests, and processing depot chunks.
/// </param>
/// <returns>A <see cref="DepotManifest"/> instance that contains information about the files present within a depot.</returns>
/// <exception cref="HttpRequestException">An network error occurred when performing the request.</exception>
/// <exception cref="SteamKitWebRequestException">A network error occurred when performing the request.</exception>
public async Task<DepotManifest> DownloadManifestAsync( uint depotId, ulong manifestId, string host, string cdnAuthToken, byte[] depotKey = null )
{
var server = new Server
Expand Down Expand Up @@ -501,6 +511,8 @@ public async Task<DepotManifest> DownloadManifestAsync( uint depotId, ulong mani
/// <returns>A <see cref="DepotChunk"/> instance that contains the data for the given chunk.</returns>
/// <exception cref="System.ArgumentNullException">chunk's <see cref="DepotManifest.ChunkData.ChunkID"/> was null.</exception>
/// <exception cref="System.IO.InvalidDataException">Thrown if the downloaded data does not match the expected length.</exception>
/// <exception cref="HttpRequestException">An network error occurred when performing the request.</exception>
/// <exception cref="SteamKitWebRequestException">A network error occurred when performing the request.</exception>
public async Task<DepotChunk> DownloadDepotChunkAsync( uint depotId, DepotManifest.ChunkData chunk )
#pragma warning restore 0419
#pragma warning restore 1574
Expand Down Expand Up @@ -549,6 +561,8 @@ public async Task<DepotChunk> DownloadDepotChunkAsync( uint depotId, DepotManife
/// </param>
/// <exception cref="System.ArgumentNullException">chunk's <see cref="DepotManifest.ChunkData.ChunkID"/> was null.</exception>
/// <exception cref="System.IO.InvalidDataException">Thrown if the downloaded data does not match the expected length.</exception>
/// <exception cref="HttpRequestException">An network error occurred when performing the request.</exception>
/// <exception cref="SteamKitWebRequestException">A network error occurred when performing the request.</exception>
public async Task<DepotChunk> DownloadDepotChunkAsync( uint depotId, DepotManifest.ChunkData chunk, string host, string cdnAuthToken, byte[] depotKey = null)
#pragma warning restore 1574
#pragma warning restore 0419
Expand Down Expand Up @@ -632,6 +646,11 @@ async Task<byte[]> DoRawCommandAsync( Server server, HttpMethod method, string c
{
var response = await httpClient.SendAsync( request, cts.Token ).ConfigureAwait( false );

if ( !response.IsSuccessStatusCode )
{
throw new SteamKitWebRequestException( $"Response status code does not indicate success: {response.StatusCode} ({response.ReasonPhrase}).", response );
}

var responseData = await response.Content.ReadAsByteArrayAsync().ConfigureAwait( false );
return responseData;
}
Expand Down
28 changes: 0 additions & 28 deletions SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -521,32 +521,4 @@ static HttpClient CreateDefaultHttpClient( Uri baseAddress )
return client;
}
}

/// <summary>
/// Thrown when WebAPI request fails.
/// </summary>
public sealed class WebAPIRequestException : HttpRequestException
{
/// <summary>
/// Represents the status code of the HTTP response.
/// </summary>
public HttpStatusCode StatusCode { get; private set; }

/// <summary>
/// Represents the collection of HTTP response headers.
/// </summary>
public HttpResponseHeaders Headers { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="WebAPIRequestException"/> class.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="response">HTTP response message including the status code and data.</param>
public WebAPIRequestException(string message, HttpResponseMessage response)
: base(message)
{
this.StatusCode = response.StatusCode;
this.Headers = response.Headers;
}
}
}
20 changes: 20 additions & 0 deletions SteamKit2/SteamKit2/Steam/WebAPI/WebAPIRequestException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Net.Http;

namespace SteamKit2
{
/// <summary>
/// Thrown when WebAPI request fails.
/// </summary>
public sealed class WebAPIRequestException : SteamKitWebRequestException
{
/// <summary>
/// Initializes a new instance of the <see cref="WebAPIRequestException"/> class.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="response">HTTP response message including the status code and data.</param>
public WebAPIRequestException(string message, HttpResponseMessage response)
: base(message, response)
{
}
}
}
34 changes: 34 additions & 0 deletions SteamKit2/SteamKit2/Util/SteamKitWebRequestException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;

namespace SteamKit2
{
/// <summary>
/// Thrown when a HTTP request fails.
/// </summary>
public class SteamKitWebRequestException : HttpRequestException
{
/// <summary>
/// Represents the status code of the HTTP response.
/// </summary>
public HttpStatusCode StatusCode { get; private set; }

/// <summary>
/// Represents the collection of HTTP response headers.
/// </summary>
public HttpResponseHeaders Headers { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="SteamKitWebRequestException"/> class.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="response">HTTP response message including the status code and data.</param>
public SteamKitWebRequestException(string message, HttpResponseMessage response)
: base(message)
{
this.StatusCode = response.StatusCode;
this.Headers = response.Headers;
}
}
}
37 changes: 37 additions & 0 deletions SteamKit2/Tests/CDNClientFacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using SteamKit2;
using Xunit;

namespace Tests
{
public class CDNClientFacts
{
[Fact]
public async Task ThrowsSteamKitWebExceptionOnUnsuccessfulWebResponse()
{
var configuration = SteamConfiguration.Create(x => x.WithHttpClientFactory(() => new HttpClient(new TeapotHttpMessageHandler())));
var steam = new SteamClient(configuration);
var client = new CDNClient(steam);

try
{
await client.DownloadManifestAsync(0, 0, "localhost", "12345");
throw new InvalidOperationException("This should be unreachable.");
}
catch (SteamKitWebRequestException ex)
{
Assert.Equal((HttpStatusCode)418, ex.StatusCode);
}
}

sealed class TeapotHttpMessageHandler : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
=> Task.FromResult(new HttpResponseMessage((HttpStatusCode)418));
}
}
}

0 comments on commit ada2c52

Please sign in to comment.