Pavel Pykhtin Pavel Pykhtin - 8 days ago 7
C# Question

Set 'per request' cookie with .Net HttpClient

Hi I'm trying to implement simple http proxy service using Owin infrastructure. This proxy must authenticate user with windows authentication, pull user's properties from the enterprise AD, add this info as a cookie value into original request and then redirect request to the application on the Internet (lets call it External Application).

I'm using HttpClient to send request to the External Application.

However HttpClient does not fit well for this scenario. It seems that the only allowed way to send cookie using it is to put them into CookieContainer and set this CookieContainer as a property of HttpClientHandler. It's ok when you have single user but in case of a proxy service cookie values from different users will mix and overwrite each other.

Is there any way to set cookie or CookieContainer per request? Or maybe there is a better way to redirect requests?

P.S. Here is some code:

Initialization of http handlers:

private void RegisterRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "Proxy",
routeTemplate: "{*path}",
handler: HttpClientFactory.CreatePipeline
(
innerHandler: new HttpClientHandler(),
handlers: new DelegatingHandler[]
{
new ProxyHandler()
}
),
defaults: new { path = RouteParameter.Optional },
constraints: null);
}


ProxyHandler
internal class ProxyHandler : DelegatingHandler
{
private readonly HttpClient _client;

public ProxyHandler()
{
var handler = new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Automatic};

_client = new HttpClient(handler);
}

protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var forwardUri = new UriBuilder(request.RequestUri);
forwardUri.Host = "localhost";
forwardUri.Port = 23016;
forwardUri.Scheme = Uri.UriSchemeHttp;

request.RequestUri = forwardUri.Uri;
request.Headers.Host = forwardUri.Host;

//Explicitly null it to avoid protocol violation
if (request.Method == HttpMethod.Get || request.Method == HttpMethod.Trace)
request.Content = null;

try
{
var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

//Explicitly null it to avoid protocol violation
if (request.Method == HttpMethod.Head)
response.Content = null;
return response;
}
catch (Exception ex)
{
var response = request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
string message = ex.Message;
if (ex.InnerException != null)
message += ':' + ex.InnerException.Message;
response.Content = new StringContent(message);
Trace.TraceError("Error:{0}", message);
return response;
}
}

private void SetCookies(HttpRequestMessage request)
{
var container = new CookieContainer();

var authCookieValue = "2EF91D8FD9EDC594F2DB82";
var authCookie = new Cookie("cookieByProxy", authCookieValue);

var targetUri = new Uri("http://localhost:23016/");
container.Add(targetUri, authCookie);

var cookieHeader = container.GetCookieHeader(targetUri);

if (!string.IsNullOrEmpty(cookieHeader))
request.Headers.TryAddWithoutValidation("Cookie", cookieHeader);//Overwriting cookie header with custom values. However cookie values are ignored by HttpClient (both old and new)
}
}

Answer

Found solution here: enter link description here The trick is in explicitly setting UseCookie flag of the HttpClientHandler to false.

var handler = new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Automatic, UseCookie = false };
Comments