diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
index 33741706393..9f4b825a6ce 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
+++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
@@ -34,17 +34,6 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/BasicHtmlWebResponseObject.Common.cs
similarity index 88%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/BasicHtmlWebResponseObject.Common.cs
index 1dcb9f8575f..8bf89230e80 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/BasicHtmlWebResponseObject.Common.cs
@@ -5,6 +5,7 @@
using System;
using System.Management.Automation;
using System.Net;
+using System.Net.Http;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
@@ -16,7 +17,7 @@ namespace Microsoft.PowerShell.Commands
///
/// Response object for html content without DOM parsing
///
- public partial class BasicHtmlWebResponseObject : WebResponseObject
+ public class BasicHtmlWebResponseObject : WebResponseObject
{
#region Properties
@@ -116,6 +117,31 @@ public WebCmdletElementCollection Images
#endregion Properties
+ #region Constructors
+
+ ///
+ /// Constructor for BasicHtmlWebResponseObject
+ ///
+ ///
+ public BasicHtmlWebResponseObject(HttpResponseMessage response)
+ : this(response, null)
+ { }
+
+ ///
+ /// Constructor for HtmlWebResponseObject with memory stream
+ ///
+ ///
+ ///
+ public BasicHtmlWebResponseObject(HttpResponseMessage response, Stream contentStream)
+ : base(response, contentStream)
+ {
+ EnsureHtmlParser();
+ InitializeContent();
+ InitializeRawContent(response);
+ }
+
+ #endregion Constructors
+
#region Private Fields
private static Regex s_tagRegex;
@@ -242,6 +268,13 @@ protected void InitializeContent()
}
}
+ private void InitializeRawContent(HttpResponseMessage baseResponse)
+ {
+ StringBuilder raw = ContentHelper.GetRawContentHeader(baseResponse);
+ raw.Append(Content);
+ this.RawContent = raw.ToString();
+ }
+
#endregion Methods
}
}
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
deleted file mode 100644
index 5e8055572a3..00000000000
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs
+++ /dev/null
@@ -1,748 +0,0 @@
-/********************************************************************++
-Copyright (c) Microsoft Corporation. All rights reserved.
---********************************************************************/
-
-using System;
-using System.Collections.ObjectModel;
-using System.Management.Automation;
-using System.Net;
-using System.IO;
-using System.Text;
-using System.Collections;
-using System.Globalization;
-using System.Security;
-using System.Security.Authentication;
-using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-using Microsoft.Win32;
-
-namespace Microsoft.PowerShell.Commands
-{
- ///
- /// The valid values for the -Authentication parameter for Invoke-RestMethod and Invoke-WebRequest
- ///
- public enum WebAuthenticationType
- {
- ///
- /// No authentication. Default.
- ///
- None,
-
- ///
- /// RFC-7617 Basic Authentication. Requires -Credential
- ///
- Basic,
-
- ///
- /// RFC-6750 OAuth 2.0 Bearer Authentication. Requires -Token
- ///
- Bearer,
-
- ///
- /// RFC-6750 OAuth 2.0 Bearer Authentication. Requires -Token
- ///
- OAuth,
- }
-
- // WebSslProtocol is used because not all SslProtocols are supported by HttpClientHandler.
- // Also SslProtocols.Default is not the "default" for HttpClientHandler as SslProtocols.Ssl3 is not supported.
- ///
- /// The valid values for the -SslProtocol parameter for Invoke-RestMethod and Invoke-WebRequest
- ///
- [Flags]
- public enum WebSslProtocol
- {
- ///
- /// No SSL protocol will be set and the system defaults will be used.
- ///
- Default = 0,
-
- ///
- /// Specifies the TLS 1.0 security protocol. The TLS protocol is defined in IETF RFC 2246.
- ///
- Tls = SslProtocols.Tls,
-
- ///
- /// Specifies the TLS 1.1 security protocol. The TLS protocol is defined in IETF RFC 4346.
- ///
- Tls11 = SslProtocols.Tls11,
-
- ///
- /// Specifies the TLS 1.2 security protocol. The TLS protocol is defined in IETF RFC 5246
- ///
- Tls12 = SslProtocols.Tls12
- }
-
- ///
- /// Base class for Invoke-RestMethod and Invoke-WebRequest commands.
- ///
- public abstract partial class WebRequestPSCmdlet : PSCmdlet
- {
- #region Virtual Properties
-
- #region URI
-
- ///
- /// Deprecated. Gets or sets UseBasicParsing. This has no affect on the operation of the Cmdlet.
- ///
- [Parameter(DontShow = true)]
- public virtual SwitchParameter UseBasicParsing { get; set; } = true;
-
- ///
- /// gets or sets the Uri property
- ///
- [Parameter(Position = 0, Mandatory = true)]
- [ValidateNotNullOrEmpty]
- public virtual Uri Uri { get; set; }
-
- #endregion
-
- #region Session
- ///
- /// gets or sets the Session property
- ///
- [Parameter]
- public virtual WebRequestSession WebSession { get; set; }
-
- ///
- /// gets or sets the SessionVariable property
- ///
- [Parameter]
- [Alias("SV")]
- public virtual string SessionVariable { get; set; }
-
- #endregion
-
- #region Authorization and Credentials
-
- ///
- /// Gets or sets the AllowUnencryptedAuthentication property
- ///
- [Parameter]
- public virtual SwitchParameter AllowUnencryptedAuthentication { get; set; }
-
- ///
- /// Gets or sets the Authentication property used to determin the Authentication method for the web session.
- /// Authentication does not work with UseDefaultCredentials.
- /// Authentication over unencrypted sessions requires AllowUnencryptedAuthentication.
- /// Basic: Requires Credential
- /// OAuth/Bearer: Requires Token
- ///
- [Parameter]
- public virtual WebAuthenticationType Authentication { get; set; } = WebAuthenticationType.None;
-
- ///
- /// gets or sets the Credential property
- ///
- [Parameter]
- [Credential]
- public virtual PSCredential Credential { get; set; }
-
- ///
- /// gets or sets the UseDefaultCredentials property
- ///
- [Parameter]
- public virtual SwitchParameter UseDefaultCredentials { get; set; }
-
- ///
- /// gets or sets the CertificateThumbprint property
- ///
- [Parameter]
- [ValidateNotNullOrEmpty]
- public virtual string CertificateThumbprint { get; set; }
-
- ///
- /// gets or sets the Certificate property
- ///
- [Parameter]
- [ValidateNotNull]
- public virtual X509Certificate Certificate { get; set; }
-
- ///
- /// gets or sets the SkipCertificateCheck property
- ///
- [Parameter]
- public virtual SwitchParameter SkipCertificateCheck { get; set; }
-
- ///
- /// Gets or sets the TLS/SSL protocol used by the Web Cmdlet
- ///
- [Parameter]
- public virtual WebSslProtocol SslProtocol { get; set; } = WebSslProtocol.Default;
-
- ///
- /// Gets or sets the Token property. Token is required by Authentication OAuth and Bearer.
- ///
- [Parameter]
- public virtual SecureString Token { get; set; }
-
- #endregion
-
- #region Headers
-
- ///
- /// gets or sets the UserAgent property
- ///
- [Parameter]
- public virtual string UserAgent { get; set; }
-
- ///
- /// gets or sets the DisableKeepAlive property
- ///
- [Parameter]
- public virtual SwitchParameter DisableKeepAlive { get; set; }
-
- ///
- /// gets or sets the TimeOut property
- ///
- [Parameter]
- [ValidateRange(0, Int32.MaxValue)]
- public virtual int TimeoutSec { get; set; }
-
- ///
- /// gets or sets the Headers property
- ///
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
- [Parameter]
- public virtual IDictionary Headers { get; set; }
-
- #endregion
-
- #region Redirect
-
- ///
- /// gets or sets the RedirectMax property
- ///
- [Parameter]
- [ValidateRange(0, Int32.MaxValue)]
- public virtual int MaximumRedirection
- {
- get { return _maximumRedirection; }
- set { _maximumRedirection = value; }
- }
- private int _maximumRedirection = -1;
-
- #endregion
-
- #region Method
-
- ///
- /// gets or sets the Method property
- ///
- [Parameter(ParameterSetName = "StandardMethod")]
- [Parameter(ParameterSetName = "StandardMethodNoProxy")]
- public virtual WebRequestMethod Method
- {
- get { return _method; }
- set { _method = value; }
- }
- private WebRequestMethod _method = WebRequestMethod.Default;
-
- ///
- /// gets or sets the CustomMethod property
- ///
- [Parameter(Mandatory=true,ParameterSetName = "CustomMethod")]
- [Parameter(Mandatory=true,ParameterSetName = "CustomMethodNoProxy")]
- [Alias("CM")]
- [ValidateNotNullOrEmpty]
- public virtual string CustomMethod
- {
- get { return _customMethod; }
- set { _customMethod = value; }
- }
- private string _customMethod;
-
- #endregion
-
- #region NoProxy
-
- ///
- /// gets or sets the NoProxy property
- ///
- [Parameter(Mandatory=true,ParameterSetName = "CustomMethodNoProxy")]
- [Parameter(Mandatory=true,ParameterSetName = "StandardMethodNoProxy")]
- public virtual SwitchParameter NoProxy { get; set; }
-
- #endregion
-
- #region Proxy
-
- ///
- /// gets or sets the Proxy property
- ///
- [Parameter(ParameterSetName = "StandardMethod")]
- [Parameter(ParameterSetName = "CustomMethod")]
- public virtual Uri Proxy { get; set; }
-
- ///
- /// gets or sets the ProxyCredential property
- ///
- [Parameter(ParameterSetName = "StandardMethod")]
- [Parameter(ParameterSetName = "CustomMethod")]
- [Credential]
- public virtual PSCredential ProxyCredential { get; set; }
-
- ///
- /// gets or sets the ProxyUseDefaultCredentials property
- ///
- [Parameter(ParameterSetName = "StandardMethod")]
- [Parameter(ParameterSetName = "CustomMethod")]
- public virtual SwitchParameter ProxyUseDefaultCredentials { get; set; }
-
- #endregion
-
- #region Input
-
- ///
- /// gets or sets the Body property
- ///
- [Parameter(ValueFromPipeline = true)]
- public virtual object Body { get; set; }
-
- ///
- /// gets or sets the ContentType property
- ///
- [Parameter]
- public virtual string ContentType { get; set; }
-
- ///
- /// gets or sets the TransferEncoding property
- ///
- [Parameter]
- [ValidateSet("chunked", "compress", "deflate", "gzip", "identity", IgnoreCase = true)]
- public virtual string TransferEncoding { get; set; }
-
- ///
- /// gets or sets the InFile property
- ///
- [Parameter]
- public virtual string InFile { get; set; }
-
- ///
- /// keep the original file path after the resolved provider path is
- /// assigned to InFile
- ///
- private string _originalFilePath;
-
- #endregion
-
- #region Output
-
- ///
- /// gets or sets the OutFile property
- ///
- [Parameter]
- public virtual string OutFile { get; set; }
-
- ///
- /// gets or sets the PassThrough property
- ///
- [Parameter]
- public virtual SwitchParameter PassThru { get; set; }
-
- #endregion
-
- #endregion Virtual Properties
-
- #region Virtual Methods
-
- internal virtual void ValidateParameters()
- {
- // sessions
- if ((null != WebSession) && (null != SessionVariable))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.SessionConflict,
- "WebCmdletSessionConflictException");
- ThrowTerminatingError(error);
- }
-
- // Authentication
- if (UseDefaultCredentials && (Authentication != WebAuthenticationType.None))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationConflict,
- "WebCmdletAuthenticationConflictException");
- ThrowTerminatingError(error);
- }
- if ((Authentication != WebAuthenticationType.None) && (null != Token) && (null != Credential))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationTokenConflict,
- "WebCmdletAuthenticationTokenConflictException");
- ThrowTerminatingError(error);
- }
- if ((Authentication == WebAuthenticationType.Basic) && (null == Credential))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationCredentialNotSupplied,
- "WebCmdletAuthenticationCredentialNotSuppliedException");
- ThrowTerminatingError(error);
- }
- if ((Authentication == WebAuthenticationType.OAuth || Authentication == WebAuthenticationType.Bearer) && (null == Token))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationTokenNotSupplied,
- "WebCmdletAuthenticationTokenNotSuppliedException");
- ThrowTerminatingError(error);
- }
- if (!AllowUnencryptedAuthentication && (Authentication != WebAuthenticationType.None) && (Uri.Scheme != "https"))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.AllowUnencryptedAuthenticationRequired,
- "WebCmdletAllowUnencryptedAuthenticationRequiredException");
- ThrowTerminatingError(error);
- }
- if (!AllowUnencryptedAuthentication && (null != Credential || UseDefaultCredentials) && (Uri.Scheme != "https"))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.AllowUnencryptedAuthenticationRequired,
- "WebCmdletAllowUnencryptedAuthenticationRequiredException");
- ThrowTerminatingError(error);
- }
-
- // credentials
- if (UseDefaultCredentials && (null != Credential))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.CredentialConflict,
- "WebCmdletCredentialConflictException");
- ThrowTerminatingError(error);
- }
-
- // Proxy server
- if (ProxyUseDefaultCredentials && (null != ProxyCredential))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.ProxyCredentialConflict,
- "WebCmdletProxyCredentialConflictException");
- ThrowTerminatingError(error);
- }
- else if ((null == Proxy) && ((null != ProxyCredential) || ProxyUseDefaultCredentials))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.ProxyUriNotSupplied,
- "WebCmdletProxyUriNotSuppliedException");
- ThrowTerminatingError(error);
- }
-
- // request body content
- if ((null != Body) && (null != InFile))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.BodyConflict,
- "WebCmdletBodyConflictException");
- ThrowTerminatingError(error);
- }
-
- // validate InFile path
- if (InFile != null)
- {
- ProviderInfo provider = null;
- ErrorRecord errorRecord = null;
-
- try
- {
- Collection providerPaths = GetResolvedProviderPathFromPSPath(InFile, out provider);
-
- if (!provider.Name.Equals(FileSystemProvider.ProviderName, StringComparison.OrdinalIgnoreCase))
- {
- errorRecord = GetValidationError(WebCmdletStrings.NotFilesystemPath,
- "WebCmdletInFileNotFilesystemPathException", InFile);
- }
- else
- {
- if (providerPaths.Count > 1)
- {
- errorRecord = GetValidationError(WebCmdletStrings.MultiplePathsResolved,
- "WebCmdletInFileMultiplePathsResolvedException", InFile);
- }
- else if (providerPaths.Count == 0)
- {
- errorRecord = GetValidationError(WebCmdletStrings.NoPathResolved,
- "WebCmdletInFileNoPathResolvedException", InFile);
- }
- else
- {
- if (Directory.Exists(providerPaths[0]))
- {
- errorRecord = GetValidationError(WebCmdletStrings.DirectoryPathSpecified,
- "WebCmdletInFileNotFilePathException", InFile);
- }
- _originalFilePath = InFile;
- InFile = providerPaths[0];
- }
- }
- }
- catch (ItemNotFoundException pathNotFound)
- {
- errorRecord = new ErrorRecord(pathNotFound.ErrorRecord, pathNotFound);
- }
- catch (ProviderNotFoundException providerNotFound)
- {
- errorRecord = new ErrorRecord(providerNotFound.ErrorRecord, providerNotFound);
- }
- catch (System.Management.Automation.DriveNotFoundException driveNotFound)
- {
- errorRecord = new ErrorRecord(driveNotFound.ErrorRecord, driveNotFound);
- }
-
- if (errorRecord != null)
- {
- ThrowTerminatingError(errorRecord);
- }
- }
-
- // output ??
- if (PassThru && (OutFile == null))
- {
- ErrorRecord error = GetValidationError(WebCmdletStrings.OutFileMissing,
- "WebCmdletOutFileMissingException");
- ThrowTerminatingError(error);
- }
- }
-
- internal virtual void PrepareSession()
- {
- // make sure we have a valid WebRequestSession object to work with
- if (null == WebSession)
- {
- WebSession = new WebRequestSession();
- }
-
- if (null != SessionVariable)
- {
- // save the session back to the PS environment if requested
- PSVariableIntrinsics vi = SessionState.PSVariable;
- vi.Set(SessionVariable, WebSession);
- }
-
- //
- // handle credentials
- //
- if (null != Credential && Authentication == WebAuthenticationType.None)
- {
- // get the relevant NetworkCredential
- NetworkCredential netCred = Credential.GetNetworkCredential();
- WebSession.Credentials = netCred;
-
- // supplying a credential overrides the UseDefaultCredentials setting
- WebSession.UseDefaultCredentials = false;
- }
- else if ((null != Credential || null!= Token) && Authentication != WebAuthenticationType.None)
- {
- ProcessAuthentication();
- }
- else if (UseDefaultCredentials)
- {
- WebSession.UseDefaultCredentials = true;
- }
-
-
- if (null != CertificateThumbprint)
- {
- X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
- store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
- X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
- X509Certificate2Collection tbCollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByThumbprint, CertificateThumbprint, false);
- if (tbCollection.Count == 0)
- {
- CryptographicException ex = new CryptographicException(WebCmdletStrings.ThumbprintNotFound);
- throw ex;
- }
- foreach (X509Certificate2 tbCert in tbCollection)
- {
- X509Certificate certificate = (X509Certificate)tbCert;
- WebSession.AddCertificate(certificate);
- }
- }
-
- if (null != Certificate)
- {
- WebSession.AddCertificate(Certificate);
- }
-
- //
- // handle the user agent
- //
- if (null != UserAgent)
- {
- // store the UserAgent string
- WebSession.UserAgent = UserAgent;
- }
-
- if (null != Proxy)
- {
- WebProxy webProxy = new WebProxy(Proxy);
- webProxy.BypassProxyOnLocal = false;
- if (null != ProxyCredential)
- {
- webProxy.Credentials = ProxyCredential.GetNetworkCredential();
- }
- else if (ProxyUseDefaultCredentials)
- {
- // If both ProxyCredential and ProxyUseDefaultCredentials are passed,
- // UseDefaultCredentials will overwrite the supplied credentials.
- webProxy.UseDefaultCredentials = true;
- }
- WebSession.Proxy = webProxy;
- }
-
- if (-1 < MaximumRedirection)
- {
- WebSession.MaximumRedirection = MaximumRedirection;
- }
-
- // store the other supplied headers
- if (null != Headers)
- {
- foreach (string key in Headers.Keys)
- {
- // add the header value (or overwrite it if already present)
- WebSession.Headers[key] = Headers[key].ToString();
- }
- }
- }
-
- #endregion Virtual Methods
-
- #region Helper Properties
-
- internal string QualifiedOutFile
- {
- get { return (QualifyFilePath(OutFile)); }
- }
-
- internal bool ShouldSaveToOutFile
- {
- get { return (!string.IsNullOrEmpty(OutFile)); }
- }
-
- internal bool ShouldWriteToPipeline
- {
- get { return (!ShouldSaveToOutFile || PassThru); }
- }
-
- #endregion Helper Properties
-
- #region Helper Methods
-
- private Uri PrepareUri(Uri uri)
- {
- uri = CheckProtocol(uri);
-
- // before creating the web request,
- // preprocess Body if content is a dictionary and method is GET (set as query)
- IDictionary bodyAsDictionary;
- LanguagePrimitives.TryConvertTo(Body, out bodyAsDictionary);
- if ((null != bodyAsDictionary)
- && ((IsStandardMethodSet() && (Method == WebRequestMethod.Default || Method == WebRequestMethod.Get))
- || (IsCustomMethodSet() && CustomMethod.ToUpperInvariant() == "GET")))
- {
- UriBuilder uriBuilder = new UriBuilder(uri);
- if (uriBuilder.Query != null && uriBuilder.Query.Length > 1)
- {
- uriBuilder.Query = uriBuilder.Query.Substring(1) + "&" + FormatDictionary(bodyAsDictionary);
- }
- else
- {
- uriBuilder.Query = FormatDictionary(bodyAsDictionary);
- }
- uri = uriBuilder.Uri;
- // set body to null to prevent later FillRequestStream
- Body = null;
- }
-
- return uri;
- }
-
- private Uri CheckProtocol(Uri uri)
- {
- if (null == uri) { throw new ArgumentNullException("uri"); }
-
- if (!uri.IsAbsoluteUri)
- {
- uri = new Uri("http://" + uri.OriginalString);
- }
- return (uri);
- }
-
- private string QualifyFilePath(string path)
- {
- string resolvedFilePath = PathUtils.ResolveFilePath(path, this, false);
- return resolvedFilePath;
- }
-
- private string FormatDictionary(IDictionary content)
- {
- if (content == null)
- throw new ArgumentNullException("content");
-
- StringBuilder bodyBuilder = new StringBuilder();
- foreach (string key in content.Keys)
- {
- if (0 < bodyBuilder.Length)
- {
- bodyBuilder.Append("&");
- }
-
- object value = content[key];
-
- // URLEncode the key and value
- string encodedKey = WebUtility.UrlEncode(key);
- string encodedValue = String.Empty;
- if (null != value)
- {
- encodedValue = WebUtility.UrlEncode(value.ToString());
- }
-
- bodyBuilder.AppendFormat("{0}={1}", encodedKey, encodedValue);
- }
- return bodyBuilder.ToString();
- }
-
- private ErrorRecord GetValidationError(string msg, string errorId)
- {
- var ex = new ValidationMetadataException(msg);
- var error = new ErrorRecord(ex, errorId, ErrorCategory.InvalidArgument, this);
- return (error);
- }
-
- private ErrorRecord GetValidationError(string msg, string errorId, params object[] args)
- {
- msg = string.Format(CultureInfo.InvariantCulture, msg, args);
- var ex = new ValidationMetadataException(msg);
- var error = new ErrorRecord(ex, errorId, ErrorCategory.InvalidArgument, this);
- return (error);
- }
-
- private bool IsStandardMethodSet()
- {
- return (ParameterSetName == "StandardMethod");
- }
-
- private bool IsCustomMethodSet()
- {
- return (ParameterSetName == "CustomMethod");
- }
-
- private string GetBasicAuthorizationHeader()
- {
- string unencoded = String.Format("{0}:{1}", Credential.UserName, Credential.GetNetworkCredential().Password);
- Byte[] bytes = Encoding.UTF8.GetBytes(unencoded);
- return String.Format("Basic {0}", Convert.ToBase64String(bytes));
- }
-
- private string GetBearerAuthorizationHeader()
- {
- return String.Format("Bearer {0}", new NetworkCredential(String.Empty, Token).Password);
- }
-
- private void ProcessAuthentication()
- {
- if(Authentication == WebAuthenticationType.Basic)
- {
- WebSession.Headers["Authorization"] = GetBasicAuthorizationHeader();
- }
- else if (Authentication == WebAuthenticationType.Bearer || Authentication == WebAuthenticationType.OAuth)
- {
- WebSession.Headers["Authorization"] = GetBearerAuthorizationHeader();
- }
- else
- {
- Diagnostics.Assert(false, String.Format("Unrecognized Authentication value: {0}", Authentication));
- }
- }
-
- #endregion Helper Methods
- }
-}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs
deleted file mode 100644
index 3b9d1b211e1..00000000000
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-/********************************************************************++
-Copyright (c) Microsoft Corporation. All rights reserved.
---********************************************************************/
-
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-
-namespace Microsoft.PowerShell.Commands
-{
- ///
- /// WebResponseObject
- ///
- public partial class WebResponseObject
- {
- #region Properties
-
- ///
- /// gets or protected sets the Content property
- ///
- [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
- public byte[] Content { get; protected set; }
-
- ///
- /// gets the StatusCode property
- ///
- public int StatusCode
- {
- get { return (WebResponseHelper.GetStatusCode(BaseResponse)); }
- }
-
- ///
- /// gets the StatusDescription property
- ///
- public string StatusDescription
- {
- get { return (WebResponseHelper.GetStatusDescription(BaseResponse)); }
- }
-
- private MemoryStream _rawContentStream;
- ///
- /// gets the RawContentStream property
- ///
- public MemoryStream RawContentStream
- {
- get { return (_rawContentStream); }
- }
-
- ///
- /// gets the RawContentLength property
- ///
- public long RawContentLength
- {
- get { return (null == RawContentStream ? -1 : RawContentStream.Length); }
- }
-
- ///
- /// gets or protected sets the RawContent property
- ///
- public string RawContent { get; protected set; }
-
- #endregion Properties
-
- #region Methods
-
- ///
- /// Reads the response content from the web response.
- ///
- private void InitializeContent()
- {
- this.Content = this.RawContentStream.ToArray();
- }
-
- private bool IsPrintable(char c)
- {
- return (Char.IsLetterOrDigit(c) || Char.IsPunctuation(c) || Char.IsSeparator(c) || Char.IsSymbol(c) || Char.IsWhiteSpace(c));
- }
-
- ///
- /// Returns the string representation of this web response.
- ///
- /// The string representation of this web response.
- public sealed override string ToString()
- {
- char[] stringContent = System.Text.Encoding.ASCII.GetChars(Content);
- for (int counter = 0; counter < stringContent.Length; counter++)
- {
- if (!IsPrintable(stringContent[counter]))
- {
- stringContent[counter] = '.';
- }
- }
-
- return new string(stringContent);
- }
-
- #endregion Methods
- }
-}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ContentHelper.Common.cs
similarity index 73%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ContentHelper.Common.cs
index b7d9d0afc7a..aeca26eef61 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ContentHelper.Common.cs
@@ -3,13 +3,15 @@
--********************************************************************/
using System;
+using System.Net.Http;
+using System.Net.Http.Headers;
using System.Management.Automation;
using System.Text;
using Microsoft.Win32;
namespace Microsoft.PowerShell.Commands
{
- internal static partial class ContentHelper
+ internal static class ContentHelper
{
#region Constants
@@ -23,6 +25,19 @@ internal static partial class ContentHelper
#region Internal Methods
+ internal static Encoding GetEncoding(HttpResponseMessage response)
+ {
+ // ContentType may not exist in response header.
+ string charSet = response.Content.Headers.ContentType?.CharSet;
+ return GetEncodingOrDefault(charSet);
+ }
+
+ internal static string GetContentType(HttpResponseMessage response)
+ {
+ // ContentType may not exist in response header. Return null if not.
+ return response.Content.Headers.ContentType?.MediaType;
+ }
+
internal static bool IsText(string contentType)
{
contentType = GetContentTypeSignature(contentType);
@@ -65,6 +80,48 @@ internal static Encoding GetDefaultEncoding()
return GetEncodingOrDefault((string)null);
}
+ internal static StringBuilder GetRawContentHeader(HttpResponseMessage response)
+ {
+ StringBuilder raw = new StringBuilder();
+
+ string protocol = WebResponseHelper.GetProtocol(response);
+ if (!string.IsNullOrEmpty(protocol))
+ {
+ int statusCode = WebResponseHelper.GetStatusCode(response);
+ string statusDescription = WebResponseHelper.GetStatusDescription(response);
+ raw.AppendFormat("{0} {1} {2}", protocol, statusCode, statusDescription);
+ raw.AppendLine();
+ }
+
+ HttpHeaders[] headerCollections =
+ {
+ response.Headers,
+ response.Content == null ? null : response.Content.Headers
+ };
+
+ foreach (var headerCollection in headerCollections)
+ {
+ if (headerCollection == null)
+ {
+ continue;
+ }
+ foreach (var header in headerCollection)
+ {
+ // Headers may have multiple entries with different values
+ foreach (var headerValue in header.Value)
+ {
+ raw.Append(header.Key);
+ raw.Append(": ");
+ raw.Append(headerValue);
+ raw.AppendLine();
+ }
+ }
+ }
+
+ raw.AppendLine();
+ return raw;
+ }
+
#endregion Internal Methods
#region Private Helper Methods
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/BasicHtmlWebResponseObject.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/BasicHtmlWebResponseObject.CoreClr.cs
deleted file mode 100644
index 1a8436b1255..00000000000
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/BasicHtmlWebResponseObject.CoreClr.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/********************************************************************++
-Copyright (c) Microsoft Corporation. All rights reserved.
---********************************************************************/
-
-using System.Net.Http;
-using System.IO;
-using System.Text;
-
-namespace Microsoft.PowerShell.Commands
-{
- ///
- /// Response object for html content without DOM parsing
- ///
- public partial class BasicHtmlWebResponseObject : WebResponseObject
- {
- #region Constructors
-
- ///
- /// Constructor for BasicHtmlWebResponseObject
- ///
- ///
- public BasicHtmlWebResponseObject(HttpResponseMessage response)
- : this(response, null)
- { }
-
- ///
- /// Constructor for HtmlWebResponseObject with memory stream
- ///
- ///
- ///
- public BasicHtmlWebResponseObject(HttpResponseMessage response, Stream contentStream)
- : base(response, contentStream)
- {
- EnsureHtmlParser();
- InitializeContent();
- InitializeRawContent(response);
- }
-
- #endregion Constructors
-
- #region Methods
-
- private void InitializeRawContent(HttpResponseMessage baseResponse)
- {
- StringBuilder raw = ContentHelper.GetRawContentHeader(baseResponse);
- raw.Append(Content);
- this.RawContent = raw.ToString();
- }
-
- #endregion Methods
- }
-}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/ContentHelper.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/ContentHelper.CoreClr.cs
deleted file mode 100644
index c10ee36b001..00000000000
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/ContentHelper.CoreClr.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-/********************************************************************++
-Copyright (c) Microsoft Corporation. All rights reserved.
---********************************************************************/
-
-using System.Text;
-using System.Linq;
-using System.Net.Http;
-using System.Net.Http.Headers;
-
-namespace Microsoft.PowerShell.Commands
-{
- internal static partial class ContentHelper
- {
- internal static Encoding GetEncoding(HttpResponseMessage response)
- {
- // ContentType may not exist in response header.
- string charSet = response.Content.Headers.ContentType?.CharSet;
- return GetEncodingOrDefault(charSet);
- }
-
- internal static string GetContentType(HttpResponseMessage response)
- {
- // ContentType may not exist in response header. Return null if not.
- return response.Content.Headers.ContentType?.MediaType;
- }
-
- internal static StringBuilder GetRawContentHeader(HttpResponseMessage response)
- {
- StringBuilder raw = new StringBuilder();
-
- string protocol = WebResponseHelper.GetProtocol(response);
- if (!string.IsNullOrEmpty(protocol))
- {
- int statusCode = WebResponseHelper.GetStatusCode(response);
- string statusDescription = WebResponseHelper.GetStatusDescription(response);
- raw.AppendFormat("{0} {1} {2}", protocol, statusCode, statusDescription);
- raw.AppendLine();
- }
-
- HttpHeaders[] headerCollections =
- {
- response.Headers,
- response.Content == null ? null : response.Content.Headers
- };
-
- foreach (var headerCollection in headerCollections)
- {
- if (headerCollection == null)
- {
- continue;
- }
- foreach (var header in headerCollection)
- {
- // Headers may have multiple entries with different values
- foreach (var headerValue in header.Value)
- {
- raw.Append(header.Key);
- raw.Append(": ");
- raw.Append(headerValue);
- raw.AppendLine();
- }
- }
- }
-
- raw.AppendLine();
- return raw;
- }
- }
-}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeRestMethodCommand.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeRestMethodCommand.CoreClr.cs
deleted file mode 100644
index eabb9fc0183..00000000000
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeRestMethodCommand.CoreClr.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-/********************************************************************++
-Copyright (c) Microsoft Corporation. All rights reserved.
---********************************************************************/
-
-using System;
-using System.Management.Automation;
-using System.Net.Http;
-using System.Text;
-
-namespace Microsoft.PowerShell.Commands
-{
- ///
- /// The Invoke-RestMethod command
- /// This command makes an HTTP or HTTPS request to a web service,
- /// and returns the response in an appropriate way.
- /// Intended to work against the wide spectrum of "RESTful" web services
- /// currently deployed across the web.
- ///
- [Cmdlet(VerbsLifecycle.Invoke, "RestMethod", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=217034", DefaultParameterSetName = "StandardMethod")]
- public partial class InvokeRestMethodCommand : WebRequestPSCmdlet
- {
- #region Virtual Method Overrides
-
- ///
- /// Process the web response and output corresponding objects.
- ///
- ///
- internal override void ProcessResponse(HttpResponseMessage response)
- {
- if (null == response) { throw new ArgumentNullException("response"); }
-
- using (BufferingStreamReader responseStream = new BufferingStreamReader(StreamHelper.GetResponseStream(response)))
- {
- if (ShouldWriteToPipeline)
- {
- // First see if it is an RSS / ATOM feed, in which case we can
- // stream it - unless the user has overridden it with a return type of "XML"
- if (TryProcessFeedStream(responseStream))
- {
- // Do nothing, content has been processed.
- }
- else
- {
- // determine the response type
- RestReturnType returnType = CheckReturnType(response);
-
- // Try to get the response encoding from the ContentType header.
- Encoding encoding = null;
- string charSet = response.Content.Headers.ContentType?.CharSet;
- if (!string.IsNullOrEmpty(charSet))
- {
- // NOTE: Don't use ContentHelper.GetEncoding; it returns a
- // default which bypasses checking for a meta charset value.
- StreamHelper.TryGetEncoding(charSet, out encoding);
- }
-
- object obj = null;
- Exception ex = null;
-
- string str = StreamHelper.DecodeStream(responseStream, ref encoding);
- // NOTE: Tests use this verbose output to verify the encoding.
- WriteVerbose(string.Format
- (
- System.Globalization.CultureInfo.InvariantCulture,
- "Content encoding: {0}",
- string.IsNullOrEmpty(encoding.HeaderName) ? encoding.EncodingName : encoding.HeaderName)
- );
- bool convertSuccess = false;
-
- if (returnType == RestReturnType.Json)
- {
- convertSuccess = TryConvertToJson(str, out obj, ref ex) || TryConvertToXml(str, out obj, ref ex);
- }
- // default to try xml first since it's more common
- else
- {
- convertSuccess = TryConvertToXml(str, out obj, ref ex) || TryConvertToJson(str, out obj, ref ex);
- }
-
- if (!convertSuccess)
- {
- // fallback to string
- obj = str;
- }
-
- WriteObject(obj);
- }
- }
-
- if (ShouldSaveToOutFile)
- {
- StreamHelper.SaveStreamToFile(responseStream, QualifiedOutFile, this);
- }
-
- if (!String.IsNullOrEmpty(ResponseHeadersVariable))
- {
- PSVariableIntrinsics vi = SessionState.PSVariable;
- vi.Set(ResponseHeadersVariable, WebResponseHelper.GetHeadersDictionary(response));
- }
- }
- }
-
- #endregion Virtual Method Overrides
-
- #region Helper Methods
-
- private RestReturnType CheckReturnType(HttpResponseMessage response)
- {
- if (null == response) { throw new ArgumentNullException("response"); }
-
- RestReturnType rt = RestReturnType.Detect;
- string contentType = ContentHelper.GetContentType(response);
- if (string.IsNullOrEmpty(contentType))
- {
- rt = RestReturnType.Detect;
- }
- else if (ContentHelper.IsJson(contentType))
- {
- rt = RestReturnType.Json;
- }
- else if (ContentHelper.IsXml(contentType))
- {
- rt = RestReturnType.Xml;
- }
-
- return (rt);
- }
-
- #endregion Helper Methods
- }
-}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/HttpKnownHeaderNames.cs
similarity index 98%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/HttpKnownHeaderNames.cs
index 944df03eb4e..0c64e02f8bf 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/HttpKnownHeaderNames.cs
@@ -7,7 +7,7 @@
namespace Microsoft.PowerShell.Commands
{
- internal static partial class HttpKnownHeaderNames
+ internal static class HttpKnownHeaderNames
{
#region Known_HTTP_Header_Names
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/InvokeRestMethodCommand.Common.cs
similarity index 69%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/InvokeRestMethodCommand.Common.cs
index a755b1d4d0b..e330ea311a6 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/InvokeRestMethodCommand.Common.cs
@@ -3,15 +3,25 @@
--********************************************************************/
using System;
-using System.Management.Automation;
using System.IO;
+using System.Net.Http;
+using System.Management.Automation;
+using System.Text;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.PowerShell.Commands
{
- public partial class InvokeRestMethodCommand
+ ///
+ /// The Invoke-RestMethod command
+ /// This command makes an HTTP or HTTPS request to a web service,
+ /// and returns the response in an appropriate way.
+ /// Intended to work against the wide spectrum of "RESTful" web services
+ /// currently deployed across the web.
+ ///
+ [Cmdlet(VerbsLifecycle.Invoke, "RestMethod", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=217034", DefaultParameterSetName = "StandardMethod")]
+ public class InvokeRestMethodCommand : WebRequestPSCmdlet
{
#region Parameters
@@ -71,8 +81,114 @@ public int MaximumFollowRelLink
#endregion Parameters
+ #region Virtual Method Overrides
+
+ ///
+ /// Process the web response and output corresponding objects.
+ ///
+ ///
+ internal override void ProcessResponse(HttpResponseMessage response)
+ {
+ if (null == response) { throw new ArgumentNullException("response"); }
+
+ using (BufferingStreamReader responseStream = new BufferingStreamReader(StreamHelper.GetResponseStream(response)))
+ {
+ if (ShouldWriteToPipeline)
+ {
+ // First see if it is an RSS / ATOM feed, in which case we can
+ // stream it - unless the user has overridden it with a return type of "XML"
+ if (TryProcessFeedStream(responseStream))
+ {
+ // Do nothing, content has been processed.
+ }
+ else
+ {
+ // determine the response type
+ RestReturnType returnType = CheckReturnType(response);
+
+ // Try to get the response encoding from the ContentType header.
+ Encoding encoding = null;
+ string charSet = response.Content.Headers.ContentType?.CharSet;
+ if (!string.IsNullOrEmpty(charSet))
+ {
+ // NOTE: Don't use ContentHelper.GetEncoding; it returns a
+ // default which bypasses checking for a meta charset value.
+ StreamHelper.TryGetEncoding(charSet, out encoding);
+ }
+
+ object obj = null;
+ Exception ex = null;
+
+ string str = StreamHelper.DecodeStream(responseStream, ref encoding);
+ // NOTE: Tests use this verbose output to verify the encoding.
+ WriteVerbose(string.Format
+ (
+ System.Globalization.CultureInfo.InvariantCulture,
+ "Content encoding: {0}",
+ string.IsNullOrEmpty(encoding.HeaderName) ? encoding.EncodingName : encoding.HeaderName)
+ );
+ bool convertSuccess = false;
+
+ if (returnType == RestReturnType.Json)
+ {
+ convertSuccess = TryConvertToJson(str, out obj, ref ex) || TryConvertToXml(str, out obj, ref ex);
+ }
+ // default to try xml first since it's more common
+ else
+ {
+ convertSuccess = TryConvertToXml(str, out obj, ref ex) || TryConvertToJson(str, out obj, ref ex);
+ }
+
+ if (!convertSuccess)
+ {
+ // fallback to string
+ obj = str;
+ }
+
+ WriteObject(obj);
+ }
+ }
+
+ if (ShouldSaveToOutFile)
+ {
+ StreamHelper.SaveStreamToFile(responseStream, QualifiedOutFile, this);
+ }
+
+ if (!String.IsNullOrEmpty(ResponseHeadersVariable))
+ {
+ PSVariableIntrinsics vi = SessionState.PSVariable;
+ vi.Set(ResponseHeadersVariable, WebResponseHelper.GetHeadersDictionary(response));
+ }
+ }
+ }
+
+ #endregion Virtual Method Overrides
+
+
#region Helper Methods
+ private RestReturnType CheckReturnType(HttpResponseMessage response)
+ {
+ if (null == response) { throw new ArgumentNullException("response"); }
+
+ RestReturnType rt = RestReturnType.Detect;
+ string contentType = ContentHelper.GetContentType(response);
+ if (string.IsNullOrEmpty(contentType))
+ {
+ rt = RestReturnType.Detect;
+ }
+ else if (ContentHelper.IsJson(contentType))
+ {
+ rt = RestReturnType.Json;
+ }
+ else if (ContentHelper.IsXml(contentType))
+ {
+ rt = RestReturnType.Xml;
+ }
+
+ return (rt);
+ }
+
private bool TryProcessFeedStream(BufferingStreamReader responseStream)
{
bool isRssOrFeed = false;
@@ -343,4 +459,4 @@ public override void Write(byte[] buffer, int offset, int count)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/InvokeWebRequestCommand.CoreClr.cs
similarity index 100%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/InvokeWebRequestCommand.CoreClr.cs
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebProxy.cs
similarity index 100%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebProxy.cs
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestPSCmdlet.Common.cs
similarity index 57%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestPSCmdlet.Common.cs
index 0163b5f0958..7fa6a9f6987 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestPSCmdlet.Common.cs
@@ -1,26 +1,31 @@
-/********************************************************************++
+/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Globalization;
+using System.IO;
+using System.Linq;
using System.Management.Automation;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
-using System.IO;
-using System.Text;
-using System.Collections;
-using System.Globalization;
+using System.Security;
using System.Security.Authentication;
using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
-using System.Collections.Generic;
-using System.Text.RegularExpressions;
-using System.Linq;
+using Microsoft.Win32;
namespace Microsoft.PowerShell.Commands
{
+
///
/// Exception class for webcmdlets to enable returning HTTP error response
///
@@ -42,11 +47,146 @@ public HttpResponseException (string message, HttpResponseMessage response) : ba
public HttpResponseMessage Response { get; private set; }
}
+ ///
+ /// The valid values for the -Authentication parameter for Invoke-RestMethod and Invoke-WebRequest
+ ///
+ public enum WebAuthenticationType
+ {
+ ///
+ /// No authentication. Default.
+ ///
+ None,
+
+ ///
+ /// RFC-7617 Basic Authentication. Requires -Credential
+ ///
+ Basic,
+
+ ///
+ /// RFC-6750 OAuth 2.0 Bearer Authentication. Requires -Token
+ ///
+ Bearer,
+
+ ///
+ /// RFC-6750 OAuth 2.0 Bearer Authentication. Requires -Token
+ ///
+ OAuth,
+ }
+
+ // WebSslProtocol is used because not all SslProtocols are supported by HttpClientHandler.
+ // Also SslProtocols.Default is not the "default" for HttpClientHandler as SslProtocols.Ssl3 is not supported.
+ ///
+ /// The valid values for the -SslProtocol parameter for Invoke-RestMethod and Invoke-WebRequest
+ ///
+ [Flags]
+ public enum WebSslProtocol
+ {
+ ///
+ /// No SSL protocol will be set and the system defaults will be used.
+ ///
+ Default = 0,
+
+ ///
+ /// Specifies the TLS 1.0 security protocol. The TLS protocol is defined in IETF RFC 2246.
+ ///
+ Tls = SslProtocols.Tls,
+
+ ///
+ /// Specifies the TLS 1.1 security protocol. The TLS protocol is defined in IETF RFC 4346.
+ ///
+ Tls11 = SslProtocols.Tls11,
+
+ ///
+ /// Specifies the TLS 1.2 security protocol. The TLS protocol is defined in IETF RFC 5246
+ ///
+ Tls12 = SslProtocols.Tls12
+ }
+
///
/// Base class for Invoke-RestMethod and Invoke-WebRequest commands.
///
- public abstract partial class WebRequestPSCmdlet : PSCmdlet
+ public abstract class WebRequestPSCmdlet : PSCmdlet
{
+
+ #region Virtual Properties
+
+ #region URI
+
+ ///
+ /// Deprecated. Gets or sets UseBasicParsing. This has no affect on the operation of the Cmdlet.
+ ///
+ [Parameter(DontShow = true)]
+ public virtual SwitchParameter UseBasicParsing { get; set; } = true;
+
+ ///
+ /// gets or sets the Uri property
+ ///
+ [Parameter(Position = 0, Mandatory = true)]
+ [ValidateNotNullOrEmpty]
+ public virtual Uri Uri { get; set; }
+
+ #endregion
+
+ #region Session
+ ///
+ /// gets or sets the Session property
+ ///
+ [Parameter]
+ public virtual WebRequestSession WebSession { get; set; }
+
+ ///
+ /// gets or sets the SessionVariable property
+ ///
+ [Parameter]
+ [Alias("SV")]
+ public virtual string SessionVariable { get; set; }
+
+ #endregion
+
+ #region Authorization and Credentials
+
+ ///
+ /// Gets or sets the AllowUnencryptedAuthentication property
+ ///
+ [Parameter]
+ public virtual SwitchParameter AllowUnencryptedAuthentication { get; set; }
+
+ ///
+ /// Gets or sets the Authentication property used to determin the Authentication method for the web session.
+ /// Authentication does not work with UseDefaultCredentials.
+ /// Authentication over unencrypted sessions requires AllowUnencryptedAuthentication.
+ /// Basic: Requires Credential
+ /// OAuth/Bearer: Requires Token
+ ///
+ [Parameter]
+ public virtual WebAuthenticationType Authentication { get; set; } = WebAuthenticationType.None;
+
+ ///
+ /// gets or sets the Credential property
+ ///
+ [Parameter]
+ [Credential]
+ public virtual PSCredential Credential { get; set; }
+
+ ///
+ /// gets or sets the UseDefaultCredentials property
+ ///
+ [Parameter]
+ public virtual SwitchParameter UseDefaultCredentials { get; set; }
+
+ ///
+ /// gets or sets the CertificateThumbprint property
+ ///
+ [Parameter]
+ [ValidateNotNullOrEmpty]
+ public virtual string CertificateThumbprint { get; set; }
+
+ ///
+ /// gets or sets the Certificate property
+ ///
+ [Parameter]
+ [ValidateNotNull]
+ public virtual X509Certificate Certificate { get; set; }
///
/// gets or sets the PreserveAuthorizationOnRedirect property
@@ -63,6 +203,54 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet
[Parameter]
public virtual SwitchParameter PreserveAuthorizationOnRedirect { get; set; }
+ ///
+ /// gets or sets the SkipCertificateCheck property
+ ///
+ [Parameter]
+ public virtual SwitchParameter SkipCertificateCheck { get; set; }
+
+ ///
+ /// Gets or sets the TLS/SSL protocol used by the Web Cmdlet
+ ///
+ [Parameter]
+ public virtual WebSslProtocol SslProtocol { get; set; } = WebSslProtocol.Default;
+
+ ///
+ /// Gets or sets the Token property. Token is required by Authentication OAuth and Bearer.
+ ///
+ [Parameter]
+ public virtual SecureString Token { get; set; }
+
+ #endregion
+
+ #region Headers
+
+ ///
+ /// gets or sets the UserAgent property
+ ///
+ [Parameter]
+ public virtual string UserAgent { get; set; }
+
+ ///
+ /// gets or sets the DisableKeepAlive property
+ ///
+ [Parameter]
+ public virtual SwitchParameter DisableKeepAlive { get; set; }
+
+ ///
+ /// gets or sets the TimeOut property
+ ///
+ [Parameter]
+ [ValidateRange(0, Int32.MaxValue)]
+ public virtual int TimeoutSec { get; set; }
+
+ ///
+ /// gets or sets the Headers property
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+ [Parameter]
+ public virtual IDictionary Headers { get; set; }
+
///
/// gets or sets the SkipHeaderValidation property
///
@@ -72,16 +260,145 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet
[Parameter]
public virtual SwitchParameter SkipHeaderValidation { get; set; }
- #region Abstract Methods
+ #endregion
+
+ #region Redirect
///
- /// Read the supplied WebResponse object and push the
- /// resulting output into the pipeline.
+ /// gets or sets the RedirectMax property
///
- /// Instance of a WebResponse object to be processed
- internal abstract void ProcessResponse(HttpResponseMessage response);
+ [Parameter]
+ [ValidateRange(0, Int32.MaxValue)]
+ public virtual int MaximumRedirection
+ {
+ get { return _maximumRedirection; }
+ set { _maximumRedirection = value; }
+ }
+ private int _maximumRedirection = -1;
- #endregion Abstract Methods
+ #endregion
+
+ #region Method
+
+ ///
+ /// gets or sets the Method property
+ ///
+ [Parameter(ParameterSetName = "StandardMethod")]
+ [Parameter(ParameterSetName = "StandardMethodNoProxy")]
+ public virtual WebRequestMethod Method
+ {
+ get { return _method; }
+ set { _method = value; }
+ }
+ private WebRequestMethod _method = WebRequestMethod.Default;
+
+ ///
+ /// gets or sets the CustomMethod property
+ ///
+ [Parameter(Mandatory=true,ParameterSetName = "CustomMethod")]
+ [Parameter(Mandatory=true,ParameterSetName = "CustomMethodNoProxy")]
+ [Alias("CM")]
+ [ValidateNotNullOrEmpty]
+ public virtual string CustomMethod
+ {
+ get { return _customMethod; }
+ set { _customMethod = value; }
+ }
+ private string _customMethod;
+
+ #endregion
+
+ #region NoProxy
+
+ ///
+ /// gets or sets the NoProxy property
+ ///
+ [Parameter(Mandatory=true,ParameterSetName = "CustomMethodNoProxy")]
+ [Parameter(Mandatory=true,ParameterSetName = "StandardMethodNoProxy")]
+ public virtual SwitchParameter NoProxy { get; set; }
+
+ #endregion
+
+ #region Proxy
+
+ ///
+ /// gets or sets the Proxy property
+ ///
+ [Parameter(ParameterSetName = "StandardMethod")]
+ [Parameter(ParameterSetName = "CustomMethod")]
+ public virtual Uri Proxy { get; set; }
+
+ ///
+ /// gets or sets the ProxyCredential property
+ ///
+ [Parameter(ParameterSetName = "StandardMethod")]
+ [Parameter(ParameterSetName = "CustomMethod")]
+ [Credential]
+ public virtual PSCredential ProxyCredential { get; set; }
+
+ ///
+ /// gets or sets the ProxyUseDefaultCredentials property
+ ///
+ [Parameter(ParameterSetName = "StandardMethod")]
+ [Parameter(ParameterSetName = "CustomMethod")]
+ public virtual SwitchParameter ProxyUseDefaultCredentials { get; set; }
+
+ #endregion
+
+ #region Input
+
+ ///
+ /// gets or sets the Body property
+ ///
+ [Parameter(ValueFromPipeline = true)]
+ public virtual object Body { get; set; }
+
+ ///
+ /// gets or sets the ContentType property
+ ///
+ [Parameter]
+ public virtual string ContentType { get; set; }
+
+ ///
+ /// gets or sets the TransferEncoding property
+ ///
+ [Parameter]
+ [ValidateSet("chunked", "compress", "deflate", "gzip", "identity", IgnoreCase = true)]
+ public virtual string TransferEncoding { get; set; }
+
+ ///
+ /// gets or sets the InFile property
+ ///
+ [Parameter]
+ public virtual string InFile { get; set; }
+
+ ///
+ /// keep the original file path after the resolved provider path is
+ /// assigned to InFile
+ ///
+ private string _originalFilePath;
+
+ #endregion
+
+ #region Output
+
+ ///
+ /// gets or sets the OutFile property
+ ///
+ [Parameter]
+ public virtual string OutFile { get; set; }
+
+ ///
+ /// gets or sets the PassThrough property
+ ///
+ [Parameter]
+ public virtual SwitchParameter PassThru { get; set; }
+
+ #endregion
+
+ #endregion Virtual Properties
+
+ #region Private Properties
///
/// Cancellation token source
@@ -108,32 +425,104 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet
///
internal int _maximumFollowRelLink = Int32.MaxValue;
- private HttpMethod GetHttpMethod(WebRequestMethod method)
+ #endregion
+
+ #region Virtual Methods
+
+ internal virtual void FillRequestStream(HttpRequestMessage request)
{
- switch (Method)
+ if (null == request) { throw new ArgumentNullException("request"); }
+
+ // set the content type
+ if (ContentType != null)
{
- case WebRequestMethod.Default:
- case WebRequestMethod.Get:
- return HttpMethod.Get;
- case WebRequestMethod.Head:
- return HttpMethod.Head;
- case WebRequestMethod.Post:
- return HttpMethod.Post;
- case WebRequestMethod.Put:
- return HttpMethod.Put;
- case WebRequestMethod.Delete:
- return HttpMethod.Delete;
- case WebRequestMethod.Trace:
- return HttpMethod.Trace;
- case WebRequestMethod.Options:
- return HttpMethod.Options;
- default:
- // Merge and Patch
- return new HttpMethod(Method.ToString().ToUpperInvariant());
+ WebSession.ContentHeaders[HttpKnownHeaderNames.ContentType] = ContentType;
+ //request
+ }
+ // ContentType == null
+ else if (Method == WebRequestMethod.Post || (IsCustomMethodSet() && CustomMethod.ToUpperInvariant() == "POST"))
+ {
+ // Win8:545310 Invoke-WebRequest does not properly set MIME type for POST
+ string contentType = null;
+ WebSession.ContentHeaders.TryGetValue(HttpKnownHeaderNames.ContentType, out contentType);
+ if (string.IsNullOrEmpty(contentType))
+ {
+ WebSession.ContentHeaders[HttpKnownHeaderNames.ContentType] = "application/x-www-form-urlencoded";
+ }
}
- }
- #region Virtual Methods
+ // coerce body into a usable form
+ if (Body != null)
+ {
+ object content = Body;
+
+ // make sure we're using the base object of the body, not the PSObject wrapper
+ PSObject psBody = Body as PSObject;
+ if (psBody != null)
+ {
+ content = psBody.BaseObject;
+ }
+
+ if (content is FormObject)
+ {
+ FormObject form = content as FormObject;
+ SetRequestContent(request, form.Fields);
+ }
+ else if (content is IDictionary && request.Method != HttpMethod.Get)
+ {
+ IDictionary dictionary = content as IDictionary;
+ SetRequestContent(request, dictionary);
+ }
+ else if (content is XmlNode)
+ {
+ XmlNode xmlNode = content as XmlNode;
+ SetRequestContent(request, xmlNode);
+ }
+ else if (content is Stream)
+ {
+ Stream stream = content as Stream;
+ SetRequestContent(request, stream);
+ }
+ else if (content is byte[])
+ {
+ byte[] bytes = content as byte[];
+ SetRequestContent(request, bytes);
+ }
+ else if (content is MultipartFormDataContent multipartFormDataContent)
+ {
+ WebSession.ContentHeaders.Clear();
+ SetRequestContent(request, multipartFormDataContent);
+ }
+ else
+ {
+ SetRequestContent(request,
+ (string)LanguagePrimitives.ConvertTo(content, typeof(string), CultureInfo.InvariantCulture));
+ }
+ }
+ else if (InFile != null) // copy InFile data
+ {
+ try
+ {
+ // open the input file
+ SetRequestContent(request, new FileStream(InFile, FileMode.Open));
+ }
+ catch (UnauthorizedAccessException)
+ {
+ string msg = string.Format(CultureInfo.InvariantCulture, WebCmdletStrings.AccessDenied,
+ _originalFilePath);
+ throw new UnauthorizedAccessException(msg);
+ }
+ }
+
+ // Add the content headers
+ if (request.Content != null)
+ {
+ foreach (var entry in WebSession.ContentHeaders)
+ {
+ request.Content.Headers.Add(entry.Key, entry.Value);
+ }
+ }
+ }
// NOTE: Only pass true for handleRedirect if the original request has an authorization header
// and PreserveAuthorizationOnRedirect is NOT set.
@@ -319,99 +708,43 @@ internal virtual HttpRequestMessage GetRequest(Uri uri, bool stripAuthorization)
return (request);
}
- internal virtual void FillRequestStream(HttpRequestMessage request)
+ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool stripAuthorization)
{
- if (null == request) { throw new ArgumentNullException("request"); }
+ if (client == null) { throw new ArgumentNullException("client"); }
+ if (request == null) { throw new ArgumentNullException("request"); }
- // set the content type
- if (ContentType != null)
- {
- WebSession.ContentHeaders[HttpKnownHeaderNames.ContentType] = ContentType;
- //request
- }
- // ContentType == null
- else if (Method == WebRequestMethod.Post || (IsCustomMethodSet() && CustomMethod.ToUpperInvariant() == "POST"))
- {
- // Win8:545310 Invoke-WebRequest does not properly set MIME type for POST
- string contentType = null;
- WebSession.ContentHeaders.TryGetValue(HttpKnownHeaderNames.ContentType, out contentType);
- if (string.IsNullOrEmpty(contentType))
- {
- WebSession.ContentHeaders[HttpKnownHeaderNames.ContentType] = "application/x-www-form-urlencoded";
- }
- }
+ _cancelToken = new CancellationTokenSource();
+ HttpResponseMessage response = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult();
- // coerce body into a usable form
- if (Body != null)
+ if (stripAuthorization && IsRedirectCode(response.StatusCode))
{
- object content = Body;
-
- // make sure we're using the base object of the body, not the PSObject wrapper
- PSObject psBody = Body as PSObject;
- if (psBody != null)
- {
- content = psBody.BaseObject;
- }
+ _cancelToken.Cancel();
+ _cancelToken = null;
- if (content is FormObject)
- {
- FormObject form = content as FormObject;
- SetRequestContent(request, form.Fields);
- }
- else if (content is IDictionary && request.Method != HttpMethod.Get)
- {
- IDictionary dictionary = content as IDictionary;
- SetRequestContent(request, dictionary);
- }
- else if (content is XmlNode)
- {
- XmlNode xmlNode = content as XmlNode;
- SetRequestContent(request, xmlNode);
- }
- else if (content is Stream)
- {
- Stream stream = content as Stream;
- SetRequestContent(request, stream);
- }
- else if (content is byte[])
- {
- byte[] bytes = content as byte[];
- SetRequestContent(request, bytes);
- }
- else if (content is MultipartFormDataContent multipartFormDataContent)
- {
- WebSession.ContentHeaders.Clear();
- SetRequestContent(request, multipartFormDataContent);
- }
- else
- {
- SetRequestContent(request,
- (string)LanguagePrimitives.ConvertTo(content, typeof(string), CultureInfo.InvariantCulture));
- }
- }
- else if (InFile != null) // copy InFile data
- {
- try
- {
- // open the input file
- SetRequestContent(request, new FileStream(InFile, FileMode.Open));
+ // if explicit count was provided, reduce it for this redirection.
+ if (WebSession.MaximumRedirection > 0)
+ {
+ WebSession.MaximumRedirection--;
}
- catch (UnauthorizedAccessException)
+ // For selected redirects that used POST, GET must be used with the
+ // redirected Location.
+ // Since GET is the default; POST only occurs when -Method POST is used.
+ if (Method == WebRequestMethod.Post && IsRedirectToGet(response.StatusCode))
{
- string msg = string.Format(CultureInfo.InvariantCulture, WebCmdletStrings.AccessDenied,
- _originalFilePath);
- throw new UnauthorizedAccessException(msg);
+ // See https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx
+ Method = WebRequestMethod.Get;
}
- }
- // Add the content headers
- if (request.Content != null)
- {
- foreach (var entry in WebSession.ContentHeaders)
+ // recreate the HttpClient with redirection enabled since the first call suppressed redirection
+ using (client = GetHttpClient(false))
+ using (HttpRequestMessage redirectRequest = GetRequest(response.Headers.Location, stripAuthorization:true))
{
- request.Content.Headers.Add(entry.Key, entry.Value);
+ FillRequestStream(redirectRequest);
+ _cancelToken = new CancellationTokenSource();
+ response = client.SendAsync(redirectRequest, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult();
}
}
+ return response;
}
// Returns true if the status code is one of the supported redirection codes.
@@ -448,52 +781,290 @@ static bool IsRedirectToGet(HttpStatusCode code)
);
}
- internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool stripAuthorization)
+ internal virtual void UpdateSession(HttpResponseMessage response)
{
- if (client == null) { throw new ArgumentNullException("client"); }
- if (request == null) { throw new ArgumentNullException("request"); }
+ if (response == null) { throw new ArgumentNullException("response"); }
+ }
- _cancelToken = new CancellationTokenSource();
- HttpResponseMessage response = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult();
+ internal virtual void ValidateParameters()
+ {
+ // sessions
+ if ((null != WebSession) && (null != SessionVariable))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.SessionConflict,
+ "WebCmdletSessionConflictException");
+ ThrowTerminatingError(error);
+ }
- if (stripAuthorization && IsRedirectCode(response.StatusCode))
+ // Authentication
+ if (UseDefaultCredentials && (Authentication != WebAuthenticationType.None))
{
- _cancelToken.Cancel();
- _cancelToken = null;
+ ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationConflict,
+ "WebCmdletAuthenticationConflictException");
+ ThrowTerminatingError(error);
+ }
+ if ((Authentication != WebAuthenticationType.None) && (null != Token) && (null != Credential))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationTokenConflict,
+ "WebCmdletAuthenticationTokenConflictException");
+ ThrowTerminatingError(error);
+ }
+ if ((Authentication == WebAuthenticationType.Basic) && (null == Credential))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationCredentialNotSupplied,
+ "WebCmdletAuthenticationCredentialNotSuppliedException");
+ ThrowTerminatingError(error);
+ }
+ if ((Authentication == WebAuthenticationType.OAuth || Authentication == WebAuthenticationType.Bearer) && (null == Token))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationTokenNotSupplied,
+ "WebCmdletAuthenticationTokenNotSuppliedException");
+ ThrowTerminatingError(error);
+ }
+ if (!AllowUnencryptedAuthentication && (Authentication != WebAuthenticationType.None) && (Uri.Scheme != "https"))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.AllowUnencryptedAuthenticationRequired,
+ "WebCmdletAllowUnencryptedAuthenticationRequiredException");
+ ThrowTerminatingError(error);
+ }
+ if (!AllowUnencryptedAuthentication && (null != Credential || UseDefaultCredentials) && (Uri.Scheme != "https"))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.AllowUnencryptedAuthenticationRequired,
+ "WebCmdletAllowUnencryptedAuthenticationRequiredException");
+ ThrowTerminatingError(error);
+ }
- // if explicit count was provided, reduce it for this redirection.
- if (WebSession.MaximumRedirection > 0)
+ // credentials
+ if (UseDefaultCredentials && (null != Credential))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.CredentialConflict,
+ "WebCmdletCredentialConflictException");
+ ThrowTerminatingError(error);
+ }
+
+ // Proxy server
+ if (ProxyUseDefaultCredentials && (null != ProxyCredential))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.ProxyCredentialConflict,
+ "WebCmdletProxyCredentialConflictException");
+ ThrowTerminatingError(error);
+ }
+ else if ((null == Proxy) && ((null != ProxyCredential) || ProxyUseDefaultCredentials))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.ProxyUriNotSupplied,
+ "WebCmdletProxyUriNotSuppliedException");
+ ThrowTerminatingError(error);
+ }
+
+ // request body content
+ if ((null != Body) && (null != InFile))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.BodyConflict,
+ "WebCmdletBodyConflictException");
+ ThrowTerminatingError(error);
+ }
+
+ // validate InFile path
+ if (InFile != null)
+ {
+ ProviderInfo provider = null;
+ ErrorRecord errorRecord = null;
+
+ try
{
- WebSession.MaximumRedirection--;
+ Collection providerPaths = GetResolvedProviderPathFromPSPath(InFile, out provider);
+
+ if (!provider.Name.Equals(FileSystemProvider.ProviderName, StringComparison.OrdinalIgnoreCase))
+ {
+ errorRecord = GetValidationError(WebCmdletStrings.NotFilesystemPath,
+ "WebCmdletInFileNotFilesystemPathException", InFile);
+ }
+ else
+ {
+ if (providerPaths.Count > 1)
+ {
+ errorRecord = GetValidationError(WebCmdletStrings.MultiplePathsResolved,
+ "WebCmdletInFileMultiplePathsResolvedException", InFile);
+ }
+ else if (providerPaths.Count == 0)
+ {
+ errorRecord = GetValidationError(WebCmdletStrings.NoPathResolved,
+ "WebCmdletInFileNoPathResolvedException", InFile);
+ }
+ else
+ {
+ if (Directory.Exists(providerPaths[0]))
+ {
+ errorRecord = GetValidationError(WebCmdletStrings.DirectoryPathSpecified,
+ "WebCmdletInFileNotFilePathException", InFile);
+ }
+ _originalFilePath = InFile;
+ InFile = providerPaths[0];
+ }
+ }
}
- // For selected redirects that used POST, GET must be used with the
- // redirected Location.
- // Since GET is the default; POST only occurs when -Method POST is used.
- if (Method == WebRequestMethod.Post && IsRedirectToGet(response.StatusCode))
+ catch (ItemNotFoundException pathNotFound)
{
- // See https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx
- Method = WebRequestMethod.Get;
+ errorRecord = new ErrorRecord(pathNotFound.ErrorRecord, pathNotFound);
+ }
+ catch (ProviderNotFoundException providerNotFound)
+ {
+ errorRecord = new ErrorRecord(providerNotFound.ErrorRecord, providerNotFound);
+ }
+ catch (System.Management.Automation.DriveNotFoundException driveNotFound)
+ {
+ errorRecord = new ErrorRecord(driveNotFound.ErrorRecord, driveNotFound);
}
- // recreate the HttpClient with redirection enabled since the first call suppressed redirection
- using (client = GetHttpClient(false))
- using (HttpRequestMessage redirectRequest = GetRequest(response.Headers.Location, stripAuthorization:true))
+ if (errorRecord != null)
{
- FillRequestStream(redirectRequest);
- _cancelToken = new CancellationTokenSource();
- response = client.SendAsync(redirectRequest, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult();
+ ThrowTerminatingError(errorRecord);
}
}
- return response;
+
+ // output ??
+ if (PassThru && (OutFile == null))
+ {
+ ErrorRecord error = GetValidationError(WebCmdletStrings.OutFileMissing,
+ "WebCmdletOutFileMissingException");
+ ThrowTerminatingError(error);
+ }
}
- internal virtual void UpdateSession(HttpResponseMessage response)
+ internal virtual void PrepareSession()
{
- if (response == null) { throw new ArgumentNullException("response"); }
+ // make sure we have a valid WebRequestSession object to work with
+ if (null == WebSession)
+ {
+ WebSession = new WebRequestSession();
+ }
+
+ if (null != SessionVariable)
+ {
+ // save the session back to the PS environment if requested
+ PSVariableIntrinsics vi = SessionState.PSVariable;
+ vi.Set(SessionVariable, WebSession);
+ }
+
+ //
+ // handle credentials
+ //
+ if (null != Credential && Authentication == WebAuthenticationType.None)
+ {
+ // get the relevant NetworkCredential
+ NetworkCredential netCred = Credential.GetNetworkCredential();
+ WebSession.Credentials = netCred;
+
+ // supplying a credential overrides the UseDefaultCredentials setting
+ WebSession.UseDefaultCredentials = false;
+ }
+ else if ((null != Credential || null!= Token) && Authentication != WebAuthenticationType.None)
+ {
+ ProcessAuthentication();
+ }
+ else if (UseDefaultCredentials)
+ {
+ WebSession.UseDefaultCredentials = true;
+ }
+
+
+ if (null != CertificateThumbprint)
+ {
+ X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
+ store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
+ X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
+ X509Certificate2Collection tbCollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByThumbprint, CertificateThumbprint, false);
+ if (tbCollection.Count == 0)
+ {
+ CryptographicException ex = new CryptographicException(WebCmdletStrings.ThumbprintNotFound);
+ throw ex;
+ }
+ foreach (X509Certificate2 tbCert in tbCollection)
+ {
+ X509Certificate certificate = (X509Certificate)tbCert;
+ WebSession.AddCertificate(certificate);
+ }
+ }
+
+ if (null != Certificate)
+ {
+ WebSession.AddCertificate(Certificate);
+ }
+
+ //
+ // handle the user agent
+ //
+ if (null != UserAgent)
+ {
+ // store the UserAgent string
+ WebSession.UserAgent = UserAgent;
+ }
+
+ if (null != Proxy)
+ {
+ WebProxy webProxy = new WebProxy(Proxy);
+ webProxy.BypassProxyOnLocal = false;
+ if (null != ProxyCredential)
+ {
+ webProxy.Credentials = ProxyCredential.GetNetworkCredential();
+ }
+ else if (ProxyUseDefaultCredentials)
+ {
+ // If both ProxyCredential and ProxyUseDefaultCredentials are passed,
+ // UseDefaultCredentials will overwrite the supplied credentials.
+ webProxy.UseDefaultCredentials = true;
+ }
+ WebSession.Proxy = webProxy;
+ }
+
+ if (-1 < MaximumRedirection)
+ {
+ WebSession.MaximumRedirection = MaximumRedirection;
+ }
+
+ // store the other supplied headers
+ if (null != Headers)
+ {
+ foreach (string key in Headers.Keys)
+ {
+ // add the header value (or overwrite it if already present)
+ WebSession.Headers[key] = Headers[key].ToString();
+ }
+ }
}
#endregion Virtual Methods
+ #region Helper Properties
+
+ internal string QualifiedOutFile
+ {
+ get { return (QualifyFilePath(OutFile)); }
+ }
+
+ internal bool ShouldSaveToOutFile
+ {
+ get { return (!string.IsNullOrEmpty(OutFile)); }
+ }
+
+ internal bool ShouldWriteToPipeline
+ {
+ get { return (!ShouldSaveToOutFile || PassThru); }
+ }
+
+ #endregion Helper Properties
+
+ #region Abstract Methods
+
+ ///
+ /// Read the supplied WebResponse object and push the
+ /// resulting output into the pipeline.
+ ///
+ /// Instance of a WebResponse object to be processed
+ internal abstract void ProcessResponse(HttpResponseMessage response);
+
+ #endregion Abstract Methods
+
#region Overrides
///
@@ -662,6 +1233,158 @@ protected override void StopProcessing()
#region Helper Methods
+ private HttpMethod GetHttpMethod(WebRequestMethod method)
+ {
+ switch (Method)
+ {
+ case WebRequestMethod.Default:
+ case WebRequestMethod.Get:
+ return HttpMethod.Get;
+ case WebRequestMethod.Head:
+ return HttpMethod.Head;
+ case WebRequestMethod.Post:
+ return HttpMethod.Post;
+ case WebRequestMethod.Put:
+ return HttpMethod.Put;
+ case WebRequestMethod.Delete:
+ return HttpMethod.Delete;
+ case WebRequestMethod.Trace:
+ return HttpMethod.Trace;
+ case WebRequestMethod.Options:
+ return HttpMethod.Options;
+ default:
+ // Merge and Patch
+ return new HttpMethod(Method.ToString().ToUpperInvariant());
+ }
+ }
+
+ private Uri PrepareUri(Uri uri)
+ {
+ uri = CheckProtocol(uri);
+
+ // before creating the web request,
+ // preprocess Body if content is a dictionary and method is GET (set as query)
+ IDictionary bodyAsDictionary;
+ LanguagePrimitives.TryConvertTo(Body, out bodyAsDictionary);
+ if ((null != bodyAsDictionary)
+ && ((IsStandardMethodSet() && (Method == WebRequestMethod.Default || Method == WebRequestMethod.Get))
+ || (IsCustomMethodSet() && CustomMethod.ToUpperInvariant() == "GET")))
+ {
+ UriBuilder uriBuilder = new UriBuilder(uri);
+ if (uriBuilder.Query != null && uriBuilder.Query.Length > 1)
+ {
+ uriBuilder.Query = uriBuilder.Query.Substring(1) + "&" + FormatDictionary(bodyAsDictionary);
+ }
+ else
+ {
+ uriBuilder.Query = FormatDictionary(bodyAsDictionary);
+ }
+ uri = uriBuilder.Uri;
+ // set body to null to prevent later FillRequestStream
+ Body = null;
+ }
+
+ return uri;
+ }
+
+ private Uri CheckProtocol(Uri uri)
+ {
+ if (null == uri) { throw new ArgumentNullException("uri"); }
+
+ if (!uri.IsAbsoluteUri)
+ {
+ uri = new Uri("http://" + uri.OriginalString);
+ }
+ return (uri);
+ }
+
+ private string QualifyFilePath(string path)
+ {
+ string resolvedFilePath = PathUtils.ResolveFilePath(path, this, false);
+ return resolvedFilePath;
+ }
+
+ private string FormatDictionary(IDictionary content)
+ {
+ if (content == null)
+ throw new ArgumentNullException("content");
+
+ StringBuilder bodyBuilder = new StringBuilder();
+ foreach (string key in content.Keys)
+ {
+ if (0 < bodyBuilder.Length)
+ {
+ bodyBuilder.Append("&");
+ }
+
+ object value = content[key];
+
+ // URLEncode the key and value
+ string encodedKey = WebUtility.UrlEncode(key);
+ string encodedValue = String.Empty;
+ if (null != value)
+ {
+ encodedValue = WebUtility.UrlEncode(value.ToString());
+ }
+
+ bodyBuilder.AppendFormat("{0}={1}", encodedKey, encodedValue);
+ }
+ return bodyBuilder.ToString();
+ }
+
+ private ErrorRecord GetValidationError(string msg, string errorId)
+ {
+ var ex = new ValidationMetadataException(msg);
+ var error = new ErrorRecord(ex, errorId, ErrorCategory.InvalidArgument, this);
+ return (error);
+ }
+
+ private ErrorRecord GetValidationError(string msg, string errorId, params object[] args)
+ {
+ msg = string.Format(CultureInfo.InvariantCulture, msg, args);
+ var ex = new ValidationMetadataException(msg);
+ var error = new ErrorRecord(ex, errorId, ErrorCategory.InvalidArgument, this);
+ return (error);
+ }
+
+ private bool IsStandardMethodSet()
+ {
+ return (ParameterSetName == "StandardMethod");
+ }
+
+ private bool IsCustomMethodSet()
+ {
+ return (ParameterSetName == "CustomMethod");
+ }
+
+ private string GetBasicAuthorizationHeader()
+ {
+ string unencoded = String.Format("{0}:{1}", Credential.UserName, Credential.GetNetworkCredential().Password);
+ Byte[] bytes = Encoding.UTF8.GetBytes(unencoded);
+ return String.Format("Basic {0}", Convert.ToBase64String(bytes));
+ }
+
+ private string GetBearerAuthorizationHeader()
+ {
+ return String.Format("Bearer {0}", new NetworkCredential(String.Empty, Token).Password);
+ }
+
+ private void ProcessAuthentication()
+ {
+ if(Authentication == WebAuthenticationType.Basic)
+ {
+ WebSession.Headers["Authorization"] = GetBasicAuthorizationHeader();
+ }
+ else if (Authentication == WebAuthenticationType.Bearer || Authentication == WebAuthenticationType.OAuth)
+ {
+ WebSession.Headers["Authorization"] = GetBearerAuthorizationHeader();
+ }
+ else
+ {
+ Diagnostics.Assert(false, String.Format("Unrecognized Authentication value: {0}", Authentication));
+ }
+ }
+
///
/// Sets the ContentLength property of the request and writes the specified content to the request's RequestStream.
///
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebResponseHelper.CoreClr.cs
similarity index 97%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebResponseHelper.CoreClr.cs
index 0949b343176..f625da9687f 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebResponseHelper.CoreClr.cs
@@ -9,7 +9,7 @@
namespace Microsoft.PowerShell.Commands
{
- internal static partial class WebResponseHelper
+ internal static class WebResponseHelper
{
internal static string GetCharacterSet(HttpResponseMessage response)
{
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObject.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebResponseObject.Common.cs
similarity index 57%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObject.CoreClr.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebResponseObject.Common.cs
index 3145eef8c3a..3bc3878cae4 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObject.CoreClr.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebResponseObject.Common.cs
@@ -1,22 +1,67 @@
-/********************************************************************++
+/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
-using System.Text;
-using System.Net.Http;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
+using System.Net.Http;
+using System.Text;
namespace Microsoft.PowerShell.Commands
{
///
/// WebResponseObject
///
- public partial class WebResponseObject
+ public class WebResponseObject
{
#region Properties
+ ///
+ /// gets or protected sets the Content property
+ ///
+ [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
+ public byte[] Content { get; protected set; }
+
+ ///
+ /// gets the StatusCode property
+ ///
+ public int StatusCode
+ {
+ get { return (WebResponseHelper.GetStatusCode(BaseResponse)); }
+ }
+
+ ///
+ /// gets the StatusDescription property
+ ///
+ public string StatusDescription
+ {
+ get { return (WebResponseHelper.GetStatusDescription(BaseResponse)); }
+ }
+
+ private MemoryStream _rawContentStream;
+ ///
+ /// gets the RawContentStream property
+ ///
+ public MemoryStream RawContentStream
+ {
+ get { return (_rawContentStream); }
+ }
+
+ ///
+ /// gets the RawContentLength property
+ ///
+ public long RawContentLength
+ {
+ get { return (null == RawContentStream ? -1 : RawContentStream.Length); }
+ }
+
+ ///
+ /// gets or protected sets the RawContent property
+ ///
+ public string RawContent { get; protected set; }
+
///
/// gets or sets the BaseResponse property
///
@@ -37,7 +82,6 @@ public Dictionary> Headers
return _headers;
}
}
-
private Dictionary> _headers = null;
///
@@ -45,7 +89,7 @@ public Dictionary> Headers
///
public Dictionary RelationLink { get; internal set; }
- #endregion
+ #endregion Properties
#region Constructors
@@ -73,6 +117,14 @@ public WebResponseObject(HttpResponseMessage response, Stream contentStream)
#region Methods
+ ///
+ /// Reads the response content from the web response.
+ ///
+ private void InitializeContent()
+ {
+ this.Content = this.RawContentStream.ToArray();
+ }
+
private void InitializeRawContent(HttpResponseMessage baseResponse)
{
StringBuilder raw = ContentHelper.GetRawContentHeader(baseResponse);
@@ -86,6 +138,29 @@ private void InitializeRawContent(HttpResponseMessage baseResponse)
this.RawContent = raw.ToString();
}
+ private bool IsPrintable(char c)
+ {
+ return (Char.IsLetterOrDigit(c) || Char.IsPunctuation(c) || Char.IsSeparator(c) || Char.IsSymbol(c) || Char.IsWhiteSpace(c));
+ }
+
+ ///
+ /// Returns the string representation of this web response.
+ ///
+ /// The string representation of this web response.
+ public sealed override string ToString()
+ {
+ char[] stringContent = System.Text.Encoding.ASCII.GetChars(Content);
+ for (int counter = 0; counter < stringContent.Length; counter++)
+ {
+ if (!IsPrintable(stringContent[counter]))
+ {
+ stringContent[counter] = '.';
+ }
+ }
+
+ return new string(stringContent);
+ }
+
private void SetResponse(HttpResponseMessage response, Stream contentStream)
{
if (null == response) { throw new ArgumentNullException("response"); }
@@ -117,6 +192,6 @@ private void SetResponse(HttpResponseMessage response, Stream contentStream)
_rawContentStream.Position = 0;
}
- #endregion
+ #endregion Methods
}
}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebResponseObjectFactory.CoreClr.cs
similarity index 100%
rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs
rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebResponseObjectFactory.CoreClr.cs