diff --git a/packages/insomnia/src/main/network/curl.ts b/packages/insomnia/src/main/network/curl.ts index 53d9737d1..81efc8e3d 100644 --- a/packages/insomnia/src/main/network/curl.ts +++ b/packages/insomnia/src/main/network/curl.ts @@ -18,6 +18,7 @@ import { urlMatchesCertHost } from '../../network/url-matches-cert-host'; import { invariant } from '../../utils/invariant'; import { setDefaultProtocol } from '../../utils/url/protocol'; import { createConfiguredCurlInstance } from './libcurl-promise'; +import { parseHeaderStrings } from './parse-header-strings'; export interface CurlConnection extends Curl { _id: string; @@ -138,7 +139,6 @@ const openCurlConnection = async ( const clientCertificates = await models.clientCertificate.findByParentId(options.workspaceId); const filteredClientCertificates = clientCertificates.filter(c => !c.disabled && urlMatchesCertHost(setDefaultProtocol(c.host, 'https:'), options.url)); const { curl, debugTimeline } = createConfiguredCurlInstance({ - // TODO: get cookies here req: { ...request, cookieJar: options.cookieJar, cookies: [] }, finalUrl: options.url, settings, @@ -146,33 +146,12 @@ const openCurlConnection = async ( certificates: filteredClientCertificates, }); debugTimeline.forEach(entry => timelineFileStreams.get(options.requestId)?.write(JSON.stringify(entry) + '\n')); - curl.enable(CurlFeature.StreamResponse); - curl.setOpt(Curl.option.DEBUGFUNCTION, (infoType, buffer) => { - const isSSLData = infoType === CurlInfoDebug.SslDataIn || infoType === CurlInfoDebug.SslDataOut; - const isEmpty = buffer.length === 0; - // Don't show cookie setting because this will display every domain in the jar - const isAddCookie = infoType === CurlInfoDebug.Text && buffer.toString('utf8').indexOf('Added cookie') === 0; - if (isSSLData || isEmpty || isAddCookie) { - return 0; - } - - // NOTE: resolves "Text" from CurlInfoDebug[CurlInfoDebug.Text] - const name = CurlInfoDebug[infoType] as keyof typeof CurlInfoDebug; - let timelineMessage; - const isRequestData = infoType === CurlInfoDebug.DataOut; - if (isRequestData) { - // Ignore large post data messages - const isLessThan10KB = buffer.length / 1024 < (settings.maxTimelineDataSizeKB || 1); - timelineMessage = isLessThan10KB ? buffer.toString('utf8') : `(${describeByteSize(buffer.length)} hidden)`; - } - const isResponseData = infoType === CurlInfoDebug.DataIn; - if (!isResponseData) { - const value = timelineMessage || buffer.toString('utf8'); - timelineFileStreams.get(options.requestId)?.write(JSON.stringify({ name, value, timestamp: Date.now() }) + '\n'); - } - return 0; - }); - curl.on('error', async (error, errorCode) => { + CurlConnections.set(options.requestId, curl); + CurlConnections.get(options.requestId)?.enable(CurlFeature.StreamResponse); + // TODO: add authHeader and request body? + const headerStrings = parseHeaderStrings({ req: request, finalUrl: options.url }); + CurlConnections.get(options.requestId)?.setOpt(Curl.option.HTTPHEADER, headerStrings); + CurlConnections.get(options.requestId)?.on('error', async (error, errorCode) => { const errorEvent: CurlErrorEvent = { _id: uuidV4(), requestId: options.requestId, @@ -193,7 +172,35 @@ const openCurlConnection = async ( } }); - curl.on('stream', async (stream: Readable, _code: number, [headersWithStatus]: HeaderInfo[]) => { + CurlConnections.get(options.requestId)?.setOpt(Curl.option.DEBUGFUNCTION, (infoType, buffer) => { + const isSSLData = infoType === CurlInfoDebug.SslDataIn || infoType === CurlInfoDebug.SslDataOut; + const isEmpty = buffer.length === 0; + // Don't show cookie setting because this will display every domain in the jar + const isAddCookie = infoType === CurlInfoDebug.Text && buffer.toString('utf8').indexOf('Added cookie') === 0; + if (isSSLData || isEmpty || isAddCookie) { + return 0; + } + + // NOTE: resolves "Text" from CurlInfoDebug[CurlInfoDebug.Text] + let name = CurlInfoDebug[infoType] as keyof typeof CurlInfoDebug; + let timelineMessage; + const isRequestData = infoType === CurlInfoDebug.DataOut; + if (isRequestData) { + // Ignore large post data messages + const isLessThan10KB = buffer.length / 1024 < (settings.maxTimelineDataSizeKB || 1); + timelineMessage = isLessThan10KB ? buffer.toString('utf8') : `(${describeByteSize(buffer.length)} hidden)`; + } + const isResponseData = infoType === CurlInfoDebug.DataIn; + if (isResponseData) { + timelineMessage = `Received ${describeByteSize(buffer.length)} chunk`; + name = 'Text'; + } + const value = timelineMessage || buffer.toString('utf8'); + timelineFileStreams.get(options.requestId)?.write(JSON.stringify({ name, value, timestamp: Date.now() }) + '\n'); + return 0; + }); + + CurlConnections.get(options.requestId)?.on('stream', async (stream: Readable, _code: number, [headersWithStatus]: HeaderInfo[]) => { event.sender.send(readyStateChannel, true); const { timeline, responseHeaders, statusCode, statusMessage, httpVersion } = parseHeadersAndBuildTimeline(options.url, headersWithStatus); @@ -233,10 +240,7 @@ const openCurlConnection = async ( } timeline.map(t => timelineFileStreams.get(options.requestId)?.write(JSON.stringify(t) + '\n')); - // we are going to write the response stream to this file - const writableStream = eventLogFileStreams.get(request._id); - // two ways to go here - invariant(writableStream, 'writableStream should be defined'); + invariant(eventLogFileStreams.get(request._id), 'writableStream should be defined'); for await (const chunk of stream) { const messageEvent: CurlMessageEvent = { _id: uuidV4(), @@ -254,7 +258,6 @@ const openCurlConnection = async ( event.sender.send(readyStateChannel, false); }); curl.perform(); - CurlConnections.set(options.requestId, curl); } catch (e) { console.error('unhandled error:', e); diff --git a/packages/insomnia/src/main/network/libcurl-promise.ts b/packages/insomnia/src/main/network/libcurl-promise.ts index 6f16a8fc0..424d45211 100644 --- a/packages/insomnia/src/main/network/libcurl-promise.ts +++ b/packages/insomnia/src/main/network/libcurl-promise.ts @@ -122,8 +122,8 @@ export const curlRequest = (options: CurlRequestOptions) => new Promise new Promise { const isSSLData = infoType === CurlInfoDebug.SslDataIn || infoType === CurlInfoDebug.SslDataOut; const isEmpty = buffer.length === 0; @@ -193,7 +193,6 @@ export const curlRequest = (options: CurlRequestOptions) => new Promise