Skip to content

Commit

Permalink
Merge pull request #10 from spookylsm/protect_getbytes_method
Browse files Browse the repository at this point in the history
chore: protect get bytes method
  • Loading branch information
spookylsm authored Apr 19, 2023
2 parents 289600b + 67a9bd4 commit 0740d47
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 123 deletions.
72 changes: 46 additions & 26 deletions src/TusDotNetClient/TusClient.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TusDotNetClient
namespace TusDotNetClient
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// Represents the different hashing algorithm implementations supported by <see cref="TusClient"/>
/// </summary>
Expand Down Expand Up @@ -91,23 +91,30 @@ public async Task<string> CreateAsync(string url, long uploadLength,
{
request.AddHeader(TusHeaderNames.UploadMetadata, string.Join(",", metadata
.Select(md =>
$"{md.key.Replace(" ", "").Replace(",", "")} {Convert.ToBase64String(Encoding.UTF8.GetBytes(md.value))}")));
$"{md.key.Replace(" ", "").Replace(",", "")} {Convert.ToBase64String(GetByteArray(md))}")));
}

var response = await client.PerformRequestAsync(request)
.ConfigureAwait(false);
var response = await client.PerformRequestAsync(request).ConfigureAwait(false);

if (response.StatusCode != HttpStatusCode.Created)
throw new Exception("CreateFileInServer failed. " + response.ResponseString);
{
throw new Exception("Failed to create the file in the server. " + response.ResponseString);
}

if (!response.Headers.ContainsKey("Location"))
throw new Exception("Location Header Missing");
{
throw new Exception("Location Header not found");
}

if (!Uri.TryCreate(response.Headers["Location"], UriKind.RelativeOrAbsolute, out var locationUri))
{
throw new Exception("Invalid Location Header");
}

if (!locationUri.IsAbsoluteUri)
{
locationUri = new Uri(requestUri, locationUri);
}

return locationUri.ToString();
}
Expand Down Expand Up @@ -149,8 +156,7 @@ public TusOperation<TusHttpResponse> DownloadAsync(string url, CancellationToken
request.DownloadProgressed += reportProgress;
var response = await client.PerformRequestAsync(request)
.ConfigureAwait(false);
var response = await client.PerformRequestAsync(request).ConfigureAwait(false);
request.DownloadProgressed -= reportProgress;
Expand All @@ -168,19 +174,21 @@ public async Task<TusServerInfo> GetServerInfo(string url)
var client = new TusHttpClient();
var request = new TusHttpRequest(url, RequestMethod.Options, AdditionalHeaders);

var response = await client.PerformRequestAsync(request)
.ConfigureAwait(false);
var response = await client.PerformRequestAsync(request).ConfigureAwait(false);

// Spec says NoContent but tusd gives OK because of browser bugs
if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.OK)
throw new Exception("getServerInfo failed. " + response.ResponseString);
{
throw new Exception("Failed to get the server info. " + response.ResponseString);
}

response.Headers.TryGetValue(TusHeaderNames.TusResumable, out var version);
response.Headers.TryGetValue(TusHeaderNames.TusVersion, out var supportedVersions);
response.Headers.TryGetValue(TusHeaderNames.TusExtension, out var extensions);
response.Headers.TryGetValue(TusHeaderNames.TusMaxSize, out var maxSizeString);
response.Headers.TryGetValue(TusHeaderNames.TusChecksumAlgorithm, out var checksumAlgorithms);
long.TryParse(maxSizeString, out var maxSize);

return new TusServerInfo(version, supportedVersions, extensions, maxSize, checksumAlgorithms);
}

Expand All @@ -196,8 +204,7 @@ public async Task<TusHttpResponse> HeadAsync(string url)

try
{
return await client.PerformRequestAsync(request)
.ConfigureAwait(false);
return await client.PerformRequestAsync(request).ConfigureAwait(false);
}
catch (TusException ex)
{
Expand Down Expand Up @@ -315,8 +322,7 @@ void OnProgress(long written, long total) =>
{
// retry by continuing the while loop but get new offset
// from server to prevent Conflict error
offset = await GetFileOffset(url)
.ConfigureAwait(false);
offset = await GetFileOffset(url).ConfigureAwait(false);
}
else
{
Expand Down Expand Up @@ -344,6 +350,16 @@ private static int ChunkSizeToMB(double chunkSize)
return (int)Math.Ceiling(chunkSize * 1024.0 * 1024.0);
}

private static byte[] GetByteArray((string key, string value) md)
{
if (md.value != null)
{
return Encoding.UTF8.GetBytes(md.value);
}

return Encoding.UTF8.GetBytes(string.Empty);
}

private async Task<long> GetFileOffset(string url)
{
var client = new TusHttpClient();
Expand All @@ -353,10 +369,14 @@ private async Task<long> GetFileOffset(string url)
.ConfigureAwait(false);

if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.OK)
{
throw new Exception("GetFileOffset failed. " + response.ResponseString);
}

if (!response.Headers.ContainsKey(TusHeaderNames.UploadOffset))
{
throw new Exception("Offset Header Missing");
}

return long.Parse(response.Headers[TusHeaderNames.UploadOffset]);
}
Expand Down
64 changes: 35 additions & 29 deletions src/TusDotNetClient/TusException.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,21 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;

namespace TusDotNetClient
namespace TusDotNetClient
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;

/// <summary>
/// Represents an exception that might occur when using <see cref="TusClient"/>.
/// </summary>
public class TusException : WebException
{
/// <summary>
/// Get the content, if any, of the failed operation.
/// </summary>
public string ResponseContent { get; }

/// <summary>
/// Get the HTTP status code, if any, of the failed operation.
/// </summary>
public HttpStatusCode StatusCode { get; }

/// <summary>
/// Get the description of the HTTP status code.
/// </summary>
public string StatusDescription { get; }

/// <summary>
/// Get the original <see cref="WebException"/> that occured.
/// </summary>
public WebException OriginalException { get; }

/// <summary>
/// Create a new instance of <see cref="TusException"/> based on an <see cref="OperationCanceledException"/>.
/// </summary>
/// <param name="ex">An <see cref="OperationCanceledException"/> to base the <see cref="TusException"/> on.</param>
/// <param name="ex">
/// An <see cref="OperationCanceledException"/> to base the <see cref="TusException"/> on.
/// </param>
public TusException(OperationCanceledException ex)
: base(ex.Message, ex, WebExceptionStatus.RequestCanceled, null)
{
Expand All @@ -43,7 +25,9 @@ public TusException(OperationCanceledException ex)
/// <summary>
/// Create a new instance of <see cref="TusException"/> based on another <see cref="TusException"/>.
/// </summary>
/// <param name="ex">The <see cref="TusException"/> to base the new <see cref="TusException"/> on.</param>
/// <param name="ex">
/// The <see cref="TusException"/> to base the new <see cref="TusException"/> on.
/// </param>
/// <param name="message">Text to prefix the <see cref="Exception.Message"/> with.</param>
public TusException(TusException ex, string message)
: base($"{message}{ex.Message}", ex, ex.Status, ex.Response)
Expand All @@ -58,7 +42,9 @@ public TusException(TusException ex, string message)
/// <summary>
/// Create a new instance of <see cref="TusException"/> based on a <see cref="WebException"/>.
/// </summary>
/// <param name="ex">The <see cref="WebException"/> to base the new <see cref="TusException"/> on.</param>
/// <param name="ex">
/// The <see cref="WebException"/> to base the new <see cref="TusException"/> on.
/// </param>
/// <param name="message">Text to prefix the <see cref="Exception.Message"/> with.</param>
public TusException(WebException ex, string message = "")
: base($"{message}{ex.Message}", ex, ex.Status, ex.Response)
Expand All @@ -77,6 +63,26 @@ public TusException(WebException ex, string message = "")
}
}

/// <summary>
/// Get the original <see cref="WebException"/> that occured.
/// </summary>
public WebException OriginalException { get; }

/// <summary>
/// Get the content, if any, of the failed operation.
/// </summary>
public string ResponseContent { get; }

/// <summary>
/// Get the HTTP status code, if any, of the failed operation.
/// </summary>
public HttpStatusCode StatusCode { get; }

/// <summary>
/// Get the description of the HTTP status code.
/// </summary>
public string StatusDescription { get; }

/// <summary>
/// Get a <see cref="string"/> containing all relevant information about the <see cref="TusException"/>.
/// </summary>
Expand Down
20 changes: 11 additions & 9 deletions src/TusDotNetClient/TusHTTPClient.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace TusDotNetClient
namespace TusDotNetClient
{
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// A class to execute requests against a Tus enabled server.
/// </summary>
Expand Down Expand Up @@ -64,9 +64,11 @@ public async Task<TusHttpResponse> PerformRequestAsync(TusHttpRequest request)
case TusHeaderNames.ContentLength:
webRequest.ContentLength = long.Parse(header.Value);
break;

case TusHeaderNames.ContentType:
webRequest.ContentType = header.Value;
break;

default:
webRequest.Headers.Add(header.Key, header.Value);
break;
Expand Down Expand Up @@ -101,7 +103,7 @@ await requestStream.WriteAsync(buffer, 0, bytesWritten, request.CancelToken)
}
}

var response = (HttpWebResponse) await webRequest.GetResponseAsync()
var response = (HttpWebResponse)await webRequest.GetResponseAsync()
.ConfigureAwait(false);

//contentLength=0 for gzipped responses due to .net bug
Expand Down
14 changes: 7 additions & 7 deletions src/TusDotNetClient/TusHeaderNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ namespace TusDotNetClient
/// </summary>
public static class TusHeaderNames
{
public const string TusResumable = "Tus-Resumable";
public const string TusVersion = "Tus-Version";
public const string ContentLength = "Content-Length";
public const string ContentType = "Content-Type";
public const string TusChecksumAlgorithm = "Tus-Checksum-Algorithm";
public const string TusExtension = "Tus-Extension";
public const string TusMaxSize = "Tus-Max-Size";
public const string TusChecksumAlgorithm = "Tus-Checksum-Algorithm";
public const string TusResumable = "Tus-Resumable";
public const string TusVersion = "Tus-Version";
public const string UploadChecksum = "Upload-Checksum";
public const string UploadLength = "Upload-Length";
public const string UploadOffset = "Upload-Offset";
public const string UploadMetadata = "Upload-Metadata";
public const string UploadChecksum = "Upload-Checksum";
public const string ContentLength = "Content-Length";
public const string ContentType = "Content-Type";
public const string UploadOffset = "Upload-Offset";
}
}
10 changes: 5 additions & 5 deletions src/TusDotNetClient/TusHttpRequest.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Threading;

namespace TusDotNetClient
namespace TusDotNetClient
{
using System;
using System.Collections.Generic;
using System.Threading;

/// <summary>
/// HTTP methods supported by <see cref="TusDotNetClient"/>
/// </summary>
Expand Down
12 changes: 6 additions & 6 deletions src/TusDotNetClient/TusHttpResponse.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;

namespace TusDotNetClient
namespace TusDotNetClient
{
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;

/// <summary>
/// Represents a response from a request made to a Tus enabled server.
/// </summary>
Expand Down
Loading

0 comments on commit 0740d47

Please sign in to comment.