Skip to content

Commit be93091

Browse files
legendecasRafaelGSS
authored andcommitted
inspector: add protocol methods retrieving sent/received data
Add protocol method `Network.dataSent` to buffer request data. And expose protocol methods `Network.getRequestPostData` and `Network.getResponseBody` allowing devtool to retrieve buffered data. PR-URL: #58645 Reviewed-By: Ryuhei Shima <shimaryuhei@gmail.com>
1 parent b5ff3f4 commit be93091

11 files changed

Lines changed: 480 additions & 85 deletions

‎doc/api/inspector.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,20 @@ This feature is only available with the `--experimental-network-inspection` flag
524524
Broadcasts the `Network.dataReceived` event to connected frontends, or buffers the data if
525525
`Network.streamResourceContent` command was not invoked for the given request yet.
526526

527+
Also enables `Network.getResponseBody` command to retrieve the response data.
528+
529+
### `inspector.Network.dataSent([params])`
530+
531+
<!-- YAML
532+
added: REPLACEME
533+
-->
534+
535+
*`params` {Object}
536+
537+
This feature is only available with the `--experimental-network-inspection` flag enabled.
538+
539+
Enables `Network.getRequestPostData` command to retrieve the request data.
540+
527541
### `inspector.Network.requestWillBeSent([params])`
528542

529543
<!-- YAML

‎lib/inspector.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ const Network = {
214214
responseReceived: (params)=>broadcastToFrontend('Network.responseReceived',params),
215215
loadingFinished: (params)=>broadcastToFrontend('Network.loadingFinished',params),
216216
loadingFailed: (params)=>broadcastToFrontend('Network.loadingFailed',params),
217+
dataSent: (params)=>broadcastToFrontend('Network.dataSent',params),
217218
dataReceived: (params)=>broadcastToFrontend('Network.dataReceived',params),
218219
};
219220

‎lib/internal/inspector/network.js‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {
66
}=primordials;
77

88
const{ now }=require('internal/perf/utils');
9+
const{ MIMEType }=require('internal/mime');
910
constkInspectorRequestId=Symbol('kInspectorRequestId');
1011

1112
// https://chromedevtools.github.io/devtools-protocol/1-3/Network/#type-ResourceType
@@ -46,9 +47,29 @@ function getNextRequestId() {
4647
return`node-network-event-${++requestId}`;
4748
};
4849

50+
functionsniffMimeType(contentType){
51+
letmimeType;
52+
letcharset;
53+
try{
54+
constmimeTypeObj=newMIMEType(contentType);
55+
mimeType=mimeTypeObj.essence||'';
56+
charset=mimeTypeObj.params.get('charset')||'';
57+
}catch{
58+
mimeType='';
59+
charset='';
60+
}
61+
62+
return{
63+
__proto__: null,
64+
mimeType,
65+
charset,
66+
};
67+
}
68+
4969
module.exports={
5070
kInspectorRequestId,
5171
kResourceType,
5272
getMonotonicTime,
5373
getNextRequestId,
74+
sniffMimeType,
5475
};

‎lib/internal/inspector/network_http.js‎

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,43 @@ const {
1313
kResourceType,
1414
getMonotonicTime,
1515
getNextRequestId,
16+
sniffMimeType,
1617
}=require('internal/inspector/network');
1718
constdc=require('diagnostics_channel');
1819
const{ Network }=require('inspector');
19-
const{ MIMEType }=require('internal/mime');
2020

2121
constkRequestUrl=Symbol('kRequestUrl');
2222

2323
// Convert a Headers object (Map<string, number | string | string[]>) to a plain object (Map<string, string>)
2424
constconvertHeaderObject=(headers={})=>{
2525
// The 'host' header that contains the host and port of the URL.
2626
lethost;
27+
letcharset;
28+
letmimeType;
2729
constdict={};
2830
for(const{0: key,1: value}ofObjectEntries(headers)){
29-
if(key.toLowerCase()==='host'){
31+
constlowerCasedKey=key.toLowerCase();
32+
if(lowerCasedKey==='host'){
3033
host=value;
3134
}
35+
if(lowerCasedKey==='content-type'){
36+
constresult=sniffMimeType(value);
37+
charset=result.charset;
38+
mimeType=result.mimeType;
39+
}
3240
if(typeofvalue==='string'){
3341
dict[key]=value;
3442
}elseif(ArrayIsArray(value)){
35-
if(key.toLowerCase()==='cookie')dict[key]=value.join('; ');
43+
if(lowerCasedKey==='cookie')dict[key]=value.join('; ');
3644
// ChromeDevTools frontend treats 'set-cookie' as a special case
3745
// https://github.com/ChromeDevTools/devtools-frontend/blob/4275917f84266ef40613db3c1784a25f902ea74e/front_end/core/sdk/NetworkRequest.ts#L1368
38-
elseif(key.toLowerCase()==='set-cookie')dict[key]=value.join('\n');
46+
elseif(lowerCasedKey==='set-cookie')dict[key]=value.join('\n');
3947
elsedict[key]=value.join(', ');
4048
}else{
4149
dict[key]=String(value);
4250
}
4351
}
44-
return[host,dict];
52+
return[dict,host,charset,mimeType];
4553
};
4654

4755
/**
@@ -52,14 +60,15 @@ const convertHeaderObject = (headers = {}) => {
5260
functiononClientRequestCreated({ request }){
5361
request[kInspectorRequestId]=getNextRequestId();
5462

55-
const{0: host,1: headers}=convertHeaderObject(request.getHeaders());
63+
const{0: headers,1: host,2: charset}=convertHeaderObject(request.getHeaders());
5664
consturl=`${request.protocol}//${host}${request.path}`;
5765
request[kRequestUrl]=url;
5866

5967
Network.requestWillBeSent({
6068
requestId: request[kInspectorRequestId],
6169
timestamp: getMonotonicTime(),
6270
wallTime: DateNow(),
71+
charset,
6372
request: {
6473
url,
6574
method: request.method,
@@ -95,16 +104,7 @@ function onClientResponseFinish({ request, response }) {
95104
return;
96105
}
97106

98-
letmimeType;
99-
letcharset;
100-
try{
101-
constmimeTypeObj=newMIMEType(response.headers['content-type']);
102-
mimeType=mimeTypeObj.essence||'';
103-
charset=mimeTypeObj.params.get('charset')||'';
104-
}catch{
105-
mimeType='';
106-
charset='';
107-
}
107+
const{0: headers,2: charset,3: mimeType}=convertHeaderObject(response.headers);
108108

109109
Network.responseReceived({
110110
requestId: request[kInspectorRequestId],
@@ -114,7 +114,7 @@ function onClientResponseFinish({ request, response }) {
114114
url: request[kRequestUrl],
115115
status: response.statusCode,
116116
statusText: response.statusMessage??'',
117-
headers: convertHeaderObject(response.headers)[1],
117+
headers,
118118
mimeType,
119119
charset,
120120
},

‎lib/internal/inspector/network_undici.js‎

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const{
4-
ArrayPrototypeFindIndex,
54
DateNow,
65
}=primordials;
76

@@ -10,10 +9,10 @@ const {
109
kResourceType,
1110
getMonotonicTime,
1211
getNextRequestId,
12+
sniffMimeType,
1313
}=require('internal/inspector/network');
1414
constdc=require('diagnostics_channel');
1515
const{ Network }=require('inspector');
16-
const{ MIMEType }=require('internal/mime');
1716

1817
// Convert an undici request headers array to a plain object (Map<string, string>)
1918
functionrequestHeadersArrayToDictionary(headers){
@@ -29,21 +28,30 @@ function requestHeadersArrayToDictionary(headers) {
2928
// Convert an undici response headers array to a plain object (Map<string, string>)
3029
functionresponseHeadersArrayToDictionary(headers){
3130
constdict={};
31+
letcharset;
32+
letmimeType;
3233
for(letidx=0;idx<headers.length;idx+=2){
3334
constkey=`${headers[idx]}`;
35+
constlowerCasedKey=key.toLowerCase();
3436
constvalue=`${headers[idx+1]}`;
3537
constprevValue=dict[key];
3638

39+
if(lowerCasedKey==='content-type'){
40+
constresult=sniffMimeType(value);
41+
charset=result.charset;
42+
mimeType=result.mimeType;
43+
}
44+
3745
if(typeofprevValue==='string'){
3846
// ChromeDevTools frontend treats 'set-cookie' as a special case
3947
// https://github.com/ChromeDevTools/devtools-frontend/blob/4275917f84266ef40613db3c1784a25f902ea74e/front_end/core/sdk/NetworkRequest.ts#L1368
40-
if(key.toLowerCase()==='set-cookie')dict[key]=`${prevValue}\n${value}`;
48+
if(lowerCasedKey==='set-cookie')dict[key]=`${prevValue}\n${value}`;
4149
elsedict[key]=`${prevValue}, ${value}`;
4250
}else{
4351
dict[key]=value;
4452
}
4553
}
46-
returndict;
54+
return[dict,charset,mimeType];
4755
};
4856

4957
/**
@@ -54,10 +62,15 @@ function responseHeadersArrayToDictionary(headers) {
5462
functiononClientRequestStart({ request }){
5563
consturl=`${request.origin}${request.path}`;
5664
request[kInspectorRequestId]=getNextRequestId();
65+
66+
constheaders=requestHeadersArrayToDictionary(request.headers);
67+
const{ charset }=sniffMimeType(headers);
68+
5769
Network.requestWillBeSent({
5870
requestId: request[kInspectorRequestId],
5971
timestamp: getMonotonicTime(),
6072
wallTime: DateNow(),
73+
charset,
6174
request: {
6275
url,
6376
method: request.method,
@@ -94,19 +107,7 @@ function onClientResponseHeaders({ request, response }) {
94107
return;
95108
}
96109

97-
letmimeType;
98-
letcharset;
99-
try{
100-
constcontentTypeKeyIndex=
101-
ArrayPrototypeFindIndex(response.headers,(header)=>header.toString().toLowerCase()==='content-type');
102-
constcontentType=contentTypeKeyIndex!==-1 ? response.headers[contentTypeKeyIndex+1].toString() : '';
103-
constmimeTypeObj=newMIMEType(contentType);
104-
mimeType=mimeTypeObj.essence||'';
105-
charset=mimeTypeObj.params.get('charset')||'';
106-
}catch{
107-
mimeType='';
108-
charset='';
109-
}
110+
const{0: headers,1: charset,2: mimeType}=responseHeadersArrayToDictionary(response.headers);
110111

111112
consturl=`${request.origin}${request.path}`;
112113
Network.responseReceived({
@@ -118,7 +119,7 @@ function onClientResponseHeaders({ request, response }) {
118119
url,
119120
status: response.statusCode,
120121
statusText: response.statusText,
121-
headers: responseHeadersArrayToDictionary(response.headers),
122+
headers,
122123
mimeType,
123124
charset,
124125
},

0 commit comments

Comments
 (0)