InvokeRestMethodCommand.Common cleanup and merge partials (#18736)

This commit is contained in:
CarloToso
2022-12-14 09:48:13 +05:00
committed by GitHub
parent 4ff581e906
commit 88077bd985
@@ -13,7 +13,15 @@ using Newtonsoft.Json.Linq;
namespace Microsoft.PowerShell.Commands
{
public partial class InvokeRestMethodCommand
/// <summary>
/// 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.
/// </summary>
[Cmdlet(VerbsLifecycle.Invoke, "RestMethod", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096706", DefaultParameterSetName = "StandardMethod")]
public class InvokeRestMethodCommand : WebRequestPSCmdlet
{
#region Parameters
@@ -83,8 +91,124 @@ namespace Microsoft.PowerShell.Commands
#endregion Parameters
#region Virtual Method Overrides
/// <summary>
/// Process the web response and output corresponding objects.
/// </summary>
/// <param name="response"></param>
internal override void ProcessResponse(HttpResponseMessage response)
{
if (response == null) { throw new ArgumentNullException(nameof(response)); }
var baseResponseStream = StreamHelper.GetResponseStream(response);
if (ShouldWriteToPipeline)
{
using var responseStream = new BufferingStreamReader(baseResponseStream);
// 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))
{
StreamHelper.TryGetEncoding(charSet, out encoding);
}
object obj = null;
Exception ex = null;
string str = StreamHelper.DecodeStream(responseStream, ref encoding);
string encodingVerboseName;
try
{
encodingVerboseName = string.IsNullOrEmpty(encoding.HeaderName) ? encoding.EncodingName : encoding.HeaderName;
}
catch (NotSupportedException)
{
encodingVerboseName = encoding.EncodingName;
}
// NOTE: Tests use this verbose output to verify the encoding.
WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Content encoding: {0}", encodingVerboseName));
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);
}
}
else if (ShouldSaveToOutFile)
{
StreamHelper.SaveStreamToFile(baseResponseStream, QualifiedOutFile, this, response.Content.Headers.ContentLength.GetValueOrDefault(), _cancelToken.Token);
}
if (!string.IsNullOrEmpty(StatusCodeVariable))
{
PSVariableIntrinsics vi = SessionState.PSVariable;
vi.Set(StatusCodeVariable, (int)response.StatusCode);
}
if (!string.IsNullOrEmpty(ResponseHeadersVariable))
{
PSVariableIntrinsics vi = SessionState.PSVariable;
vi.Set(ResponseHeadersVariable, WebResponseHelper.GetHeadersDictionary(response));
}
}
#endregion Virtual Method Overrides
#region Helper Methods
private static RestReturnType CheckReturnType(HttpResponseMessage response)
{
if (response == null) { throw new ArgumentNullException(nameof(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(Stream responseStream)
{
bool isRssOrFeed = false;
@@ -111,7 +235,8 @@ namespace Microsoft.PowerShell.Commands
if (isRssOrFeed)
{
XmlDocument workingDocument = new();
// performing a Read() here to avoid rrechecking
// Performing a Read() here to avoid rechecking
// "rss" or "feed" items
reader.Read();
while (!reader.EOF)
@@ -122,7 +247,7 @@ namespace Microsoft.PowerShell.Commands
string.Equals("Entry", reader.Name, StringComparison.OrdinalIgnoreCase))
)
{
// this one will do reader.Read() internally
// This one will do reader.Read() internally
XmlNode result = workingDocument.ReadNode(reader);
WriteObject(result);
}
@@ -178,7 +303,7 @@ namespace Microsoft.PowerShell.Commands
doc = null;
}
return (doc != null);
return doc != null;
}
private static bool TryConvertToJson(string json, out object obj, ref Exception exRef)
@@ -226,7 +351,7 @@ namespace Microsoft.PowerShell.Commands
return converted;
}
#endregion
#endregion Helper Methods
/// <summary>
/// Enum for rest return type.
@@ -265,20 +390,11 @@ namespace Microsoft.PowerShell.Commands
private readonly MemoryStream _streamBuffer;
private readonly byte[] _copyBuffer;
public override bool CanRead
{
get { return true; }
}
public override bool CanRead => true;
public override bool CanSeek
{
get { return true; }
}
public override bool CanSeek => true;
public override bool CanWrite
{
get { return false; }
}
public override bool CanWrite => false;
public override void Flush()
{
@@ -359,140 +475,4 @@ namespace Microsoft.PowerShell.Commands
}
}
}
// TODO: Merge Partials
/// <summary>
/// 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.
/// </summary>
[Cmdlet(VerbsLifecycle.Invoke, "RestMethod", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096706", DefaultParameterSetName = "StandardMethod")]
public partial class InvokeRestMethodCommand : WebRequestPSCmdlet
{
#region Virtual Method Overrides
/// <summary>
/// Process the web response and output corresponding objects.
/// </summary>
/// <param name="response"></param>
internal override void ProcessResponse(HttpResponseMessage response)
{
if (response == null) { throw new ArgumentNullException(nameof(response)); }
var baseResponseStream = StreamHelper.GetResponseStream(response);
if (ShouldWriteToPipeline)
{
using var responseStream = new BufferingStreamReader(baseResponseStream);
// 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))
{
StreamHelper.TryGetEncoding(charSet, out encoding);
}
object obj = null;
Exception ex = null;
string str = StreamHelper.DecodeStream(responseStream, ref encoding);
string encodingVerboseName;
try
{
encodingVerboseName = string.IsNullOrEmpty(encoding.HeaderName) ? encoding.EncodingName : encoding.HeaderName;
}
catch (NotSupportedException)
{
encodingVerboseName = encoding.EncodingName;
}
// NOTE: Tests use this verbose output to verify the encoding.
WriteVerbose(string.Format
(
System.Globalization.CultureInfo.InvariantCulture,
"Content encoding: {0}",
encodingVerboseName)
);
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);
}
}
else if (ShouldSaveToOutFile)
{
StreamHelper.SaveStreamToFile(baseResponseStream, QualifiedOutFile, this, response.Content.Headers.ContentLength.GetValueOrDefault(), _cancelToken.Token);
}
if (!string.IsNullOrEmpty(StatusCodeVariable))
{
PSVariableIntrinsics vi = SessionState.PSVariable;
vi.Set(StatusCodeVariable, (int)response.StatusCode);
}
if (!string.IsNullOrEmpty(ResponseHeadersVariable))
{
PSVariableIntrinsics vi = SessionState.PSVariable;
vi.Set(ResponseHeadersVariable, WebResponseHelper.GetHeadersDictionary(response));
}
}
#endregion Virtual Method Overrides
#region Helper Methods
private static RestReturnType CheckReturnType(HttpResponseMessage response)
{
if (response == null) { throw new ArgumentNullException(nameof(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
}
}