diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs index d44828acd32..41af8ebc6dc 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs @@ -15,11 +15,8 @@ internal static class ContentHelper { #region Internal Methods - internal static string GetContentType(HttpResponseMessage response) - { - // ContentType may not exist in response header. Return null if not. - return response.Content.Headers.ContentType?.MediaType; - } + // ContentType may not exist in response header. Return null if not. + internal static string GetContentType(HttpResponseMessage response) => response.Content.Headers.ContentType?.MediaType; internal static Encoding GetDefaultEncoding() => Encoding.UTF8; @@ -32,8 +29,7 @@ internal static StringBuilder GetRawContentHeader(HttpResponseMessage response) { int statusCode = WebResponseHelper.GetStatusCode(response); string statusDescription = WebResponseHelper.GetStatusDescription(response); - raw.Append($"{protocol} {statusCode} {statusDescription}"); - raw.AppendLine(); + raw.AppendLine($"{protocol} {statusCode} {statusDescription}"); } HttpHeaders[] headerCollections = @@ -52,12 +48,9 @@ internal static StringBuilder GetRawContentHeader(HttpResponseMessage response) foreach (var header in headerCollection) { // Headers may have multiple entries with different values - foreach (var headerValue in header.Value) + foreach (string headerValue in header.Value) { - raw.Append(header.Key); - raw.Append(": "); - raw.Append(headerValue); - raw.AppendLine(); + raw.AppendLine($"{header.Key}: {headerValue}"); } } } @@ -101,10 +94,10 @@ private static bool CheckIsJson(string contentType) // Add in these other "javascript" related types that // sometimes get sent down as the mime type for JSON content isJson |= contentType.Equals("text/json", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("application/x-javascript", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("text/x-javascript", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("application/javascript", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("text/javascript", StringComparison.OrdinalIgnoreCase); + || contentType.Equals("application/x-javascript", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("text/x-javascript", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("application/javascript", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("text/javascript", StringComparison.OrdinalIgnoreCase); return isJson; } @@ -118,8 +111,8 @@ private static bool CheckIsText(string contentType) // Any text, xml or json types are text bool isText = contentType.StartsWith("text/", StringComparison.OrdinalIgnoreCase) - || CheckIsXml(contentType) - || CheckIsJson(contentType); + || CheckIsXml(contentType) + || CheckIsJson(contentType); // Further content type analysis is available on Windows if (Platform.IsWindows && !isText) @@ -156,11 +149,11 @@ private static bool CheckIsXml(string contentType) } // RFC 3023: Media types with the suffix "+xml" are XML - bool isXml = (contentType.Equals("application/xml", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("application/xml-external-parsed-entity", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("application/xml-dtd", StringComparison.OrdinalIgnoreCase)); - - isXml |= contentType.EndsWith("+xml", StringComparison.OrdinalIgnoreCase); + bool isXml = contentType.Equals("application/xml", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("application/xml-external-parsed-entity", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("application/xml-dtd", StringComparison.OrdinalIgnoreCase) + || contentType.EndsWith("+xml", StringComparison.OrdinalIgnoreCase); + return isXml; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index beb9ad93e7e..befa819504a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -105,7 +105,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet [ValidateNotNullOrEmpty] public virtual Uri Uri { get; set; } - #endregion + #endregion URI #region HTTP Version @@ -117,7 +117,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet [HttpVersionCompletions] public virtual Version HttpVersion { get; set; } - #endregion + #endregion HTTP Version #region Session /// @@ -133,7 +133,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet [Alias("SV")] public virtual string SessionVariable { get; set; } - #endregion + #endregion Session #region Authorization and Credentials @@ -198,13 +198,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet [Parameter] public virtual SecureString Token { get; set; } - /// - /// Gets or sets the AllowInsecureRedirect property used to follow HTTP redirects from HTTPS. - /// - [Parameter] - public virtual SwitchParameter AllowInsecureRedirect { get; set; } - - #endregion + #endregion Authorization and Credentials #region Headers @@ -234,10 +228,25 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet [Parameter] public virtual IDictionary Headers { get; set; } - #endregion + /// + /// Gets or sets the SkipHeaderValidation property. + /// + /// + /// This property adds headers to the request's header collection without validation. + /// + [Parameter] + public virtual SwitchParameter SkipHeaderValidation { get; set; } + + #endregion Headers #region Redirect + /// + /// Gets or sets the AllowInsecureRedirect property used to follow HTTP redirects from HTTPS. + /// + [Parameter] + public virtual SwitchParameter AllowInsecureRedirect { get; set; } + /// /// Gets or sets the RedirectMax property. /// @@ -252,6 +261,21 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet [ValidateRange(0, int.MaxValue)] public virtual int MaximumRetryCount { get; set; } + /// + /// Gets or sets the PreserveAuthorizationOnRedirect property. + /// + /// + /// This property overrides compatibility with web requests on Windows. + /// On FullCLR (WebRequest), authorization headers are stripped during redirect. + /// CoreCLR (HTTPClient) does not have this behavior so web requests that work on + /// PowerShell/FullCLR can fail with PowerShell/CoreCLR. To provide compatibility, + /// we'll detect requests with an Authorization header and automatically strip + /// the header when the first redirect occurs. This switch turns off this logic for + /// edge cases where the authorization header needs to be preserved across redirects. + /// + [Parameter] + public virtual SwitchParameter PreserveAuthorizationOnRedirect { get; set; } + /// /// Gets or sets the RetryIntervalSec property, which determines the number seconds between retries. /// @@ -259,7 +283,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet [ValidateRange(1, int.MaxValue)] public virtual int RetryIntervalSec { get; set; } = 5; - #endregion + #endregion Redirect #region Method @@ -286,7 +310,7 @@ public virtual string CustomMethod private string _custommethod; - #endregion + #endregion Method #region NoProxy @@ -297,7 +321,7 @@ public virtual string CustomMethod [Parameter(Mandatory = true, ParameterSetName = "StandardMethodNoProxy")] public virtual SwitchParameter NoProxy { get; set; } - #endregion + #endregion NoProxy #region Proxy @@ -323,7 +347,7 @@ public virtual string CustomMethod [Parameter(ParameterSetName = "CustomMethod")] public virtual SwitchParameter ProxyUseDefaultCredentials { get; set; } - #endregion + #endregion Proxy #region Input @@ -365,7 +389,7 @@ public virtual string CustomMethod /// private string _originalFilePath; - #endregion + #endregion Input #region Output @@ -393,7 +417,7 @@ public virtual string CustomMethod [Parameter] public virtual SwitchParameter SkipHttpErrorCheck { get; set; } - #endregion + #endregion Output #endregion Virtual Properties @@ -825,30 +849,6 @@ public HttpResponseException(string message, HttpResponseMessage response) : bas /// public abstract partial class WebRequestPSCmdlet : PSCmdlet { - /// - /// Gets or sets the PreserveAuthorizationOnRedirect property. - /// - /// - /// This property overrides compatibility with web requests on Windows. - /// On FullCLR (WebRequest), authorization headers are stripped during redirect. - /// CoreCLR (HTTPClient) does not have this behavior so web requests that work on - /// PowerShell/FullCLR can fail with PowerShell/CoreCLR. To provide compatibility, - /// we'll detect requests with an Authorization header and automatically strip - /// the header when the first redirect occurs. This switch turns off this logic for - /// edge cases where the authorization header needs to be preserved across redirects. - /// - [Parameter] - public virtual SwitchParameter PreserveAuthorizationOnRedirect { get; set; } - - /// - /// Gets or sets the SkipHeaderValidation property. - /// - /// - /// This property adds headers to the request's header collection without validation. - /// - [Parameter] - public virtual SwitchParameter SkipHeaderValidation { get; set; } - #region Abstract Methods /// diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs index 9de4311e430..aaf921c7f0d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs @@ -43,7 +43,7 @@ internal static Dictionary> GetHeadersDictionary(Htt internal static bool IsText(HttpResponseMessage response) { // ContentType may not exist in response header. - string contentType = response.Content.Headers.ContentType?.MediaType; + string contentType = ContentHelper.GetContentType(response); return ContentHelper.IsText(contentType); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs index 7dade00b4f6..4c8f1c40321 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs @@ -11,15 +11,7 @@ internal static class WebResponseObjectFactory { internal static WebResponseObject GetResponseObject(HttpResponseMessage response, Stream responseStream, ExecutionContext executionContext) { - WebResponseObject output; - if (WebResponseHelper.IsText(response)) - { - output = new BasicHtmlWebResponseObject(response, responseStream); - } - else - { - output = new WebResponseObject(response, responseStream); - } + WebResponseObject output = WebResponseHelper.IsText(response) ? new BasicHtmlWebResponseObject(response, responseStream) : new WebResponseObject(response, responseStream); return output; }