Skip to content

Commit 553332c

Browse files
amitjoshi438Amit Joshi
andauthored
Add URL-encoded body processing and refactor HTTP methods (#1397)
* Add body processing for URL-encoded content type in HttpClient * Remove default contentType parameter from DeleteAsync method in Server logic mock SDK * Refactor URL parsing to use the URL constructor and update path and port handling in Server logic mock SDK * Add server logic debugging feature toggle and telemetry events * Enable server logic debugging context in command visibility --------- Co-authored-by: Amit Joshi <[email protected]>
1 parent 77cda07 commit 553332c

File tree

6 files changed

+101
-32
lines changed

6 files changed

+101
-32
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@
962962
{
963963
"command": "microsoft.powerplatform.pages.debugServerLogic",
964964
"group": "navigation",
965-
"when": "resourcePath =~ /server-logics?[/\\\\]/ && resourceExtname == .js"
965+
"when": "microsoft.powerplatform.pages.serverLogicDebuggingEnabled && resourcePath =~ /server-logics?[/\\\\]/ && resourceExtname == .js"
966966
}
967967
],
968968
"commandPalette": [

src/common/OneDSLoggerTelemetry/client/desktopExtensionTelemetryEventNames.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export enum desktopTelemetryEventNames {
77
DESKTOP_EXTENSION_INIT_CONTEXT = "DesktopExtensionInitContext",
88

99
// Server Logic Debugger Events
10+
SERVER_LOGIC_DEBUG_FEATURE_DISABLED = "ServerLogicDebugFeatureDisabled",
1011
SERVER_LOGIC_DEBUG_STARTED = "ServerLogicDebugStarted",
1112
SERVER_LOGIC_DEBUG_COMMAND_EXECUTED = "ServerLogicDebugCommandExecuted",
1213
SERVER_LOGIC_RUN_COMMAND_EXECUTED = "ServerLogicRunCommandExecuted",

src/common/ecs-features/ecsFeatureGates.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,13 @@ export const {
140140
enableMetadataDiff: false,
141141
}
142142
});
143+
144+
export const {
145+
feature: EnableServerLogicDebugging
146+
} = getFeatureConfigs({
147+
teamName: PowerPagesClientName,
148+
description: 'Enable Server Logic Debugging in VS Code Desktop',
149+
fallback: {
150+
enableServerLogicDebugging: false,
151+
}
152+
});

src/debugger/server-logic/ServerLogicDebugger.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { oneDSLoggerWrapper } from '../../common/OneDSLoggerTelemetry/oneDSLogge
1111
import { ServerLogicCodeLensProvider } from './ServerLogicCodeLensProvider';
1212
import { ServerLogicDebugProvider } from './ServerLogicDebugProvider';
1313
import { desktopTelemetryEventNames } from '../../common/OneDSLoggerTelemetry/client/desktopExtensionTelemetryEventNames';
14+
import { ECSFeaturesClient } from '../../common/ecs-features/ecsFeatureClient';
15+
import { EnableServerLogicDebugging } from '../../common/ecs-features/ecsFeatureGates';
1416
import {
1517
SERVER_LOGIC_CONFIG_KEYS,
1618
SERVER_LOGIC_FILES,
@@ -100,10 +102,33 @@ function ensureGitignore(gitignorePath: string): void {
100102
}
101103
}
102104

105+
/**
106+
* Checks if server logic debugging is enabled via FCB
107+
* @returns true if the feature is enabled
108+
*/
109+
export function isServerLogicDebuggingEnabled(): boolean {
110+
const { enableServerLogicDebugging } = ECSFeaturesClient.getConfig(EnableServerLogicDebugging);
111+
return enableServerLogicDebugging;
112+
}
113+
103114
/**
104115
* Activates the Server Logic debugger
105116
*/
106117
export function activateServerLogicDebugger(context: vscode.ExtensionContext): void {
118+
const isEnabled = isServerLogicDebuggingEnabled();
119+
120+
// Set context for menu visibility
121+
vscode.commands.executeCommand("setContext", "microsoft.powerplatform.pages.serverLogicDebuggingEnabled", isEnabled);
122+
123+
// Check FCB before activating
124+
if (!isEnabled) {
125+
oneDSLoggerWrapper.getLogger().traceInfo(
126+
desktopTelemetryEventNames.SERVER_LOGIC_DEBUG_FEATURE_DISABLED,
127+
{}
128+
);
129+
return;
130+
}
131+
107132
const provider = new ServerLogicDebugProvider();
108133
context.subscriptions.push(
109134
vscode.debug.registerDebugConfigurationProvider('node', provider)

src/debugger/server-logic/ServerLogicMockSdk.ts

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,28 @@ const Server = {
5959
6060
Connector: {
6161
HttpClient: {
62+
_processBodyForContentType: function(body, contentType) {
63+
if (contentType === "application/x-www-form-urlencoded" && body) {
64+
try {
65+
const bodyObj = JSON.parse(body);
66+
const isNodeJs = typeof process !== 'undefined' &&
67+
process.versions != null &&
68+
process.versions.node != null;
69+
70+
if (isNodeJs) {
71+
const querystring = require('querystring');
72+
return querystring.stringify(bodyObj);
73+
} else {
74+
return new URLSearchParams(bodyObj).toString();
75+
}
76+
} catch (e) {
77+
Server.Logger.Warning(\`[TRANSFORM] Body is not valid JSON, using as-is: \${e.message}\`);
78+
return body;
79+
}
80+
}
81+
return body;
82+
},
83+
6284
GetAsync: async function (url, headers = {}) {
6385
Server.Logger.Log(\`[MOCK] HttpClient.GetAsync called with URL: \${url}\`);
6486
@@ -72,16 +94,15 @@ const Server = {
7294
try {
7395
const https = require('https');
7496
const http = require('http');
75-
const urlLib = require('url');
7697
77-
const parsedUrl = urlLib.parse(url);
98+
const parsedUrl = new URL(url);
7899
const protocol = parsedUrl.protocol === 'https:' ? https : http;
79100
80101
return new Promise((resolve, reject) => {
81102
const options = {
82103
hostname: parsedUrl.hostname,
83-
port: parsedUrl.port,
84-
path: parsedUrl.path,
104+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
105+
path: parsedUrl.pathname + parsedUrl.search,
85106
method: 'GET',
86107
headers: headers
87108
};
@@ -174,28 +195,32 @@ const Server = {
174195
process.versions != null &&
175196
process.versions.node != null;
176197
198+
const processedBody = this._processBodyForContentType(body, contentType);
199+
if (processedBody !== body) {
200+
Server.Logger.Log(\`[TRANSFORM] Converted JSON to URL-encoded: \${processedBody}\`);
201+
}
202+
177203
if (isNodeJs) {
178204
Server.Logger.Log(\`[NODE.JS] Making actual POST request to: \${url}\`);
179205
180206
try {
181207
const https = require('https');
182208
const http = require('http');
183-
const urlLib = require('url');
184209
185-
const parsedUrl = urlLib.parse(url);
210+
const parsedUrl = new URL(url);
186211
const protocol = parsedUrl.protocol === 'https:' ? https : http;
187212
188213
return new Promise((resolve, reject) => {
189214
const requestHeaders = {
190215
...headers,
191216
'Content-Type': contentType,
192-
'Content-Length': Buffer.byteLength(body || '')
217+
'Content-Length': Buffer.byteLength(processedBody || '')
193218
};
194219
195220
const options = {
196221
hostname: parsedUrl.hostname,
197-
port: parsedUrl.port,
198-
path: parsedUrl.path,
222+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
223+
path: parsedUrl.pathname + parsedUrl.search,
199224
method: 'POST',
200225
headers: requestHeaders
201226
};
@@ -241,8 +266,8 @@ const Server = {
241266
resolve(JSON.stringify(errorResponse));
242267
});
243268
244-
if (body) {
245-
req.write(body);
269+
if (processedBody) {
270+
req.write(processedBody);
246271
}
247272
req.end();
248273
});
@@ -287,28 +312,32 @@ const Server = {
287312
process.versions != null &&
288313
process.versions.node != null;
289314
315+
const processedBody = this._processBodyForContentType(body, contentType);
316+
if (processedBody !== body) {
317+
Server.Logger.Log(\`[TRANSFORM] Converted JSON to URL-encoded: \${processedBody}\`);
318+
}
319+
290320
if (isNodeJs) {
291321
Server.Logger.Log(\`[NODE.JS] Making actual PATCH request to: \${url}\`);
292322
293323
try {
294324
const https = require('https');
295325
const http = require('http');
296-
const urlLib = require('url');
297326
298-
const parsedUrl = urlLib.parse(url);
327+
const parsedUrl = new URL(url);
299328
const protocol = parsedUrl.protocol === 'https:' ? https : http;
300329
301330
return new Promise((resolve, reject) => {
302331
const requestHeaders = {
303332
...headers,
304333
'Content-Type': contentType,
305-
'Content-Length': Buffer.byteLength(body || '')
334+
'Content-Length': Buffer.byteLength(processedBody || '')
306335
};
307336
308337
const options = {
309338
hostname: parsedUrl.hostname,
310-
port: parsedUrl.port,
311-
path: parsedUrl.path,
339+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
340+
path: parsedUrl.pathname + parsedUrl.search,
312341
method: 'PATCH',
313342
headers: requestHeaders
314343
};
@@ -354,8 +383,8 @@ const Server = {
354383
resolve(JSON.stringify(errorResponse));
355384
});
356385
357-
if (body) {
358-
req.write(body);
386+
if (processedBody) {
387+
req.write(processedBody);
359388
}
360389
req.end();
361390
});
@@ -400,28 +429,32 @@ const Server = {
400429
process.versions != null &&
401430
process.versions.node != null;
402431
432+
const processedBody = this._processBodyForContentType(body, contentType);
433+
if (processedBody !== body) {
434+
Server.Logger.Log(\`[TRANSFORM] Converted JSON to URL-encoded: \${processedBody}\`);
435+
}
436+
403437
if (isNodeJs) {
404438
Server.Logger.Log(\`[NODE.JS] Making actual PUT request to: \${url}\`);
405439
406440
try {
407441
const https = require('https');
408442
const http = require('http');
409-
const urlLib = require('url');
410443
411-
const parsedUrl = urlLib.parse(url);
444+
const parsedUrl = new URL(url);
412445
const protocol = parsedUrl.protocol === 'https:' ? https : http;
413446
414447
return new Promise((resolve, reject) => {
415448
const requestHeaders = {
416449
...headers,
417450
'Content-Type': contentType,
418-
'Content-Length': Buffer.byteLength(body || '')
451+
'Content-Length': Buffer.byteLength(processedBody || '')
419452
};
420453
421454
const options = {
422455
hostname: parsedUrl.hostname,
423-
port: parsedUrl.port,
424-
path: parsedUrl.path,
456+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
457+
path: parsedUrl.pathname + parsedUrl.search,
425458
method: 'PUT',
426459
headers: requestHeaders
427460
};
@@ -467,8 +500,8 @@ const Server = {
467500
resolve(JSON.stringify(errorResponse));
468501
});
469502
470-
if (body) {
471-
req.write(body);
503+
if (processedBody) {
504+
req.write(processedBody);
472505
}
473506
req.end();
474507
});
@@ -505,7 +538,7 @@ const Server = {
505538
}
506539
},
507540
508-
DeleteAsync: async function (url, headers = {}, contentType = "application/json") {
541+
DeleteAsync: async function (url, headers = {}) {
509542
Server.Logger.Log(\`[MOCK] HttpClient.DeleteAsync called with URL: \${url}\`);
510543
511544
const isNodeJs = typeof process !== 'undefined' &&
@@ -518,16 +551,15 @@ const Server = {
518551
try {
519552
const https = require('https');
520553
const http = require('http');
521-
const urlLib = require('url');
522554
523-
const parsedUrl = urlLib.parse(url);
555+
const parsedUrl = new URL(url);
524556
const protocol = parsedUrl.protocol === 'https:' ? https : http;
525557
526558
return new Promise((resolve, reject) => {
527559
const options = {
528560
hostname: parsedUrl.hostname,
529-
port: parsedUrl.port,
530-
path: parsedUrl.path,
561+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
562+
path: parsedUrl.pathname + parsedUrl.search,
531563
method: 'DELETE',
532564
headers: headers
533565
};

src/debugger/server-logic/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
export {
77
activateServerLogicDebugger,
88
createServerLogicDebugConfig,
9-
ensureRuntimeLoader
9+
ensureRuntimeLoader,
10+
isServerLogicDebuggingEnabled
1011
} from './ServerLogicDebugger';
1112
export {
1213
ServerLogicDebugProvider,

0 commit comments

Comments
 (0)