Skip to content

Commit

Permalink
Support large files downloading (like crashdumps) from device (#302)
Browse files Browse the repository at this point in the history
* Support HoloLens 2 devices

* Delayed HTTP GET operation

* Allow unsafe HTTP headers for support large file downloading in Device Portal

* Removing unsupported Length parameter from delayed GET buffer

* fix unit tests

* fix post unexisting file test

* support for uploading large files
  • Loading branch information
TaniaChistyakova authored and fieldsJacksonG committed Dec 3, 2019
1 parent 3d83c87 commit 2c67e0b
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ public async Task<HttpResponseMessage> GetAsync(Uri uri)
/// <returns>Async task returning the response.</returns>
public async Task<HttpResponseMessage> PostAsync(Uri uri, HttpContent content)
{
if(content != null)
{
await content.ReadAsByteArrayAsync();
}
Task<HttpResponseMessage> task = new Task<HttpResponseMessage>(() => this.HttpStoredResponse(uri, HttpMethods.Post));
task.Start();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ public enum DevicePortalPlatforms
/// </summary>
HoloLens,

/// <summary>
/// HoloLens 2 platform
/// </summary>
HoloLens2,

/// <summary>
/// Xbox One platform
/// </summary>
Expand Down Expand Up @@ -234,6 +239,9 @@ public DevicePortalPlatforms Platform
case "Virtual Machine":
return DevicePortalPlatforms.VirtualMachine;

case "HoloLens 2":
return DevicePortalPlatforms.HoloLens2;

default:
return (DevicePortalPlatforms)Enum.Parse(typeof(DevicePortalPlatforms), this.PlatformName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,13 @@ public async Task<byte[]> GetWindowsErrorReportingFileAsync(string user, string
byte[] werFile = null;
using (Stream stream = await this.GetAsync(uri))
{
werFile = new byte[stream.Length];
stream.Read(werFile, 0, werFile.Length);
using (MemoryStream outStream = new MemoryStream())
{
await outStream.CopyToAsync(outStream);

werFile = new byte[outStream.Length];
await stream.ReadAsync(werFile, 0, werFile.Length);
}
}

return werFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
#endif // !WINDOWS_UWP
#if WINDOWS_UWP
using System.Runtime.InteropServices.WindowsRuntime;
Expand Down Expand Up @@ -61,12 +62,34 @@ public partial class DevicePortal
private IDevicePortalConnection deviceConnection;
#if !WINDOWS_UWP

// Enable/disable useUnsafeHeaderParsing.
// See https://social.msdn.microsoft.com/Forums/en-US/ff098248-551c-4da9-8ba5-358a9f8ccc57/how-do-i-enable-useunsafeheaderparsing-from-code-net-20?forum=netfxnetcom
private static bool ToggleAllowUnsafeHeaderParsing(bool enable)
{
Type settingsSectionType = Assembly.GetAssembly(typeof(System.Net.Configuration.SettingsSection))?.GetType("System.Net.Configuration.SettingsSectionInternal");
if (settingsSectionType == null) { return false; }

object anInstance = settingsSectionType.InvokeMember("Section", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] { });
if (anInstance == null) { return false; }

FieldInfo aUseUnsafeHeaderParsing = settingsSectionType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance);
if (aUseUnsafeHeaderParsing == null) { return false; }

aUseUnsafeHeaderParsing.SetValue(anInstance, enable);

return true;
}

/// <summary>
/// Initializes static members of the <see cref="DevicePortal" /> class.
/// </summary>
static DevicePortal()
{
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
if (!ToggleAllowUnsafeHeaderParsing(true))
{
Console.WriteLine("Failed to enable useUnsafeHeaderParsing");
}
}

#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,12 @@ public async Task DeleteMrcFileAsync(string fileName)

using (Stream dataStream = await this.GetAsync(uri))
{
dataBytes = new byte[dataStream.Length];
dataStream.Read(dataBytes, 0, dataBytes.Length);
using (MemoryStream outStream = new MemoryStream())
{
await dataStream.CopyToAsync(outStream);
dataBytes = new byte[outStream.Length];
await outStream.ReadAsync(dataBytes, 0, dataBytes.Length);
}
}

return dataBytes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,6 @@ public async Task<HolographicSimulationPlaybackStates> GetHolographicSimulationP

using (Stream dataStream = await this.GetAsync(uri))
{
if ((dataStream != null) &&
(dataStream.Length != 0))
{
// Try to get the session state.
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ public async Task<byte[]> StopHolographicSimulationRecordingAsync()

using (Stream dataStream = await this.GetAsync(uri))
{
if ((dataStream != null) &&
(dataStream.Length != 0))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HolographicSimulationError));
HolographicSimulationError error = null;
Expand All @@ -123,8 +121,12 @@ public async Task<byte[]> StopHolographicSimulationRecordingAsync()
}

// Getting here indicates that we have file data to return.
dataBytes = new byte[dataStream.Length];
dataStream.Read(dataBytes, 0, dataBytes.Length);
using (MemoryStream outStream = new MemoryStream())
{
await dataStream.CopyToAsync(outStream);
dataBytes = new byte[outStream.Length];
await outStream.ReadAsync(dataBytes, 0, dataBytes.Length);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ public static T ReadJsonStream<T>(Stream dataStream, DataContractJsonSerializerS

using (dataStream)
{
if ((dataStream != null) &&
(dataStream.Length != 0))
if (dataStream != null)
{
JsonFormatCheck<T>(dataStream);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,14 @@ public async Task<X509Certificate2> GetRootDeviceCertificateAsync()

using (Stream stream = await this.GetAsync(uri))
{
using (BinaryReader reader = new BinaryReader(stream))
using (MemoryStream outStream = new MemoryStream())
{
byte[] certData = reader.ReadBytes((int)stream.Length);
certificate = new X509Certificate2(certData);
await stream.CopyToAsync(outStream);
using (BinaryReader reader = new BinaryReader(outStream))
{
byte[] certData = reader.ReadBytes((int)outStream.Length);
certificate = new X509Certificate2(certData);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,39 @@ public partial class DevicePortal
public async Task<Stream> GetAsync(
Uri uri)
{
MemoryStream dataStream = null;

WebRequestHandler handler = new WebRequestHandler();
handler.UseDefaultCredentials = false;
handler.Credentials = this.deviceConnection.Credentials;
handler.ServerCertificateValidationCallback = this.ServerCertificateValidation;

using (HttpClient client = new HttpClient(handler))
HttpClient client = null;
HttpResponseMessage response = null;
try
{
WebRequestHandler handler = new WebRequestHandler();
handler.UseDefaultCredentials = false;
handler.Credentials = this.deviceConnection.Credentials;
handler.ServerCertificateValidationCallback = this.ServerCertificateValidation;

client = new HttpClient(handler);
this.ApplyHttpHeaders(client, HttpMethods.Get);

using (HttpResponseMessage response = await client.GetAsync(uri).ConfigureAwait(false))
response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
if (!response.IsSuccessStatusCode)
{
throw await DevicePortalException.CreateAsync(response);
}

this.RetrieveCsrfToken(response);

using (HttpContent content = response.Content)
{
dataStream = new MemoryStream();
throw await DevicePortalException.CreateAsync(response);
}

await content.CopyToAsync(dataStream).ConfigureAwait(false);
this.RetrieveCsrfToken(response);

// Ensure we return with the stream pointed at the origin.
dataStream.Position = 0;
}
if (response.Content == null)
{
throw new DevicePortalException(System.Net.HttpStatusCode.NoContent, "", uri);
}
}

return dataStream;
return await response.Content.ReadAsStreamAsync();
}
catch (Exception)
{
response?.Dispose();
client?.Dispose();
throw;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public partial class DevicePortal

using (HttpClient client = new HttpClient(requestSettings))
{
client.Timeout = TimeSpan.FromMilliseconds(-1);

this.ApplyHttpHeaders(client, HttpMethods.Post);

using (HttpResponseMessage response = await client.PostAsync(uri, requestContent).ConfigureAwait(false))
Expand Down

0 comments on commit 2c67e0b

Please sign in to comment.