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 a8825d779..2797f92cc 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 @@ -280,10 +280,7 @@ namespace Microsoft.PowerShell.Commands try { // open the input file - using (FileStream fs = new FileStream(InFile, FileMode.Open)) - { - SetRequestContent(request, fs); - } + SetRequestContent(request, new FileStream(InFile, FileMode.Open)); } catch (UnauthorizedAccessException) { @@ -331,55 +328,57 @@ namespace Microsoft.PowerShell.Commands // Set cmdlet context for write progress ValidateParameters(); PrepareSession(); - HttpClient client = GetHttpClient(); - HttpRequestMessage request = GetRequest(Uri); - FillRequestStream(request); - try + using (HttpClient client = GetHttpClient()) + using (HttpRequestMessage request = GetRequest(Uri)) { - long requestContentLength = 0; - if (request.Content != null) - requestContentLength = request.Content.Headers.ContentLength.Value; - - string reqVerboseMsg = String.Format(CultureInfo.CurrentCulture, - "{0} {1} with {2}-byte payload", - request.Method, - request.RequestUri, - requestContentLength); - WriteVerbose(reqVerboseMsg); - - HttpResponseMessage response = GetResponse(client, request); - response.EnsureSuccessStatusCode(); - - string contentType = ContentHelper.GetContentType(response); - string respVerboseMsg = string.Format(CultureInfo.CurrentCulture, - "received {0}-byte response of content type {1}", - response.Content.Headers.ContentLength, - contentType); - WriteVerbose(respVerboseMsg); - ProcessResponse(response); - UpdateSession(response); - - // If we hit our maximum redirection count, generate an error. - // Errors with redirection counts of greater than 0 are handled automatically by .NET, but are - // impossible to detect programmatically when we hit this limit. By handling this ourselves - // (and still writing out the result), users can debug actual HTTP redirect problems. - if (WebSession.MaximumRedirection == 0) // Indicate "HttpClientHandler.AllowAutoRedirect == false" + FillRequestStream(request); + try { - if (response.StatusCode == HttpStatusCode.Found || - response.StatusCode == HttpStatusCode.Moved || - response.StatusCode == HttpStatusCode.MovedPermanently) + long requestContentLength = 0; + if (request.Content != null) + requestContentLength = request.Content.Headers.ContentLength.Value; + + string reqVerboseMsg = String.Format(CultureInfo.CurrentCulture, + "{0} {1} with {2}-byte payload", + request.Method, + request.RequestUri, + requestContentLength); + WriteVerbose(reqVerboseMsg); + + HttpResponseMessage response = GetResponse(client, request); + response.EnsureSuccessStatusCode(); + + string contentType = ContentHelper.GetContentType(response); + string respVerboseMsg = string.Format(CultureInfo.CurrentCulture, + "received {0}-byte response of content type {1}", + response.Content.Headers.ContentLength, + contentType); + WriteVerbose(respVerboseMsg); + ProcessResponse(response); + UpdateSession(response); + + // If we hit our maximum redirection count, generate an error. + // Errors with redirection counts of greater than 0 are handled automatically by .NET, but are + // impossible to detect programmatically when we hit this limit. By handling this ourselves + // (and still writing out the result), users can debug actual HTTP redirect problems. + if (WebSession.MaximumRedirection == 0) // Indicate "HttpClientHandler.AllowAutoRedirect == false" { - ErrorRecord er = new ErrorRecord(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, request); - er.ErrorDetails = new ErrorDetails(WebCmdletStrings.MaximumRedirectionCountExceeded); - WriteError(er); + if (response.StatusCode == HttpStatusCode.Found || + response.StatusCode == HttpStatusCode.Moved || + response.StatusCode == HttpStatusCode.MovedPermanently) + { + ErrorRecord er = new ErrorRecord(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, request); + er.ErrorDetails = new ErrorDetails(WebCmdletStrings.MaximumRedirectionCountExceeded); + WriteError(er); + } } } - } - catch (HttpRequestException ex) - { - ErrorRecord er = new ErrorRecord(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); - ThrowTerminatingError(er); + catch (HttpRequestException ex) + { + ErrorRecord er = new ErrorRecord(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); + ThrowTerminatingError(er); + } } } catch (CryptographicException ex) diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index 0736b631d..798b5ca4d 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -5108,6 +5108,11 @@ end "Stop-Service", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), new SessionStateAliasEntry("sv", "Set-Variable", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), + // Web cmdlets aliases + new SessionStateAliasEntry("irm", + "Invoke-RestMethod", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), + new SessionStateAliasEntry("iwr", + "Invoke-WebRequest", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), // Porting note: #if !UNIX is used to disable aliases for cmdlets which conflict with Linux / OS X #if !UNIX // ac is a native command on OS X @@ -5175,10 +5180,6 @@ end "Get-PSSnapIn", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), new SessionStateAliasEntry("gwmi", "Get-WmiObject", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), - new SessionStateAliasEntry("irm", - "Invoke-RestMethod", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), - new SessionStateAliasEntry("iwr", - "Invoke-WebRequest", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), new SessionStateAliasEntry("iwmi", "Invoke-WMIMethod", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), new SessionStateAliasEntry("ogv", diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 0a2365729..11529315a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -643,3 +643,127 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { $result.Error | Should BeNullOrEmpty } } + +Describe "Validate Invoke-WebRequest and Invoke-RestMethod -InFile" -Tags "Feature" { + + Context "InFile parameter negative tests" { + + $testCases = @( +#region INVOKE-WEBREQUEST + @{ + Name = 'Validate error for Invoke-WebRequest -InFile ""' + ScriptBlock = {Invoke-WebRequest -Uri http://httpbin.org/post -Method Post -InFile ""} + ExpectedFullyQualifiedErrorId = 'WebCmdletInFileNotFilePathException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand' + } + + @{ + Name = 'Validate error for Invoke-WebRequest -InFile' + ScriptBlock = {Invoke-WebRequest -Uri http://httpbin.org/post -Method Post -InFile} + ExpectedFullyQualifiedErrorId = 'MissingArgument,Microsoft.PowerShell.Commands.InvokeWebRequestCommand' + } + + @{ + Name = "Validate error for Invoke-WebRequest -InFile $TestDrive\content.txt" + ScriptBlock = {Invoke-WebRequest -Uri http://httpbin.org/post -Method Post -InFile $TestDrive\content.txt} + ExpectedFullyQualifiedErrorId = 'PathNotFound,Microsoft.PowerShell.Commands.InvokeWebRequestCommand' + } +#endregion + +#region INVOKE-RESTMETHOD + @{ + Name = "Validate error for Invoke-RestMethod -InFile ''" + ScriptBlock = {Invoke-RestMethod -Uri http://httpbin.org/post -Method Post -InFile ''} + ExpectedFullyQualifiedErrorId = 'WebCmdletInFileNotFilePathException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand' + } + + @{ + Name = "Validate error for Invoke-RestMethod -InFile " + ScriptBlock = {Invoke-RestMethod -Uri http://httpbin.org/post -Method Post -InFile} + ExpectedFullyQualifiedErrorId = 'MissingArgument,Microsoft.PowerShell.Commands.InvokeRestMethodCommand' + } + + @{ + Name = "Validate error for Invoke-RestMethod -InFile $TestDrive\content.txt" + ScriptBlock = {Invoke-RestMethod -Uri http://httpbin.org/post -Method Post -InFile $TestDrive\content.txt} + ExpectedFullyQualifiedErrorId = 'PathNotFound,Microsoft.PowerShell.Commands.InvokeRestMethodCommand' + } +#endregion + ) + + It "" -TestCases $testCases { + param ($scriptblock, $expectedFullyQualifiedErrorId) + + try + { + & $scriptblock + throw "No Exception!" + } + catch + { + $_.FullyQualifiedErrorId | should be $ExpectedFullyQualifiedErrorId + } + } + } + + Context "InFile parameter positive tests" { + + BeforeAll { + $filePath = Join-Path $TestDrive test.txt + New-Item -Path $filePath -Value "hello" -ItemType File -Force + } + + It "Invoke-WebRequest -InFile" { + $result = Invoke-WebRequest -InFile $filePath -Uri http://httpbin.org/post -Method Post + $content = $result.Content | ConvertFrom-Json + $content.form | Should Match "hello" + } + + It "Invoke-RestMethod -InFile" { + $result = Invoke-RestMethod -InFile $filePath -Uri http://httpbin.org/post -Method Post + $result.form | Should Match "hello" + } + } +} + +Describe "Web cmdlets tests using the cmdlet's aliases" -Tags "CI" { + + function SearchEngineIsOnline + { + param ( + [ValidateNotNullOrEmpty()] + $webAddress + ) + $ping = new-object System.Net.NetworkInformation.Ping + $sendPing = $ping.SendPingAsync($webAddress) + return ($sendPing.Result.Status -eq "Success") + } + + # Make sure either www.bing.com or www.google.com are online to send a request. + $endPointToUse = $null + foreach ($uri in @("www.bing.com", "www.google.com")) + { + if (SearchEngineIsOnline $uri) + { + $endPointToUse = $uri + break + } + } + + # If neither www.bing.com nor www.google.com are online, then skip the tests. + $skipTests = ($endPointToUse -eq $null) + $finalUri = $endPointToUse + "?q=how+many+feet+in+a+mile" + + It "Execute Invoke-WebRequest --> 'iwr -URI $finalUri'" -Skip:$skipTests { + $result = iwr -URI $finalUri -TimeoutSec 5 + $result.StatusCode | Should Be "200" + $result.Links | Should Not Be $null + } + + It "Execute Invoke-RestMethod --> 'irm -URI $finalUri'" -Skip:$skipTests { + $result = irm -URI $finalUri -TimeoutSec 5 + foreach ($word in @("200", "how", "many", "feet", "in", "mile")) + { + $result | Should Match $word + } + } +}