diff --git a/Samples/SampleWdpClient.UniversalWindows/Settings.StyleCop b/Samples/SampleWdpClient.UniversalWindows/Settings.StyleCop new file mode 100644 index 00000000..6d356bc9 --- /dev/null +++ b/Samples/SampleWdpClient.UniversalWindows/Settings.StyleCop @@ -0,0 +1,824 @@ + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + \ No newline at end of file diff --git a/Samples/SampleWdpClient/Settings.StyleCop b/Samples/SampleWdpClient/Settings.StyleCop new file mode 100644 index 00000000..6d356bc9 --- /dev/null +++ b/Samples/SampleWdpClient/Settings.StyleCop @@ -0,0 +1,824 @@ + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + \ No newline at end of file diff --git a/Samples/XboxWdpDriver/XboxWdpDriver.csproj b/Samples/XboxWdpDriver/XboxWdpDriver.csproj index f1cddabb..f4b9e950 100644 --- a/Samples/XboxWdpDriver/XboxWdpDriver.csproj +++ b/Samples/XboxWdpDriver/XboxWdpDriver.csproj @@ -78,7 +78,6 @@ - - + \ No newline at end of file diff --git a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/CertificateHandling.cs b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/CertificateHandling.cs index 831e5232..23d2107a 100644 --- a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/CertificateHandling.cs +++ b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/CertificateHandling.cs @@ -40,10 +40,15 @@ public async Task 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); + outStream.Position = 0; + using (BinaryReader reader = new BinaryReader(outStream)) + { + byte[] certData = reader.ReadBytes((int)outStream.Length); + certificate = new X509Certificate2(certData); + } } } diff --git a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/HttpMultipartFileContent.cs b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/HttpMultipartFileContent.cs new file mode 100644 index 00000000..f036ca1f --- /dev/null +++ b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/HttpMultipartFileContent.cs @@ -0,0 +1,141 @@ +//---------------------------------------------------------------------------------------------- +// +// Licensed under the MIT License. See LICENSE.TXT in the project root license information. +// +//---------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.Tools.WindowsDevicePortal +{ + /// + /// This class mimicks , with two main differences + /// 1. Simplifies posting files by taking file names instead of managing streams. + /// 2. Does not quote the boundaries, due to a bug in the device portal + /// + internal sealed class HttpMultipartFileContent : HttpContent + { + /// + /// List of items to transfer + /// + private List items = new List(); + + /// + /// Boundary string + /// + private string boundaryString; + + /// + /// Initializes a new instance of the class. + /// + public HttpMultipartFileContent() : this(Guid.NewGuid().ToString()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The boundary string for file content. + public HttpMultipartFileContent(string boundary) + { + this.boundaryString = boundary; + Headers.TryAddWithoutValidation("Content-Type", string.Format("multipart/form-data; boundary={0}", this.boundaryString)); + } + + /// + /// Adds a file to the list of items to transfer + /// + /// The name of the file to add + public void Add(string filename) + { + if (filename != null) + { + this.items.Add(filename); + } + } + + /// + /// Adds a range of files to the list of items to transfer + /// + /// List of files to add + public void AddRange(IEnumerable filenames) + { + if (filenames != null) + { + this.items.AddRange(filenames); + } + } + + /// + /// Serializes the stream. + /// + /// Serialized Stream + /// The Transport Context + /// Task tracking progress + protected override async Task SerializeToStreamAsync(Stream outStream, TransportContext context) + { + var boundary = Encoding.ASCII.GetBytes($"--{boundaryString}\r\n"); + var newline = Encoding.ASCII.GetBytes("\r\n"); + foreach (var item in this.items) + { + outStream.Write(boundary, 0, boundary.Length); + var headerdata = GetFileHeader(new FileInfo(item)); + outStream.Write(headerdata, 0, headerdata.Length); + + using (var file = File.OpenRead(item)) + { + await file.CopyToAsync(outStream); + } + + outStream.Write(newline, 0, newline.Length); + await outStream.FlushAsync(); + } + + // Close the installation request data. + boundary = Encoding.ASCII.GetBytes($"--{boundaryString}--\r\n"); + outStream.Write(boundary, 0, boundary.Length); + await outStream.FlushAsync(); + } + + /// + /// Computes required length for the transfer. + /// + /// The computed length value + /// Whether or not the length was successfully computed + protected override bool TryComputeLength(out long length) + { + length = 0; + var boundaryLength = Encoding.ASCII.GetBytes(string.Format("--{0}\r\n", this.boundaryString)).Length; + foreach (var item in this.items) + { + var headerdata = GetFileHeader(new FileInfo(item)); + length += boundaryLength + headerdata.Length + new FileInfo(item).Length + 2; + } + + length += boundaryLength + 2; + return true; + } + + /// + /// Gets the file header for the transfer + /// + /// Information about the file + /// A byte array with the file header information + private static byte[] GetFileHeader(FileInfo info) + { + string contentType = "application/octet-stream"; + if (info.Extension.ToLower() == ".cer") + { + contentType = "application/x-x509-ca-cert"; + } + + return Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{0}\"\r\nContent-Type: {1}\r\n\r\n", info.Name, contentType)); + } + } +} \ No newline at end of file diff --git a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestDelete.cs b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestDelete.cs index 12e85497..2cabaa50 100644 --- a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestDelete.cs +++ b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestDelete.cs @@ -54,6 +54,10 @@ public async Task DeleteAsync(Uri uri) // Ensure we return with the stream pointed at the origin. dataStream.Position = 0; + if (dataStream.Length == 0) + { + dataStream = null; + } } } } diff --git a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestGet.cs b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestGet.cs index 78dc22a7..616457b6 100644 --- a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestGet.cs +++ b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestGet.cs @@ -24,39 +24,39 @@ public partial class DevicePortal public async Task 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; + } } } } diff --git a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestPost.cs b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestPost.cs index 069c77fb..459f01dc 100644 --- a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestPost.cs +++ b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestPost.cs @@ -30,8 +30,7 @@ public async Task PostAsync( string requestStreamContentType = null) { StreamContent requestContent = null; - MemoryStream responseDataStream = null; - + if (requestStream != null) { requestContent = new StreamContent(requestStream); @@ -39,6 +38,21 @@ public async Task PostAsync( requestContent.Headers.TryAddWithoutValidation(ContentTypeHeaderName, requestStreamContentType); } + return await this.PostAsync(uri, requestContent); + } + + /// + /// Submits the http post request to the specified uri. + /// + /// The uri to which the post request will be issued. + /// Optional content containing data for the request body. + /// Task tracking the completion of the POST request + public async Task PostAsync( + Uri uri, + HttpContent requestContent) + { + MemoryStream responseDataStream = null; + WebRequestHandler requestSettings = new WebRequestHandler(); requestSettings.UseDefaultCredentials = false; requestSettings.Credentials = this.deviceConnection.Credentials; @@ -46,6 +60,8 @@ public async Task PostAsync( 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)) @@ -67,6 +83,10 @@ public async Task PostAsync( // Ensure we return with the stream pointed at the origin. responseDataStream.Position = 0; + if (responseDataStream.Length == 0) + { + responseDataStream = null; + } } } } diff --git a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestPut.cs b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestPut.cs index a85ed32b..24835d3c 100644 --- a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestPut.cs +++ b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/RestPut.cs @@ -58,6 +58,10 @@ public async Task PutAsync( // Ensure we return with the stream pointed at the origin. dataStream.Position = 0; + if(dataStream.Length == 0) + { + dataStream = null; + } } } } diff --git a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/WebSocket.cs b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/WebSocket.cs index 14de4cd4..384cda3a 100644 --- a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/WebSocket.cs +++ b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/HttpRest/WebSocket.cs @@ -73,7 +73,14 @@ private async Task ConnectInternalAsync( this.websocket = new ClientWebSocket(); this.websocket.Options.UseDefaultCredentials = false; this.websocket.Options.Credentials = this.deviceConnection.Credentials; - this.websocket.Options.SetRequestHeader("Origin", this.deviceConnection.Connection.AbsoluteUri); + //Origin address must be especially cooked to pass through all Device Portal checks + string OriginAddress = this.deviceConnection.Connection.Scheme + "://" + this.deviceConnection.Connection.Host; + if((this.deviceConnection.Connection.Scheme == "http" && this.deviceConnection.Connection.Port != 80) || + (this.deviceConnection.Connection.Scheme == "https" && this.deviceConnection.Connection.Port != 443)) + { + OriginAddress += ":" + this.deviceConnection.Connection.Port; + } + this.websocket.Options.SetRequestHeader("Origin", OriginAddress); // There is no way to set a ServerCertificateValidationCallback for a single web socket, hence the workaround. ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors) diff --git a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper.csproj b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper.csproj index 8b614814..c64db6be 100644 --- a/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper.csproj +++ b/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper/WindowsDevicePortalWrapper.csproj @@ -57,6 +57,7 @@ + @@ -69,7 +70,6 @@ - - + \ No newline at end of file