Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/WopiValidator.Core/IWopiRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace Microsoft.Office.WopiValidator.Core
{
Expand All @@ -26,5 +27,15 @@ IResponseData Execute(string endpointAddress,
string userAgent,
RSACryptoServiceProvider proofKeyProviderNew,
RSACryptoServiceProvider proofKeyProviderOld);

Task<IResponseData> ExecuteAsync(string endpointAddress,
string accessToken,
long accessTokenTtl,
ITestCase testCase,
Dictionary<string, string> savedState,
IResourceManager resourceManager,
string userAgent,
RSACryptoServiceProvider proofKeyProviderNew,
RSACryptoServiceProvider proofKeyProviderOld);
}
}
20 changes: 20 additions & 0 deletions src/WopiValidator.Core/Requests/GetFromFileUrlRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace Microsoft.Office.WopiValidator.Core.Requests
{
Expand Down Expand Up @@ -43,5 +44,24 @@ public override IResponseData Execute(

return ExecuteRequest(executionData);
}

public async override Task<IResponseData> ExecuteAsync(
string endpointAddress,
string accessToken,
long accessTokenTtl,
ITestCase testCase,
Dictionary<string, string> savedState,
IResourceManager resourceManager,
string userAgent,
RSACryptoServiceProvider proofKeyProviderNew,
RSACryptoServiceProvider proofKeyProviderOld)
{
RequestExecutionData executionData = new RequestExecutionData(
new Uri(GetEndpointAddressOverride(savedState)),
Enumerable.Empty<KeyValuePair<string, string>>(),
null);

return await ExecuteRequestAsync(executionData).ConfigureAwait(false);
}
}
}
116 changes: 107 additions & 9 deletions src/WopiValidator.Core/Requests/RequestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace Microsoft.Office.WopiValidator.Core.Requests
{
Expand Down Expand Up @@ -65,15 +66,7 @@ protected IResponseData ExecuteRequest(
TargetUrl = executionData.TargetUri.AbsoluteUri;
RequestHeaders = executionData.Headers.ToArray();

HttpWebRequest request = WebRequest.CreateHttp(executionData.TargetUri);
request.UserAgent = userAgent;
request.AllowAutoRedirect = false;

// apply custom headers
foreach (KeyValuePair<string, string> header in RequestHeaders)
request.Headers.Add(header.Key, header.Value);

request.Method = RequestMethod;
HttpWebRequest request = CreateHttpWebRequest(executionData, userAgent);

MemoryStream content = executionData.ContentStream;
// set proper ContentLength and content stream
Expand Down Expand Up @@ -116,6 +109,77 @@ protected IResponseData ExecuteRequest(
}
}

/// <summary>
/// Executes request and gathers response data.
/// </summary>
/// <param name="targetUri">URI request should be made against</param>
/// <param name="headers">Set of custom headers that should be added to the request</param>
/// <param name="content">Request content stream</param>
/// <returns>IResponseData instance with information takes from response.</returns>
protected async Task<IResponseData> ExecuteRequestAsync(
RequestExecutionData executionData,
string userAgent = null
)
{
TargetUrl = executionData.TargetUri.AbsoluteUri;
RequestHeaders = executionData.Headers.ToArray();

HttpWebRequest request = CreateHttpWebRequest(executionData, userAgent);

MemoryStream content = executionData.ContentStream;
// set proper ContentLength and content stream
if (content != null)
{
request.ContentLength = content.Length;
using (Stream requestStream = await request.GetRequestStreamAsync().ConfigureAwait(false))
{
content.Seek(0, SeekOrigin.Begin);
await content.CopyToAsync(requestStream).ConfigureAwait(false);
}
}
else
{
request.ContentLength = 0;
}
Stopwatch timer = new Stopwatch();
try
{
timer.Start();
using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync().ConfigureAwait(false))
{
timer.Stop();
return await GetResponseDataAsync(response, IsTextResponseExpected, timer.Elapsed).ConfigureAwait(false);
}
}
// ProtocolErrors will have a non-null Response object so we can still get response details
catch (WebException ex) when (ex.Status == WebExceptionStatus.ProtocolError)
{
using (HttpWebResponse response = (HttpWebResponse)ex.Response)
{
timer.Stop();
return await GetResponseDataAsync(response, IsTextResponseExpected, timer.Elapsed).ConfigureAwait(false);
}
}
// no response, so we wrap the exception details so they can be included in a validation failure
catch (WebException ex)
{
return ExceptionHelper.WrapExceptionInResponseData(ex);
}
}

private HttpWebRequest CreateHttpWebRequest(RequestExecutionData executionData, string userAgent)
{
HttpWebRequest request = WebRequest.CreateHttp(executionData.TargetUri);
request.UserAgent = userAgent;
request.AllowAutoRedirect = false;

// apply custom headers
foreach (KeyValuePair<string, string> header in RequestHeaders)
request.Headers.Add(header.Key, header.Value);

request.Method = RequestMethod;
return request;
}

/// <summary>
/// Replaces EndpointAddress if set
Expand Down Expand Up @@ -176,6 +240,30 @@ private static IResponseData GetResponseData(HttpWebResponse response, bool isTe
return new ResponseData(content, (int)response.StatusCode, headers, isTextResponseExpected, elapsed);
}

/// <summary>
/// Gets information from the response.
/// </summary>
/// <returns>IResponseData instance with information from the response.</returns>
private static async Task<IResponseData> GetResponseDataAsync(HttpWebResponse response, bool isTextResponseExpected, TimeSpan elapsed)
{
MemoryStream content = new MemoryStream();
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
await responseStream.CopyToAsync(content).ConfigureAwait(false);
}

// just to be sure
content.Seek(0, SeekOrigin.Begin);

Dictionary<string, string> headers = response.Headers
.Cast<string>()
.Select(k => new { Key = k, Value = response.Headers[ k ] })
.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);

return new ResponseData(content, (int)response.StatusCode, headers, isTextResponseExpected, elapsed);
}

public abstract IResponseData Execute(string endpointAddress,
string accessToken,
long accessTokenTtl,
Expand All @@ -185,5 +273,15 @@ public abstract IResponseData Execute(string endpointAddress,
string userAgent,
RSACryptoServiceProvider proofKeyProviderNew,
RSACryptoServiceProvider proofKeyProviderOld);

public abstract Task<IResponseData> ExecuteAsync(string endpointAddress,
string accessToken,
long accessTokenTtl,
ITestCase testCase,
Dictionary<string, string> savedState,
IResourceManager resourceManager,
string userAgent,
RSACryptoServiceProvider proofKeyProviderNew,
RSACryptoServiceProvider proofKeyProviderOld);
}
}
26 changes: 25 additions & 1 deletion src/WopiValidator.Core/Requests/WopiRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.Office.WopiValidator.Core.Requests
{
Expand Down Expand Up @@ -70,6 +71,29 @@ public override IResponseData Execute(string endpointAddress,
string userAgent,
RSACryptoServiceProvider proofKeyProviderNew,
RSACryptoServiceProvider proofKeyProviderOld)
{
RequestExecutionData executionData = CreateExecutionData(endpointAddress, ref accessToken, accessTokenTtl, savedState, resourceManager, proofKeyProviderNew, proofKeyProviderOld);
return ExecuteRequest(executionData, userAgent);
}

/// <summary>
/// Executes WOPI request at given WOPI endpoint address against provided wopi FileRep.
/// </summary>
public async override Task<IResponseData> ExecuteAsync(string endpointAddress,
string accessToken,
long accessTokenTtl,
ITestCase testCase,
Dictionary<string, string> savedState,
IResourceManager resourceManager,
string userAgent,
RSACryptoServiceProvider proofKeyProviderNew,
RSACryptoServiceProvider proofKeyProviderOld)
{
RequestExecutionData executionData = CreateExecutionData(endpointAddress, ref accessToken, accessTokenTtl, savedState, resourceManager, proofKeyProviderNew, proofKeyProviderOld);
return await ExecuteRequestAsync(executionData, userAgent).ConfigureAwait(false);
}

private RequestExecutionData CreateExecutionData(string endpointAddress, ref string accessToken, long accessTokenTtl, Dictionary<string, string> savedState, IResourceManager resourceManager, RSACryptoServiceProvider proofKeyProviderNew, RSACryptoServiceProvider proofKeyProviderOld)
{
// Get the url of the WOPI endpoint that we'll call - either the normal endpoint, or a SavedState override.
// If it's an override it might change the accessToken that we're using because it probably already has a token on it.
Expand Down Expand Up @@ -105,7 +129,7 @@ public override IResponseData Execute(string endpointAddress,

MemoryStream contentStream = HasRequestContent ? GetRequestContent(resourceManager) : null;
RequestExecutionData executionData = new RequestExecutionData(uri, headers, contentStream);
return ExecuteRequest(executionData, userAgent);
return executionData;
}

protected Uri GetRequestUri(string endpointAddress, ref string accessToken, long accessTokenTtl, Dictionary<string, string> savedState)
Expand Down
Loading