// @flow import type { Request } from '../../models/request'; import type { Response } from '../../models/response'; import * as React from 'react'; import autobind from 'autobind-decorator'; import fs from 'fs'; import mime from 'mime-types'; import { remote } from 'electron'; import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; import SizeTag from './tags/size-tag'; import StatusTag from './tags/status-tag'; import TimeTag from './tags/time-tag'; import Button from './base/button'; import PreviewModeDropdown from './dropdowns/preview-mode-dropdown'; import ResponseViewer from './viewers/response-viewer'; import ResponseHistoryDropdown from './dropdowns/response-history-dropdown'; import ResponseTimer from './response-timer'; import ResponseTimelineViewer from './viewers/response-timeline-viewer'; import ResponseHeadersViewer from './viewers/response-headers-viewer'; import ResponseCookiesViewer from './viewers/response-cookies-viewer'; import * as models from '../../models'; import { PREVIEW_MODE_SOURCE } from '../../common/constants'; import { getSetCookieHeaders } from '../../common/misc'; import { cancelCurrentRequest } from '../../network/network'; import Hotkey from './hotkey'; import ErrorBoundary from './error-boundary'; import type { HotKeyRegistry } from '../../common/hotkeys'; import { hotKeyRefs } from '../../common/hotkeys'; import type { RequestVersion } from '../../models/request-version'; import { showError } from '../components/modals/index'; import prettify from 'insomnia-prettify'; type Props = { // Functions handleSetFilter: Function, showCookiesModal: Function, handleSetPreviewMode: Function, handleSetActiveResponse: Function, handleDeleteResponses: Function, handleDeleteResponse: Function, handleShowRequestSettings: Function, // Required previewMode: string, filter: string, filterHistory: Array, editorFontSize: number, editorIndentSize: number, editorKeyMap: string, editorLineWrapping: boolean, loadStartTime: number, responses: Array, hotKeyRegistry: HotKeyRegistry, // Other requestVersions: Array, request: ?Request, response: ?Response, }; @autobind class ResponsePane extends React.PureComponent { _responseViewer: any; _setResponseViewerRef(n: any) { this._responseViewer = n; } _handleGetResponseBody(): Buffer | null { if (!this.props.response) { return null; } return models.response.getBodyBuffer(this.props.response); } async _handleDownloadResponseBody() { const { response, request } = this.props; if (!response || !request) { // Should never happen console.warn('No response to download'); return; } const { contentType } = response; const extension = mime.extension(contentType) || 'unknown'; const options = { title: 'Save Response Body', buttonLabel: 'Save', defaultPath: `${request.name.replace(/ +/g, '_')}-${Date.now()}.${extension}`, }; remote.dialog.showSaveDialog(options, outputPath => { if (!outputPath) { return; } const readStream = models.response.getBodyStream(response); let dataBuffers = []; if (readStream) { readStream.on('data', data => { dataBuffers.push(data); }); readStream.on('end', () => { const to = fs.createWriteStream(outputPath); if (extension === 'json') { dataBuffers = prettify.json(dataBuffers); } to.write(dataBuffers); to.on('error', err => { showError({ title: 'Save Failed', message: 'Failed to save response body', error: err, }); }); }); } }); } async _handleDownloadFullResponseBody() { const { response, request } = this.props; if (!response || !request) { // Should never happen console.warn('No response to download'); return; } const timeline = await models.response.getTimeline(response); const headers = timeline .filter(v => v.name === 'HEADER_IN') .map(v => v.value) .join(''); const options = { title: 'Save Full Response', buttonLabel: 'Save', defaultPath: `${request.name.replace(/ +/g, '_')}-${Date.now()}.txt`, }; remote.dialog.showSaveDialog(options, filename => { if (!filename) { return; } const readStream = models.response.getBodyStream(response); if (readStream) { const to = fs.createWriteStream(filename); to.write(headers); readStream.pipe(to); to.on('error', err => { console.warn('Failed to save full response', err); }); } }); } _handleTabSelect(index: number, lastIndex: number) { if (this._responseViewer != null && index === 0 && index !== lastIndex) { // Fix for CodeMirror editor not updating its content. // Refresh must be called when the editor is visible, // so use nextTick to give time for it to be visible. process.nextTick(() => { this._responseViewer.refresh(); }); } } render() { const { request, responses, requestVersions, response, previewMode, handleShowRequestSettings, handleSetPreviewMode, handleSetActiveResponse, handleDeleteResponses, handleDeleteResponse, handleSetFilter, loadStartTime, editorLineWrapping, editorFontSize, editorIndentSize, editorKeyMap, filter, filterHistory, showCookiesModal, hotKeyRegistry, } = this.props; const paneClasses = 'response-pane theme--pane pane'; const paneHeaderClasses = 'pane__header theme--pane__header'; const paneBodyClasses = 'pane__body theme--pane__body'; if (!request) { return (
); } if (!response) { return (
Send Request
Focus Url Bar
Manage Cookies
Edit Environments
); } const cookieHeaders = getSetCookieHeaders(response.headers); return (
{!response ? null : (
)}
); } } export default ResponsePane;