Skip to content

Commit

Permalink
Allow ResponseData.Headers to support multiple values for the same key (
Browse files Browse the repository at this point in the history
hardkoded#1831)

* Allow ResponseData.Headers to support multiple values for the same key

- Without breaking the current API this change allows for arrays of values
  (Anything that implements ICollection and can be iterated over).
- The Headers with null values will be ignored, previously an exception
  would have occurred with the Value.ToString() call so this is unlikely
  a breaking change in behaviour.
- New test case added

Resolves hardkoded#1542

* Apply suggestions from code review

Co-authored-by: Darío Kondratiuk <dariokondratiuk@gmail.com>
  • Loading branch information
amaitland and kblok authored Oct 5, 2021
1 parent 39594ea commit 80a9aed
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,35 @@ await e.Request.RespondAsync(new ResponseData
Assert.Equal("True", response.Headers["foo"]);
Assert.Equal("Yo, page!", await Page.EvaluateExpressionAsync<string>("document.body.textContent"));
}

[SkipBrowserFact(skipFirefox: true)]
public async Task ShouldAllowMultipleInterceptedRequestResponseHeaders()
{
await Page.SetRequestInterceptionAsync(true);
Page.Request += async (_, e) =>
{
await e.Request.RespondAsync(new ResponseData
{
Status = HttpStatusCode.OK,
Headers = new Dictionary<string, object>
{
["foo"] = new bool[] { true, false },
["Set-Cookie"] = new string[] { "sessionId=abcdef", "specialId=123456" }
},
Body = "Yo, page!"
});
};

var response = await Page.GoToAsync(TestConstants.EmptyPage);
var cookies = await Page.GetCookiesAsync(TestConstants.EmptyPage);

Assert.Equal(HttpStatusCode.OK, response.Status);
Assert.Equal("True\nFalse", response.Headers["foo"]);
Assert.Equal("Yo, page!", await Page.EvaluateExpressionAsync<string>("document.body.textContent"));
Assert.Equal("specialId", cookies[0].Name);
Assert.Equal("123456", cookies[0].Value);
Assert.Equal("sessionId", cookies[1].Name);
Assert.Equal("abcdef", cookies[1].Value);
}
}
}
36 changes: 26 additions & 10 deletions lib/PuppeteerSharp/Request.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
Expand Down Expand Up @@ -231,24 +232,39 @@ public async Task RespondAsync(ResponseData response)

_interceptionHandled = true;

var responseHeaders = new Dictionary<string, string>();
var responseHeaders = new List<Header>();

if (response.Headers != null)
{
foreach (var keyValue in response.Headers)
foreach (var keyValuePair in response.Headers)
{
responseHeaders[keyValue.Key] = keyValue.Value.ToString();
if (keyValuePair.Value == null)
{
continue;
}

if (keyValuePair.Value is ICollection values)
{
foreach (var val in values)
{
responseHeaders.Add(new Header { Name = keyValuePair.Key, Value = val.ToString() });
}
}
else
{
responseHeaders.Add(new Header { Name = keyValuePair.Key, Value = keyValuePair.Value.ToString() });
}
}
}

if (response.ContentType != null)
{
responseHeaders["content-type"] = response.ContentType;
if (!response.Headers.ContainsKey("content-length") && response.BodyData != null)
{
responseHeaders.Add(new Header { Name = "content-length", Value = response.BodyData.Length.ToString(CultureInfo.CurrentCulture) });
}
}

if (!responseHeaders.ContainsKey("content-length") && response.BodyData != null)
if (response.ContentType != null)
{
responseHeaders["content-length"] = response.BodyData.Length.ToString(CultureInfo.CurrentCulture);
responseHeaders.Add(new Header { Name = "content-type", Value = response.ContentType });
}

try
Expand All @@ -257,7 +273,7 @@ public async Task RespondAsync(ResponseData response)
{
RequestId = InterceptionId,
ResponseCode = response.Status != null ? (int)response.Status : 200,
ResponseHeaders = HeadersArray(responseHeaders),
ResponseHeaders = responseHeaders.ToArray(),
Body = response.BodyData != null ? Convert.ToBase64String(response.BodyData) : null
}).ConfigureAwait(false);
}
Expand Down
4 changes: 3 additions & 1 deletion lib/PuppeteerSharp/ResponseData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ public string Body
/// <value>The body as binary.</value>
public byte[] BodyData { get; set; }
/// <summary>
/// Response headers. Header values will be converted to a string.
/// Response headers. Header values will be converted to strings. Headers with null values will be
/// ignored. When multiple headers values are required use an <see cref="System.Collections.ICollection"/>
/// to add multiple values for the Header key.
/// </summary>
/// <value>Headers.</value>
public Dictionary<string, object> Headers { get; set; }
Expand Down

0 comments on commit 80a9aed

Please sign in to comment.