diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs index 2797f92cc59..ca38c1ed3e6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs @@ -19,6 +19,27 @@ namespace Microsoft.PowerShell.Commands { + /// + /// Exception class for webcmdlets to enable returning HTTP error response + /// + public sealed class HttpResponseException : HttpRequestException + { + /// + /// Constructor for HttpResponseException + /// + /// Message for the exception + /// Response from the HTTP server + public HttpResponseException (string message, HttpResponseMessage response) : base(message) + { + Response = response; + } + + /// + /// HTTP error response + /// + public HttpResponseMessage Response { get; private set; } + } + /// /// Base class for Invoke-RestMethod and Invoke-WebRequest commands. /// @@ -347,7 +368,6 @@ protected override void ProcessRecord() WriteVerbose(reqVerboseMsg); HttpResponseMessage response = GetResponse(client, request); - response.EnsureSuccessStatusCode(); string contentType = ContentHelper.GetContentType(response); string respVerboseMsg = string.Format(CultureInfo.CurrentCulture, @@ -355,6 +375,39 @@ protected override void ProcessRecord() response.Content.Headers.ContentLength, contentType); WriteVerbose(respVerboseMsg); + + if (!response.IsSuccessStatusCode) + { + string message = String.Format(CultureInfo.CurrentCulture, WebCmdletStrings.ResponseStatusCodeFailure, + (int)response.StatusCode, response.ReasonPhrase); + HttpResponseException httpEx = new HttpResponseException(message, response); + ErrorRecord er = new ErrorRecord(httpEx, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); + string detailMsg = ""; + StreamReader reader = null; + try + { + reader = new StreamReader(StreamHelper.GetResponseStream(response)); + // remove HTML tags making it easier to read + detailMsg = System.Text.RegularExpressions.Regex.Replace(reader.ReadToEnd(), "<[^>]*>",""); + } + catch (Exception) + { + // catch all + } + finally + { + if (reader != null) + { + reader.Dispose(); + } + } + if (!String.IsNullOrEmpty(detailMsg)) + { + er.ErrorDetails = new ErrorDetails(detailMsg); + } + ThrowTerminatingError(er); + } + ProcessResponse(response); UpdateSession(response); @@ -542,4 +595,4 @@ internal long SetRequestContent(HttpRequestMessage request, IDictionary content) #endregion Helper Methods } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx index 368e34ad7be..b7256271e95 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx @@ -210,4 +210,7 @@ Conversion from JSON failed with error: {0} + + Response status code does not indicate success: {0} ({1}). + \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 11529315a69..66d618ddc61 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -399,6 +399,19 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { $result = ExecuteWebCommand -command $command $result.Error | Should BeNullOrEmpty } + + It "Validate Invoke-WebRequest returns HTTP errors in exception" { + + $command = "Invoke-WebRequest -Uri http://httpbin.org/status/418" + $result = ExecuteWebCommand -command $command + + $result.Error.ErrorDetails.Message | Should Match "\-=\[ teapot \]" + $result.Error.Exception | Should BeOfType Microsoft.PowerShell.Commands.HttpResponseException + $result.Error.Exception.Response.StatusCode | Should Be 418 + $result.Error.Exception.Response.ReasonPhrase | Should Be "I'm a teapot" + $result.Error.Exception.Message | Should Match ": 418 \(I'm a teapot\)\." + $result.Error.FullyQualifiedErrorId | Should Be "WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" + } } Describe "Invoke-RestMethod tests" -Tags "Feature" { @@ -642,6 +655,19 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { $result = ExecuteWebCommand -command $command $result.Error | Should BeNullOrEmpty } + + It "Validate Invoke-RestMethod returns HTTP errors in exception" { + + $command = "Invoke-RestMethod -Uri http://httpbin.org/status/418" + $result = ExecuteWebCommand -command $command + + $result.Error.ErrorDetails.Message | Should Match "\-=\[ teapot \]" + $result.Error.Exception | Should BeOfType Microsoft.PowerShell.Commands.HttpResponseException + $result.Error.Exception.Response.StatusCode | Should Be 418 + $result.Error.Exception.Response.ReasonPhrase | Should Be "I'm a teapot" + $result.Error.Exception.Message | Should Match ": 418 \(I'm a teapot\)\." + $result.Error.FullyQualifiedErrorId | Should Be "WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand" + } } Describe "Validate Invoke-WebRequest and Invoke-RestMethod -InFile" -Tags "Feature" {