import React, {PropTypes, PureComponent} from 'react'; import iconv from 'iconv-lite'; import autobind from 'autobind-decorator'; import {shell} from 'electron'; import {SimplePDF} from 'simple-react-pdf'; import CodeEditor from '../codemirror/code-editor'; import ResponseWebView from './response-webview'; import ResponseRaw from './response-raw'; import ResponseError from './response-error'; import {LARGE_RESPONSE_MB, PREVIEW_MODE_FRIENDLY, PREVIEW_MODE_RAW} from '../../../common/constants'; let alwaysShowLargeResponses = false; @autobind class ResponseViewer extends PureComponent { constructor (props) { super(props); this.state = { blockingBecauseTooLarge: false, bodyBuffer: null }; } _handleOpenLink (link) { shell.openExternal(link); } _handleDismissBlocker () { this.setState({blockingBecauseTooLarge: false}); } _handleDisableBlocker () { alwaysShowLargeResponses = true; this._handleDismissBlocker(); } _maybeLoadResponseBody (props) { // Block the response if it's too large const responseIsTooLarge = props.bytes > LARGE_RESPONSE_MB * 1024 * 1024; if (!alwaysShowLargeResponses && responseIsTooLarge) { this.setState({blockingBecauseTooLarge: true}); } else { this.setState({ blockingBecauseTooLarge: false, bodyBuffer: props.getBody() }); } } componentWillMount () { this._maybeLoadResponseBody(this.props); } componentWillReceiveProps (nextProps) { this._maybeLoadResponseBody(nextProps); } shouldComponentUpdate (nextProps, nextState) { for (let k of Object.keys(nextProps)) { const value = nextProps[k]; if (typeof value !== 'function' && this.props[k] !== value) { return true; } } for (let k of Object.keys(nextState)) { const value = nextState[k]; if (typeof value !== 'function' && this.state[k] !== value) { return true; } } return false; } render () { const { previewMode, filter, filterHistory, contentType, editorLineWrapping, editorFontSize, editorIndentSize, editorKeyMap, updateFilter, url, error } = this.props; const {bodyBuffer} = this.state; if (error) { return ( ); } const {blockingBecauseTooLarge} = this.state; if (blockingBecauseTooLarge) { return (

Response body over {LARGE_RESPONSE_MB}MB hidden to prevent unresponsiveness

{' '}

); } if (!bodyBuffer) { return (
Failed to read response body from filesystem
); } if (bodyBuffer.length === 0) { return (
No body returned for response
); } const ct = contentType.toLowerCase(); if (previewMode === PREVIEW_MODE_FRIENDLY && ct.indexOf('image/') === 0) { const justContentType = contentType.split(';')[0]; const base64Body = bodyBuffer.toString('base64'); return (
); } else if (previewMode === PREVIEW_MODE_FRIENDLY && ct.includes('html')) { const justContentType = contentType.split(';')[0]; const match = contentType.match(/charset=([\w-]+)/); const charset = (match && match.length >= 2) ? match[1] : 'utf-8'; return ( ); } else if (previewMode === PREVIEW_MODE_FRIENDLY && ct.indexOf('application/pdf') === 0) { const justContentType = contentType.split(';')[0]; const base64Body = bodyBuffer.toString('base64'); return (
); } else if (previewMode === PREVIEW_MODE_RAW) { const match = contentType.match(/charset=([\w-]+)/); const charset = (match && match.length >= 2) ? match[1] : 'utf-8'; return ( ); } else { // Show everything else as "source" const match = contentType.match(/charset=([\w-]+)/); const charset = (match && match.length >= 2) ? match[1] : 'utf-8'; const body = iconv.decode(bodyBuffer, charset); let mode = contentType; // Try to detect content-types if there isn't one if (!mode) { if (body.match(/^\s*<\?xml [^?]*\?>/)) { mode = 'application/xml'; } else { try { JSON.parse(body); mode = 'application/json'; } catch (e) { // Nothing } } } return ( ); } } } ResponseViewer.propTypes = { getBody: PropTypes.func.isRequired, previewMode: PropTypes.string.isRequired, filter: PropTypes.string.isRequired, filterHistory: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, editorFontSize: PropTypes.number.isRequired, editorIndentSize: PropTypes.number.isRequired, editorKeyMap: PropTypes.string.isRequired, editorLineWrapping: PropTypes.bool.isRequired, url: PropTypes.string.isRequired, bytes: PropTypes.number.isRequired, contentType: PropTypes.string.isRequired, // Optional updateFilter: PropTypes.func, error: PropTypes.string }; export default ResponseViewer;