Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/insomnia-smoke-test/fixtures/files/rawfile.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
raw file content
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from '@playwright/test';

import { loadFixture } from '../../playwright/paths';
import { getFixturePath, loadFixture } from '../../playwright/paths';
import { test } from '../../playwright/test';;

test.describe('pre-request features tests', async () => {
Expand Down Expand Up @@ -30,7 +30,7 @@ test.describe('pre-request features tests', async () => {
// but it is rewritten here
insomnia.baseEnvironment.set('preDefinedValue', 'fromScript');
// "customValue" is already defined in the folder environment.
// folder version will override the following wone
// folder version will override the following one
insomnia.baseEnvironment.set('customValue', 'fromScript');
`,
body: `{
Expand Down Expand Up @@ -198,16 +198,17 @@ test.describe('pre-request features tests', async () => {
mode: 'raw',
raw: 'rawContent',
});
insomnia.request.auth.update(
{
type: 'bearer',
bearer: [
{key: 'token', value: 'tokenValue'},
],
},
'bearer'
);
// insomnia.request.proxy.update({}); // TODO: enable proxy and test it
// insomnia.request.auth.update(
// {
// type: 'bearer',
// bearer: [
// {key: 'token', value: 'tokenValue'},
// ],
// },
// 'bearer'
// );
// TODO: enable proxy and test it
// insomnia.request.proxy.update({});
// insomnia.request.certificate.update({});
`,
body: '{}',
Expand All @@ -217,6 +218,112 @@ test.describe('pre-request features tests', async () => {
expect(bodyJson.data).toEqual('rawContent');
},
},
{
name: 'sendRequest every content type',
preReqScript: `
const rawReq = {
url: 'http://127.0.0.1:4010/echo',
method: 'POST',
header: {
'Content-Type': 'text/plain',
},
body: {
mode: 'raw',
raw: 'rawContent',
},
};
const urlencodedReq = {
url: 'http://127.0.0.1:4010/echo',
method: 'POST',
header: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
mode: 'urlencoded',
urlencoded: [
{ key: 'k1', value: 'v1' },
{ key: 'k2', value: 'v2' },
],
},
};
const gqlReq = {
url: 'http://127.0.0.1:4010/echo',
method: 'POST',
header: {
'Content-Type': 'application/graphql',
},
body: {
mode: 'graphql',
graphql: {
query: 'query',
operationName: 'operation',
variables: 'var',
},
},
};
const fileReq = {
url: 'http://127.0.0.1:4010/echo',
method: 'POST',
header: {
'Content-Type': 'application/octet-stream',
},
body: {
mode: 'file',
file: "${getFixturePath('files/rawfile.txt')}",
},
};
const formdataReq = {
url: 'http://127.0.0.1:4010/echo',
method: 'POST',
header: {
// TODO: try to understand why this breaks the test
// 'Content-Type': 'multipart/form-data',
},
body: {
mode: 'formdata',
formdata: [
{ key: 'k1', type: 'text', value: 'v1' },
{ key: 'k2', type: 'file', value: "${getFixturePath('files/rawfile.txt')}" },
],
},
};
const promises = [rawReq, urlencodedReq, gqlReq, fileReq, formdataReq].map(req => {
return new Promise((resolve, reject) => {
insomnia.sendRequest(
req,
(err, resp) => {
if (err != null) {
reject(err);
} else {
resolve(resp);
}
}
);
});
});
// send request
const resps = await Promise.all(promises);
// set envs
insomnia.environment.set('rawBody', resps[0].body);
insomnia.environment.set('urlencodedBody', resps[1].body);
insomnia.environment.set('gqlBody', resps[2].body);
insomnia.environment.set('fileBody', resps[3].body);
insomnia.environment.set('formdataBody', resps[4].body);
`,
body: '{ "rawBody": {{ _.rawBody }}, "urlencodedBody": {{ _.urlencodedBody }}, "gqlBody": {{ _.gqlBody }}, "fileBody": {{ _.fileBody }}, "formdataBody": {{ _.formdataBody }} }',
customVerify: (bodyJson: any) => {
const reqBodyJsons = JSON.parse(bodyJson.data);
expect(reqBodyJsons.rawBody.data).toEqual('rawContent');
expect(reqBodyJsons.urlencodedBody.data).toEqual('k1=v1&k2=v2');
expect(JSON.parse(reqBodyJsons.gqlBody.data)).toEqual({
query: 'query',
operationName: 'operation',
variables: 'var',
});
expect(reqBodyJsons.fileBody.data).toEqual('raw file content');
expect(reqBodyJsons.formdataBody.data).toEqual('--X-INSOMNIA-BOUNDARY\r\nContent-Disposition: form-data; name=\"k1\"\r\n\r\nv1\r\n--X-INSOMNIA-BOUNDARY\r\nContent-Disposition: form-data; name=\"k2\"; filename=\"rawfile.txt\"\r\nContent-Type: text/plain\r\n\r\nraw file content\r\n--X-INSOMNIA-BOUNDARY--\r\n');
},
},
];

for (let i = 0; i < testCases.length; i++) {
Expand Down Expand Up @@ -258,7 +365,6 @@ test.describe('pre-request features tests', async () => {
expect(rows.length).toBeGreaterThan(0);

const bodyJson = JSON.parse(rows.join(' '));

if (tc.expectedBody) {
expect(JSON.parse(bodyJson.data)).toEqual(tc.expectedBody);
}
Expand Down
10 changes: 4 additions & 6 deletions packages/insomnia/src/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
/// <reference types="vite/client" />
import type { MainBridgeAPI } from './main/ipc/main';
import type { HiddenBrowserWindowToMainBridgeAPI } from './hidden-window-preload';
import type { RendererToMainBridgeAPI } from './main/ipc/main';

declare global {
interface Window {
main: MainBridgeAPI;
main: RendererToMainBridgeAPI;
bridge: HiddenBrowserWindowToMainBridgeAPI;
dialog: Pick<Electron.Dialog, 'showOpenDialog' | 'showSaveDialog'>;
app: Pick<Electron.App, 'getPath' | 'getAppPath'>;
shell: Pick<Electron.Shell, 'showItemInFolder'>;
clipboard: Pick<Electron.Clipboard, 'readText' | 'writeText' | 'clear'>;
bridge: {
requireInterceptor: (module: string) => any;
onmessage: (listener: (data: any, callback: (result: any) => void) => void) => void;
};
}
}

Expand Down
14 changes: 12 additions & 2 deletions packages/insomnia/src/hidden-window-preload.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';

import type { Compression } from './models/response';
import * as CollectionModule from './sdk/objects';
import { RequestContext } from './sdk/objects/interfaces';
import type { RequestContext } from './sdk/objects/interfaces';

const bridge: Window['bridge'] = {
export interface HiddenBrowserWindowToMainBridgeAPI {
requireInterceptor: (module: string) => any;
onmessage: (listener: (data: any, callback: (result: any) => void) => void) => void;
curlRequest: (options: any) => Promise<any>;
readCurlResponse: (options: { bodyPath: string; bodyCompression: Compression }) => Promise<{ body: string; error: string }>;
}
const bridge: HiddenBrowserWindowToMainBridgeAPI = {
onmessage: listener => {
const rendererListener = (event: IpcRendererEvent) => {
const [port] = event.ports;
Expand All @@ -24,6 +31,9 @@ const bridge: Window['bridge'] = {

throw Error(`no module is found for "${moduleName}"`);
},

curlRequest: options => ipcRenderer.invoke('curlRequest', options),
readCurlResponse: options => ipcRenderer.invoke('readCurlResponse', options),
};

if (process.contextIsolated) {
Expand Down
2 changes: 1 addition & 1 deletion packages/insomnia/src/main/ipc/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { cancelCurlRequest, curlRequest } from '../network/libcurl-promise';
import { WebSocketBridgeAPI } from '../network/websocket';
import { gRPCBridgeAPI } from './grpc';

export interface MainBridgeAPI {
export interface RendererToMainBridgeAPI {
loginStateChange: () => void;
openInBrowser: (url: string) => void;
restart: () => void;
Expand Down
18 changes: 18 additions & 0 deletions packages/insomnia/src/main/network/curl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { CookieJar } from '../../models/cookie-jar';
import { Environment } from '../../models/environment';
import { RequestAuthentication, RequestHeader } from '../../models/request';
import { Response } from '../../models/response';
import { Compression, getBodyBuffer } from '../../models/response';
import { addSetCookiesToToughCookieJar } from '../../network/set-cookie-util';
import { urlMatchesCertHost } from '../../network/url-matches-cert-host';
import { invariant } from '../../utils/invariant';
Expand Down Expand Up @@ -353,6 +354,7 @@ export interface CurlBridgeAPI {
findMany: typeof findMany;
};
}

export const registerCurlHandlers = () => {
ipcMain.handle('curl.open', openCurlConnection);
ipcMain.on('curl.close', closeCurlConnection);
Expand All @@ -361,4 +363,20 @@ export const registerCurlHandlers = () => {
ipcMain.handle('curl.event.findMany', (_, options: Parameters<typeof findMany>[0]) => findMany(options));
};

ipcMain.handle('readCurlResponse', async (_, options: { bodyPath?: string; bodyCompression?: Compression }) => {
const readFailureMsg = '[main/curlBridgeAPI] failed to read response body message';
const bodyBufferOrErrMsg = getBodyBuffer(options, readFailureMsg);
// TODO(jackkav): simplify the fail msg and reuse in other getBodyBuffer renderer calls
if (!bodyBufferOrErrMsg) {
return { body: '', error: readFailureMsg };
} else if (typeof bodyBufferOrErrMsg === 'string') {
if (bodyBufferOrErrMsg === readFailureMsg) {
return { body: '', error: readFailureMsg };
}
return { body: '', error: `unknown error in loading response body: ${bodyBufferOrErrMsg}` };
}

return { body: bodyBufferOrErrMsg.toString('utf8'), error: '' };
});

electron.app.on('window-all-closed', closeAllCurlConnections);
2 changes: 1 addition & 1 deletion packages/insomnia/src/models/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface ResponseHeader {
value: string;
}

type Compression = 'zip' | null | '__NEEDS_MIGRATION__' | undefined;
export type Compression = 'zip' | null | '__NEEDS_MIGRATION__' | undefined;

export interface BaseResponse {
environmentId: string | null;
Expand Down
3 changes: 2 additions & 1 deletion packages/insomnia/src/network/cancellation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Request } from '../models/request';
import { RequestContext } from '../sdk/objects/interfaces';

const cancelRequestFunctionMap = new Map<string, () => void>();

export async function cancelRequestById(requestId: string) {
const cancel = cancelRequestFunctionMap.get(requestId);
if (cancel) {
Expand Down Expand Up @@ -65,7 +66,7 @@ export const cancellableCurlRequest = async (requestOptions: CurlRequestOptions)
}
};

const cancellablePromise = ({ signal, fn }: { signal: AbortSignal; fn: Promise<any> }) => {
export const cancellablePromise = ({ signal, fn }: { signal: AbortSignal; fn: Promise<any> }) => {
if (signal?.aborted) {
return Promise.reject(new DOMException('Aborted', 'AbortError'));
}
Expand Down
9 changes: 8 additions & 1 deletion packages/insomnia/src/network/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const tryToExecutePreRequestScript = async (
timelinePath: string,
responseId: string,
baseEnvironment: Environment,
clientCertificates: ClientCertificate[],
) => {
if (!request.preRequestScript) {
return {
Expand Down Expand Up @@ -108,9 +109,15 @@ export const tryToExecutePreRequestScript = async (
// this is more deterministic and avoids that script accidently manipulates baseEnvironment instead of environment
environment: environment._id === baseEnvironment._id ? {} : (environment?.data || {}),
baseEnvironment: baseEnvironment?.data || {},
clientCertificates,
settings,
},
});
const output = await Promise.race([timeoutPromise, preRequestPromise]) as { request: Request; environment: Record<string, any>; baseEnvironment: Record<string, any> };
const output = await Promise.race([timeoutPromise, preRequestPromise]) as {
request: Request;
environment: Record<string, any>;
baseEnvironment: Record<string, any>;
};
console.log('[network] Pre-request script succeeded', output);

const envPropertyOrder = orderedJSON.parse(
Expand Down
22 changes: 22 additions & 0 deletions packages/insomnia/src/sdk/objects/insomnia.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import { ClientCertificate } from '../../models/client-certificate';
import { RequestBodyParameter, RequestHeader } from '../../models/request';
import { Settings } from '../../models/settings';
import { toPreRequestAuth } from './auth';
import { Environment, Variables } from './environments';
import { RequestContext } from './interfaces';
import { unsupportedError } from './properties';
import { Request as ScriptRequest, RequestBodyOptions, RequestOptions } from './request';
import { Response as ScriptResponse } from './response';
import { sendRequest } from './send-request';

export class InsomniaObject {
public environment: Environment;
public collectionVariables: Environment;
public baseEnvironment: Environment;
public variables: Variables;
public request: ScriptRequest;
private settings: Settings;
private clientCertificates: ClientCertificate[];

// TODO: follows will be enabled after Insomnia supports them
private _globals: Environment;
Expand All @@ -24,6 +30,8 @@ export class InsomniaObject {
baseEnvironment: Environment;
variables: Variables;
request: ScriptRequest;
settings: Settings;
clientCertificates: ClientCertificate[];
},
) {
this._globals = rawObj.globals;
Expand All @@ -33,6 +41,16 @@ export class InsomniaObject {
this._iterationData = rawObj.iterationData;
this.variables = rawObj.variables;
this.request = rawObj.request;
this.settings = rawObj.settings;
this.clientCertificates = rawObj.clientCertificates;
}

sendRequest(
request: string | ScriptRequest,
cb: (error?: string, response?: ScriptResponse) => void
) {
// TODO: hook to settings later
return sendRequest(request, cb, this.settings);
}

// TODO: remove this after enabled globals
Expand All @@ -53,6 +71,8 @@ export class InsomniaObject {
iterationData: this._iterationData.toObject(),
variables: this.variables.toObject(),
request: this.request,
settings: this.settings,
clientCertificates: this.clientCertificates,
};
};
}
Expand Down Expand Up @@ -114,6 +134,8 @@ export function initInsomniaObject(
iterationData,
variables,
request,
settings: rawObj.settings,
clientCertificates: rawObj.clientCertificates,
},
);
};
4 changes: 4 additions & 0 deletions packages/insomnia/src/sdk/objects/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ClientCertificate } from '../../models/client-certificate';
import type { Request } from '../../models/request';
import { Settings } from '../../models/settings';

export interface RequestContext {
request: Request;
Expand All @@ -9,4 +11,6 @@ export interface RequestContext {
globals?: object;
iterationData?: object;
timeout: number;
settings: Settings;
clientCertificates: ClientCertificate[];
}
Loading