Skip to content

Commit

Permalink
Request Options : Adds fix to support injecting/appending custom head…
Browse files Browse the repository at this point in the history
…ers into request via RequestOptions. (Azure#2371)

This PR focuses on adding support to inject custom headers into requests via RequestOptions. This would allow customers to directly inject custom headers. (The RequestOptions.Properties is meant for the client context and is not meant for adding headers.)
  • Loading branch information
kr-santosh authored Apr 22, 2021
1 parent b9bb04a commit f1bac2a
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 1 deletion.
26 changes: 26 additions & 0 deletions Microsoft.Azure.Cosmos/src/RequestOptions/RequestOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ public class RequestOptions
/// </summary>
public IReadOnlyDictionary<string, object> Properties { get; set; }

#if PREVIEW
/// <summary>
/// Gets or sets a delegate which injects/appends a custom header in the request.
/// </summary>
public
#else
internal
#endif
Action<Headers> AddRequestHeaders { get; set; }

/// <summary>
/// Gets or sets the boolean to use effective partition key routing in the cosmos db request.
/// </summary>
Expand Down Expand Up @@ -79,6 +89,22 @@ internal virtual void PopulateRequestOptions(RequestMessage request)
{
request.Headers.Add(HttpConstants.HttpHeaders.IfNoneMatch, this.IfNoneMatchEtag);
}

this.AddRequestHeaders?.Invoke(request.Headers);
}

#if PREVIEW
/// <summary>
/// Clone RequestOptions.
/// </summary>
/// <returns> cloned RequestOptions. </returns>
public
#else
internal
#endif
RequestOptions ShallowCopy()
{
return this.MemberwiseClone() as RequestOptions;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,41 @@ public async Task VerifyKnownHeaders()
}
}

[TestMethod]
public async Task VerifyRequestOptionCustomRequestHeaders()
{
CustomHeaderValidationHandler headerValidationHandler = new CustomHeaderValidationHandler();
using CosmosClient client = TestCommon.CreateCosmosClient(x => x.AddCustomHandlers(headerValidationHandler));
Database database = null;
try
{
database = await client.CreateDatabaseAsync(nameof(VerifyRequestOptionCustomRequestHeaders) + Guid.NewGuid().ToString());
Container container = await database.CreateContainerAsync(
Guid.NewGuid().ToString(),
"/pk");

ToDoActivity toDoActivity = ToDoActivity.CreateRandomToDoActivity();
ItemRequestOptions requestOptions = new ItemRequestOptions
{
AddRequestHeaders = (headers) => headers["x-ms-cosmos-database-rid"] = "databaseRidValue",
};

await container.CreateItemAsync(toDoActivity, new PartitionKey(toDoActivity.pk), requestOptions: requestOptions);

// null pass
requestOptions.AddRequestHeaders = null;

await container.ReadItemAsync<ToDoActivity>(toDoActivity.id, new PartitionKey(toDoActivity.pk), requestOptions: requestOptions);
}
finally
{
if (database != null)
{
await database.DeleteStreamAsync();
}
}
}

private class HeaderValidationHandler : RequestHandler
{
public override async Task<ResponseMessage> SendAsync(RequestMessage request, CancellationToken cancellationToken)
Expand Down Expand Up @@ -76,5 +111,28 @@ private void ValidateLazyHeadersAreNotCreated(CosmosMessageHeadersInternal inter
}
}
}

private class CustomHeaderValidationHandler : RequestHandler
{
public override async Task<ResponseMessage> SendAsync(RequestMessage request, CancellationToken cancellationToken)
{
if (request.ResourceType == Documents.ResourceType.Document)
{
this.ValidateCustomHeaders(request.Headers.CosmosMessageHeaders);
}

return await base.SendAsync(request, cancellationToken);
}

private void ValidateCustomHeaders(CosmosMessageHeadersInternal internalHeaders)
{
string customHeaderValue = internalHeaders.Get("x-ms-cosmos-database-rid");

if (!string.IsNullOrEmpty(customHeaderValue))
{
Assert.AreEqual("databaseRidValue", customHeaderValue);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1797,7 +1797,32 @@
"NestedTypes": {}
}
},
"Members": {},
"Members": {
"Microsoft.Azure.Cosmos.RequestOptions ShallowCopy()": {
"Type": "Method",
"Attributes": [],
"MethodInfo": "Microsoft.Azure.Cosmos.RequestOptions ShallowCopy();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"System.Action`1[Microsoft.Azure.Cosmos.Headers] AddRequestHeaders": {
"Type": "Property",
"Attributes": [],
"MethodInfo": "System.Action`1[Microsoft.Azure.Cosmos.Headers] AddRequestHeaders;CanRead:True;CanWrite:True;System.Action`1[Microsoft.Azure.Cosmos.Headers] get_AddRequestHeaders();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;Void set_AddRequestHeaders(System.Action`1[Microsoft.Azure.Cosmos.Headers]);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"System.Action`1[Microsoft.Azure.Cosmos.Headers] get_AddRequestHeaders()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
"Attributes": [
"CompilerGeneratedAttribute"
],
"MethodInfo": "System.Action`1[Microsoft.Azure.Cosmos.Headers] get_AddRequestHeaders();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"Void set_AddRequestHeaders(System.Action`1[Microsoft.Azure.Cosmos.Headers])[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
"Attributes": [
"CompilerGeneratedAttribute"
],
"MethodInfo": "Void set_AddRequestHeaders(System.Action`1[Microsoft.Azure.Cosmos.Headers]);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
}
},
"NestedTypes": {}
},
"Microsoft.Azure.Cosmos.TransactionalBatch;System.Object;IsAbstract:True;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": {
Expand Down

0 comments on commit f1bac2a

Please sign in to comment.