Core feature update (#245)
This commit is contained in:
Родитель
3da96db226
Коммит
676ad42097
|
@ -20,15 +20,18 @@
|
|||
|
||||
# Change Log
|
||||
|
||||
## Upcoming Release
|
||||
## 3.0.3 - December 2019
|
||||
|
||||
* Authentication
|
||||
* Added the [Register-PartnerTokenCache](https://docs.microsoft.com/powershell/module/partnercenter/Register-PartnerTokenCache) to create, and delete, the control file that determines if a in-memory token cache should be used instead of the default persistent token cache
|
||||
* Addressed an issue where an InvalidOperationException exception was being encountering with the [Connect-PartnerCenter](https://docs.microsoft.com/powershell/module/partnercenter/New-PartnerAccessToken) and [New-PartnerAccessToken](https://docs.microsoft.com/powershell/module/partnercenter/New-PartnerAccessToken) commands when specifying an environment
|
||||
* Addressed an issue where an InvalidOperationException exception was being encountering with the [Connect-PartnerCenter](https://docs.microsoft.com/powershell/module/partnercenter/Connect-PartnerCenter) and [New-PartnerAccessToken](https://docs.microsoft.com/powershell/module/partnercenter/New-PartnerAccessToken) commands when specifying an environment
|
||||
* Addressed an issue where an InvalidOperationException exception was being encountered under certain circumstances when invoking [Connect-PartnerCenter](https://docs.microsoft.com/powershell/module/partnercenter/Connect-PartnerCenter) and attempting to authenticate interactively
|
||||
* Addressed issue [#234](https://github.com/microsoft/Partner-Center-PowerShell/issues/234) that was preventing the [New-PartnerAccessToken](https://docs.microsoft.com/powershell/module/partnercenter/New-PartnerAccessToken) command from executing successfully when being invoked through an Azure Function app
|
||||
* Invoice
|
||||
* Added the [Get-PartnerUnbilledInvoiceLineItem](https://docs.microsoft.com/powershell/module/partnercenter/Get-PartnerUnbilledInvoiceLineItem) command to get unbilled invoice line items
|
||||
* Removed the `Period` parameter from the [Get-PartnerInvoiceLineItem](https://docs.microsoft.com/powershell/module/partnercenter/Get-PartnerInvoiceLineItem) command because the functionality it enabled has been replaced with the [Get-PartnerUnbilledInvoiceLineItem](https://docs.microsoft.com/powershell/module/partnercenter/Get-PartnerUnbilledInvoiceLineItem) command
|
||||
* Network
|
||||
* Addressed an issue where the HTTP response from [Get-PartnerUser](https://docs.microsoft.com/powershell/module/partnercenter/Get-PartnerUser) and [Get-PartnerUserSignInActivity](https://docs.microsoft.com/powershell/module/partnercenter/Get-PartnerUserSignInActivity) was not being correctly written to the debug pipeline
|
||||
* Product Upgrades
|
||||
* Addressed an issue with starting the upgrade process for an Azure Plan
|
||||
* Subscription
|
|
@ -1,3 +1,3 @@
|
|||
# Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
|
|
@ -54,13 +54,13 @@ chances of your issue being dealt with quickly:
|
|||
- **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
|
||||
causing the problem (line of code or commit)
|
||||
|
||||
You can file new issues by providing the above information at the [corresponding repository's issues link](https://github.com/Microsoft/Partner-Center-PowerShell/issues/new).
|
||||
You can file new issues by providing the above information at the [corresponding repository's issues link](https://github.com/microsoft/Partner-Center-PowerShell/issues/new).
|
||||
|
||||
### Submitting a Pull Request
|
||||
|
||||
Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
|
||||
- [Search the repository](https://github.com/Microsoft/Partner-Center-PowerShell/pulls) for an open or closed PR
|
||||
- [Search the repository](https://github.com/microsoft/Partner-Center-PowerShell/pulls) for an open or closed PR
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
|
||||
- Make your changes in a new git fork:
|
||||
|
@ -77,4 +77,4 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
|||
git push -f
|
||||
```
|
||||
|
||||
That is it! Thank you for your contribution!
|
||||
That is it! Thank you for your contribution!
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Factories
|
|||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -30,7 +31,7 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Factories
|
|||
GraphClientFactory.CreateDefaultHandlers(null),
|
||||
new ClientTracingHandler
|
||||
{
|
||||
InnerHandler = new HttpClientHandler()
|
||||
InnerHandler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip }
|
||||
}), false, null));
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -12,5 +12,10 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Models.Authentication
|
|||
/// Key value for the token cache component.
|
||||
/// </summary>
|
||||
public const string TokenCache = "TokenCache";
|
||||
|
||||
/// <summary>
|
||||
/// Key value for the write warning component.
|
||||
/// </summary>
|
||||
public const string WriteWarning = "WriteWarning";
|
||||
}
|
||||
}
|
|
@ -7,24 +7,25 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Network
|
|||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Extensions;
|
||||
using Identity.Client.Extensibility;
|
||||
using Microsoft.Store.PartnerCenter.PowerShell.Models;
|
||||
using Microsoft.Store.PartnerCenter.PowerShell.Models.Authentication;
|
||||
using Models;
|
||||
using Models.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// Provide a custom Web UI for public client applications to sign-in users and have them consent part of the Authorization code flow.
|
||||
/// Provide a custom Web UI for client applications to sign-in users and have them consent part of the authorization code flow.
|
||||
/// </summary>
|
||||
internal class DefaultOsBrowserWebUi : ICustomWebUi
|
||||
public class DefaultOsBrowserWebUi : ICustomWebUi
|
||||
{
|
||||
/// <summary>
|
||||
/// The HTML returned after failed authentication.
|
||||
/// </summary>
|
||||
private const string CloseWindowFailureHtml = @"<html>
|
||||
private const string DefaultFailureHtml = @"<html>
|
||||
<head><title>Authentication Failed</title></head>
|
||||
<body>
|
||||
Authentication failed. You can return to the application. Feel free to close this browser tab.
|
||||
|
@ -36,7 +37,7 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Network
|
|||
/// <summary>
|
||||
/// The HTML returned after successful authentication.
|
||||
/// </summary>
|
||||
private const string CloseWindowSuccessHtml = @"<html>
|
||||
private const string DefaultSuccessHtml = @"<html>
|
||||
<head><title>Authentication Complete</title></head>
|
||||
<body>
|
||||
Authentication complete. You can return to the application. Feel free to close this browser tab.
|
||||
|
@ -44,18 +45,17 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Network
|
|||
</html>";
|
||||
|
||||
/// <summary>
|
||||
/// The message written to the console.
|
||||
/// The message to be written to the console.
|
||||
/// </summary>
|
||||
private readonly string message;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DefaultOsBrowserWebUi" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message written to the console.</param>
|
||||
/// <param name="message">The message to be written to the console.</param>
|
||||
public DefaultOsBrowserWebUi(string message)
|
||||
{
|
||||
message.AssertNotEmpty(nameof(message));
|
||||
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
@ -77,20 +77,40 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Network
|
|||
|
||||
WriteWarning(message);
|
||||
|
||||
using (SingleMessageTcpListener listener = new SingleMessageTcpListener(redirectUri.Port))
|
||||
return await new HttpListenerInterceptor().ListenToSingleRequestAndRespondAsync(
|
||||
redirectUri.Port,
|
||||
GetResponseMessage,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the response message to be sent to the browser.
|
||||
/// </summary>
|
||||
/// <param name="authCodeUri">The URI that contains the authorization code.</param>
|
||||
/// <returns>The response message to be sent to the browser.</returns>
|
||||
private MessageAndHttpCode GetResponseMessage(Uri authCodeUri)
|
||||
{
|
||||
// Parse the URI to understand if an error was returned. This is done just to show the user a nice error message in the browser.
|
||||
NameValueCollection authCodeQueryKeyValue = HttpUtility.ParseQueryString(authCodeUri.Query);
|
||||
|
||||
string errorValue = authCodeQueryKeyValue.Get("error");
|
||||
|
||||
if (!string.IsNullOrEmpty(errorValue))
|
||||
{
|
||||
Uri authCodeUri = null;
|
||||
string errorDescription = authCodeQueryKeyValue.Get("error_description");
|
||||
|
||||
await listener.ListenToSingleRequestAndRespondAsync(
|
||||
(uri) =>
|
||||
{
|
||||
authCodeUri = uri;
|
||||
return GetMessageToShowInBroswerAfterAuth(uri);
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
WriteWarning($"Default OS browser intercepted an URI with an error: {errorValue} {errorDescription}");
|
||||
|
||||
return authCodeUri;
|
||||
string errorMessage = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
DefaultFailureHtml,
|
||||
errorValue,
|
||||
errorDescription);
|
||||
|
||||
return new MessageAndHttpCode(HttpStatusCode.OK, errorMessage);
|
||||
}
|
||||
|
||||
return new MessageAndHttpCode(HttpStatusCode.OK, DefaultSuccessHtml);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -130,31 +150,14 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Network
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HTML that will be shown in the browser.
|
||||
/// Writes the warning message to the pipeline.
|
||||
/// </summary>
|
||||
/// <param name="uri">The URI returned back from the STS authorization endpoint.</param>
|
||||
/// <returns>The HTML to be shown in the browser.</returns>
|
||||
private static string GetMessageToShowInBroswerAfterAuth(Uri uri)
|
||||
{
|
||||
NameValueCollection authCodeQueryKeyValue = HttpUtility.ParseQueryString(uri.Query);
|
||||
|
||||
string errorString = authCodeQueryKeyValue.Get("error");
|
||||
|
||||
if (!string.IsNullOrEmpty(errorString))
|
||||
{
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
CloseWindowFailureHtml,
|
||||
errorString,
|
||||
authCodeQueryKeyValue.Get("error_description"));
|
||||
}
|
||||
|
||||
return CloseWindowSuccessHtml;
|
||||
}
|
||||
|
||||
/// <param name="text">The message to be written to the pipeline.</param>
|
||||
private void WriteWarning(string message)
|
||||
{
|
||||
if (PartnerSession.Instance.TryGetComponent("WriteWarning", out EventHandler<StreamEventArgs> writeWarningEvent))
|
||||
message.AssertNotEmpty(nameof(message));
|
||||
|
||||
if (PartnerSession.Instance.TryGetComponent(ComponentKey.WriteWarning, out EventHandler<StreamEventArgs> writeWarningEvent))
|
||||
{
|
||||
writeWarningEvent(this, new StreamEventArgs { Resource = message });
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.Store.PartnerCenter.PowerShell.Network
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Rest;
|
||||
|
||||
/// <summary>
|
||||
/// Provides the ability to listen and intercept HTTP operations.
|
||||
/// </summary>
|
||||
internal class HttpListenerInterceptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Listens for a single request and responds.
|
||||
/// </summary>
|
||||
/// <param name="port">The port where to listen for requests.</param>
|
||||
/// <param name="responseProducer">The function responsible for responding.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<Uri> ListenToSingleRequestAndRespondAsync(int port, Func<Uri, MessageAndHttpCode> responseProducer, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
HttpListener httpListener = null;
|
||||
|
||||
try
|
||||
{
|
||||
string urlToListenTo = "http://localhost:" + port + "/";
|
||||
|
||||
httpListener = new HttpListener();
|
||||
httpListener.Prefixes.Add(urlToListenTo);
|
||||
|
||||
httpListener.Start();
|
||||
ServiceClientTracing.Information($"[HttpListenerInterceptor] Listening for authorization code on {urlToListenTo}");
|
||||
|
||||
using (cancellationToken.Register(() =>
|
||||
{
|
||||
TryStopListening(httpListener);
|
||||
}))
|
||||
{
|
||||
HttpListenerContext context = await httpListener.GetContextAsync().ConfigureAwait(false);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
Respond(responseProducer, context);
|
||||
ServiceClientTracing.Information($"[HttpListenerInterceptor] Received a message on {urlToListenTo}");
|
||||
|
||||
// the request URL should now contain the auth code and pkce
|
||||
return context.Request.Url;
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryStopListening(httpListener);
|
||||
}
|
||||
}
|
||||
|
||||
private void Respond(Func<Uri, MessageAndHttpCode> responseProducer, HttpListenerContext context)
|
||||
{
|
||||
MessageAndHttpCode messageAndCode = responseProducer(context.Request.Url);
|
||||
ServiceClientTracing.Information($"[HttpListenerInterceptor] Processing a response message to the browser. HttpStatus: {messageAndCode.HttpCode}");
|
||||
|
||||
switch (messageAndCode.HttpCode)
|
||||
{
|
||||
case HttpStatusCode.Found:
|
||||
context.Response.StatusCode = (int)HttpStatusCode.Found;
|
||||
context.Response.RedirectLocation = messageAndCode.Message;
|
||||
break;
|
||||
case HttpStatusCode.OK:
|
||||
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(messageAndCode.Message);
|
||||
context.Response.ContentLength64 = buffer.Length;
|
||||
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("HttpCode not supported" + messageAndCode.HttpCode);
|
||||
}
|
||||
|
||||
context.Response.OutputStream.Close();
|
||||
}
|
||||
|
||||
private static void TryStopListening(HttpListener httpListener)
|
||||
{
|
||||
try
|
||||
{
|
||||
httpListener?.Abort();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.Store.PartnerCenter.PowerShell.Network
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the message and status code used to respond to HTTP requests.
|
||||
/// </summary>
|
||||
internal class MessageAndHttpCode
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MessageAndHttpCode" /> class.
|
||||
/// </summary>
|
||||
/// <param name="httpCode">The status code for the HTTP operation.</param>
|
||||
/// <param name="message">The message that will be sent with the response.</param>
|
||||
public MessageAndHttpCode(HttpStatusCode httpCode, string message)
|
||||
{
|
||||
HttpCode = httpCode;
|
||||
Message = message ?? throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status code for the HTTP operation.
|
||||
/// </summary>
|
||||
public HttpStatusCode HttpCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message that will be sent with the response.
|
||||
/// </summary>
|
||||
public string Message { get; }
|
||||
}
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.Store.PartnerCenter.PowerShell.Network
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides the ability to listen for a single message and respond.
|
||||
/// </summary>
|
||||
internal class SingleMessageTcpListener : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Listens for connections from TCP network clients.
|
||||
/// </summary>
|
||||
private readonly TcpListener listener;
|
||||
|
||||
/// <summary>
|
||||
/// The port on which to listen for incoming connection attempts.
|
||||
/// </summary>
|
||||
private readonly int port;
|
||||
|
||||
/// <summary>
|
||||
/// A flag indicating if the object has already been disposed.
|
||||
/// </summary>
|
||||
private bool disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SingleMessageTcpListener" /> class
|
||||
/// </summary>
|
||||
/// <param name="port">The port on which to listen for incoming connection attempts.</param>
|
||||
public SingleMessageTcpListener(int port)
|
||||
{
|
||||
port.AssertPositive(nameof(port));
|
||||
|
||||
this.port = port;
|
||||
listener = new TcpListener(IPAddress.Loopback, this.port);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Listens for a single request and responds.
|
||||
/// </summary>
|
||||
/// <param name="producer"></param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <returns></returns>
|
||||
public async Task ListenToSingleRequestAndRespondAsync(Func<Uri, string> producer, CancellationToken cancellationToken)
|
||||
{
|
||||
TcpClient tcpClient = null;
|
||||
|
||||
cancellationToken.Register(() => listener.Stop());
|
||||
listener.Start();
|
||||
|
||||
try
|
||||
{
|
||||
tcpClient = await AcceptTcpClientAsync(cancellationToken).ConfigureAwait(false);
|
||||
await ExtractUriAndRespondAsync(tcpClient, producer, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
tcpClient?.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
listener?.Stop();
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
private async Task<TcpClient> AcceptTcpClientAsync(CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await listener.AcceptTcpClientAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) when (token.IsCancellationRequested)
|
||||
{
|
||||
throw new OperationCanceledException("Cancellation was requested while awaiting TCP client connection.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> GetTcpResponseAsync(TcpClient client, CancellationToken cancellationToken)
|
||||
{
|
||||
NetworkStream networkStream = client.GetStream();
|
||||
|
||||
byte[] readBuffer = new byte[1024];
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
int numberOfBytesRead;
|
||||
|
||||
do
|
||||
{
|
||||
numberOfBytesRead = await networkStream.ReadAsync(readBuffer, 0, readBuffer.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
string s = Encoding.ASCII.GetString(readBuffer, 0, numberOfBytesRead);
|
||||
stringBuilder.Append(s);
|
||||
|
||||
}
|
||||
while (networkStream.DataAvailable);
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
private async Task ExtractUriAndRespondAsync(TcpClient tcpClient, Func<Uri, string> responseProducer, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
string httpRequest = await GetTcpResponseAsync(tcpClient, cancellationToken).ConfigureAwait(false);
|
||||
Uri uri = ExtractUriFromHttpRequest(httpRequest);
|
||||
|
||||
await WriteResponseAsync(responseProducer(uri), tcpClient.GetStream(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
private Uri ExtractUriFromHttpRequest(string httpRequest)
|
||||
{
|
||||
Regex r1 = new Regex(@"GET \/\?(.*) HTTP");
|
||||
Match match = r1.Match(httpRequest);
|
||||
string getQuery;
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Not a GET query.");
|
||||
}
|
||||
|
||||
getQuery = match.Groups[1].Value;
|
||||
|
||||
UriBuilder uriBuilder = new UriBuilder
|
||||
{
|
||||
Query = getQuery,
|
||||
Port = port
|
||||
};
|
||||
|
||||
return uriBuilder.Uri;
|
||||
}
|
||||
|
||||
private static async Task WriteResponseAsync(string message, NetworkStream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
string fullResponse = $"HTTP/1.1 200 OK\r\n\r\n{message}";
|
||||
byte[] response = Encoding.ASCII.GetBytes(fullResponse);
|
||||
|
||||
await stream.WriteAsync(response, 0, response.Length, cancellationToken).ConfigureAwait(false);
|
||||
await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
# Generated by: Microsoft Corporation
|
||||
#
|
||||
# Generated on: 01/10/2020
|
||||
# Generated on: 12/27/2019
|
||||
#
|
||||
|
||||
@{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
# Generated by: Microsoft Corporation
|
||||
#
|
||||
# Generated on: 01/10/2020
|
||||
# Generated on: 12/27/2019
|
||||
#
|
||||
|
||||
$PSDefaultParameterValues.Clear()
|
||||
|
|
|
@ -87,25 +87,8 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Validations
|
|||
resource.PhoneNumber));
|
||||
}
|
||||
|
||||
//if (string.IsNullOrEmpty(resource.Country) && !string.IsNullOrEmpty(resource.Region))
|
||||
//{
|
||||
// debugAction("The country parameter must be specified to perform address validation. Since it was not provided this operation will not be performed a default value of true will be returned.");
|
||||
// return true;
|
||||
//}
|
||||
|
||||
//if (string.IsNullOrEmpty(resource.Country))
|
||||
//{
|
||||
// debugAction("The country parameter must be specifed to perform address validation. Since it was not provided this operation will be performed and a value of false will be returned.");
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//if (resource.Country.Equals(ChinaCountryCode, StringComparison.InvariantCultureIgnoreCase) ||
|
||||
// resource.Country.Equals(MexicoCountryCode, StringComparison.InvariantCultureIgnoreCase) ||
|
||||
// resource.Country.Equals(UnitedStatesCountryCode, StringComparison.InvariantCultureIgnoreCase))
|
||||
//{
|
||||
debugAction("Checking if the address is valid using the partner service.");
|
||||
return partner.Validations.IsAddressValidAsync(resource).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче