Skip to content

Commit 408e3ea

Browse files
authored
Support fetching request POST data (#2402)
* Support fetching request POST data * rider had the wrong file header
1 parent fa171fb commit 408e3ea

File tree

10 files changed

+123
-13
lines changed

10 files changed

+123
-13
lines changed

lib/PuppeteerSharp.Tests/DeviceRequestPromptTests/MockCDPSession.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// * MIT License
22
// *
3-
// * Copyright (c) Microsoft Corporation.
3+
// * Copyright (c) Darío Kondratiuk
44
// *
55
// * Permission is hereby granted, free of charge, to any person obtaining a copy
66
// * of this software and associated documentation files (the "Software"), to deal

lib/PuppeteerSharp.Tests/NetworkTests/RequestPostDataTests.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ namespace PuppeteerSharp.Tests.NetworkTests
1010
{
1111
public class RequestPostDataTests : PuppeteerPageBaseTest
1212
{
13-
public RequestPostDataTests(): base()
14-
{
15-
}
16-
1713
[PuppeteerTest("network.spec.ts", "Request.postData", "should work")]
1814
[Skip(SkipAttribute.Targets.Firefox)]
1915
public async Task ShouldWork()
@@ -34,5 +30,25 @@ public async Task ShouldBeUndefinedWhenThereIsNoPostData()
3430
var response = await Page.GoToAsync(TestConstants.EmptyPage);
3531
Assert.Null(response.Request.PostData);
3632
}
33+
34+
[PuppeteerTest("network.spec.ts", "Request.postData", "should work with blobs")]
35+
[Skip(SkipAttribute.Targets.Firefox)]
36+
public async Task ShouldWorkWithBlobs()
37+
{
38+
await Page.GoToAsync(TestConstants.EmptyPage);
39+
Server.SetRoute("/post", _ => Task.CompletedTask);
40+
IRequest request = null;
41+
Page.Request += (_, e) => request = e.Request;
42+
await Page.EvaluateExpressionHandleAsync(@"fetch('./post', {
43+
method: 'POST',
44+
body:new Blob([JSON.stringify({foo: 'bar'})], {
45+
type: 'application/json',
46+
}),
47+
})");
48+
Assert.NotNull(request);
49+
Assert.Null(request.PostData);
50+
Assert.True(request.HasPostData);
51+
Assert.AreEqual("{\"foo\":\"bar\"}", await request.FetchPostDataAsync());
52+
}
3753
}
3854
}

lib/PuppeteerSharp/DeviceRequestPromptManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// * MIT License
22
// *
3-
// * Copyright (c) Microsoft Corporation.
3+
// * Copyright (c) Darío Kondratiuk
44
// *
55
// * Permission is hereby granted, free of charge, to any person obtaining a copy
66
// * of this software and associated documentation files (the "Software"), to deal

lib/PuppeteerSharp/IRequest.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace PuppeteerSharp
1717
public interface IRequest
1818
{
1919
/// <summary>
20-
/// Responsed attached to the request.
20+
/// Response attached to the request.
2121
/// </summary>
2222
/// <value>The response.</value>
2323
public IResponse Response { get; }
@@ -105,6 +105,13 @@ public interface IRequest
105105
/// <value>The redirect chain.</value>
106106
IRequest[] RedirectChain { get; }
107107

108+
/// <summary>
109+
/// True when the request has POST data. Note that <see cref="PostData"/> might still be null when this flag is true
110+
/// when the data is too long or not readily available in the decoded form.
111+
/// In that case, use <see cref="FetchPostDataAsync"/>.
112+
/// </summary>
113+
bool HasPostData { get; }
114+
108115
/// <summary>
109116
/// Continues request with optional request overrides. To use this, request interception should be enabled with <see cref="IPage.SetRequestInterceptionAsync(bool)"/>. Exception is immediately thrown if the request interception is not enabled.
110117
/// If the URL is set it won't perform a redirect. The request will be silently forwarded to the new url. For example, the address bar will show the original url.
@@ -127,5 +134,11 @@ public interface IRequest
127134
/// <param name="errorCode">Optional error code. Defaults to <see cref="RequestAbortErrorCode.Failed"/>.</param>
128135
/// <returns>Task.</returns>
129136
Task AbortAsync(RequestAbortErrorCode errorCode = RequestAbortErrorCode.Failed);
137+
138+
/// <summary>
139+
/// Fetches the POST data for the request from the browser.
140+
/// </summary>
141+
/// <returns>Task which resolves to the request's POST data.</returns>
142+
Task<string> FetchPostDataAsync();
130143
}
131144
}

lib/PuppeteerSharp/Messaging/DeviceAccessCancelPrompt.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// * MIT License
22
// *
3-
// * Copyright (c) Microsoft Corporation.
3+
// * Copyright (c) Darío Kondratiuk
44
// *
55
// * Permission is hereby granted, free of charge, to any person obtaining a copy
66
// * of this software and associated documentation files (the "Software"), to deal

lib/PuppeteerSharp/Messaging/DeviceAccessSelectPrompt.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// * MIT License
22
// *
3-
// * Copyright (c) Microsoft Corporation.
3+
// * Copyright (c) Darío Kondratiuk
44
// *
55
// * Permission is hereby granted, free of charge, to any person obtaining a copy
66
// * of this software and associated documentation files (the "Software"), to deal
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// * MIT License
2+
// *
3+
// * Copyright (c) Darío Kondratiuk
4+
// *
5+
// * Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// * of this software and associated documentation files (the "Software"), to deal
7+
// * in the Software without restriction, including without limitation the rights
8+
// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// * copies of the Software, and to permit persons to whom the Software is
10+
// * furnished to do so, subject to the following conditions:
11+
// *
12+
// * The above copyright notice and this permission notice shall be included in all
13+
// * copies or substantial portions of the Software.
14+
// *
15+
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// * SOFTWARE.
22+
23+
namespace PuppeteerSharp.Messaging.Protocol.Network;
24+
25+
internal class GetRequestPostDataRequest(string requestId)
26+
{
27+
public string RequestId { get; set; } = requestId;
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// * MIT License
2+
// *
3+
// * Copyright (c) Darío Kondratiuk
4+
// *
5+
// * Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// * of this software and associated documentation files (the "Software"), to deal
7+
// * in the Software without restriction, including without limitation the rights
8+
// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// * copies of the Software, and to permit persons to whom the Software is
10+
// * furnished to do so, subject to the following conditions:
11+
// *
12+
// * The above copyright notice and this permission notice shall be included in all
13+
// * copies or substantial portions of the Software.
14+
// *
15+
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// * SOFTWARE.
22+
23+
namespace PuppeteerSharp.Messaging.Protocol.Network;
24+
25+
internal class GetRequestPostDataResponse
26+
{
27+
public string PostData { get; set; }
28+
}

lib/PuppeteerSharp/Payload.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
using System;
21
using System.Collections.Generic;
3-
using System.Linq;
42
using System.Net.Http;
5-
using System.Web;
63
using Newtonsoft.Json;
74
using PuppeteerSharp.Helpers.Json;
85

@@ -30,12 +27,17 @@ public class Payload
3027
/// Gets or sets the HTTP headers.
3128
/// </summary>
3229
/// <value>HTTP headers.</value>
33-
public Dictionary<string, string> Headers { get; set; } = new();
30+
public Dictionary<string, string> Headers { get; set; } = [];
3431

3532
/// <summary>
3633
/// Gets or sets the URL.
3734
/// </summary>
3835
/// <value>The URL.</value>
3936
public string Url { get; set; }
37+
38+
/// <summary>
39+
/// Gets or sets a value indicating whether this <see cref="Payload"/> has post data.
40+
/// </summary>
41+
public bool? HasPostData { get; set; }
4042
}
4143
}

lib/PuppeteerSharp/Request.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Threading.Tasks;
99
using Microsoft.Extensions.Logging;
1010
using PuppeteerSharp.Messaging;
11+
using PuppeteerSharp.Messaging.Protocol.Network;
1112

1213
namespace PuppeteerSharp
1314
{
@@ -39,6 +40,7 @@ internal Request(
3940
ResourceType = e.Type;
4041
Method = e.Request.Method;
4142
PostData = e.Request.PostData;
43+
HasPostData = e.Request.HasPostData ?? false;
4244
Frame = frame;
4345
RedirectChainList = redirectChain;
4446

@@ -90,6 +92,9 @@ internal Request(
9092
/// <inheritdoc/>
9193
public IRequest[] RedirectChain => RedirectChainList.ToArray();
9294

95+
/// <inheritdoc/>
96+
public bool HasPostData { get; private set; }
97+
9398
internal bool FromMemoryCache { get; set; }
9499

95100
internal List<IRequest> RedirectChainList { get; }
@@ -263,6 +268,24 @@ public async Task AbortAsync(RequestAbortErrorCode errorCode = RequestAbortError
263268
}
264269
}
265270

271+
/// <inheritdoc />
272+
public async Task<string> FetchPostDataAsync()
273+
{
274+
try
275+
{
276+
var result = await _client.SendAsync<GetRequestPostDataResponse>(
277+
"Network.getRequestPostData",
278+
new GetRequestPostDataRequest(RequestId)).ConfigureAwait(false);
279+
return result.PostData;
280+
}
281+
catch (Exception ex)
282+
{
283+
_logger.LogError(ex, ex.ToString());
284+
}
285+
286+
return null;
287+
}
288+
266289
private Header[] HeadersArray(Dictionary<string, string> headers)
267290
=> headers?.Select(pair => new Header { Name = pair.Key, Value = pair.Value }).ToArray();
268291
}

0 commit comments

Comments
 (0)