Skip to content

Commit

Permalink
Add full explanations & improve UI for Send failures
Browse files Browse the repository at this point in the history
  • Loading branch information
pimterry committed Mar 11, 2024
1 parent ad73779 commit a018fee
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 179 deletions.
38 changes: 28 additions & 10 deletions src/components/send/response-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@ import { inject, observer } from "mobx-react";
import * as portals from 'react-reverse-portal';

import { HttpExchange } from "../../types";
import { logError } from "../../errors";

import { UiStore } from '../../model/ui/ui-store';
import { AccountStore } from '../../model/account/account-store';
import { SuccessfulExchange } from "../../model/http/exchange";
import { CompletedExchange, SuccessfulExchange } from "../../model/http/exchange";
import { RequestInput } from "../../model/send/send-request-model";
import { tagsToErrorType } from "../../model/http/error-types";

import { ContainerSizedEditor } from '../editor/base-editor';
import { HttpAbortedResponseCard } from '../view/http/http-aborted-card';

import { SendCardContainer } from './send-card-section';
import { PendingResponseStatusSection, ResponseStatusSection } from './sent-response-status';
import { FailedResponseStatusSection, PendingResponseStatusSection, ResponseStatusSection } from './sent-response-status';
import { PendingResponseHeaderSection, SentResponseHeaderSection } from './sent-response-headers';
import { SentResponseBodyCard } from './sent-response-body';

import { SentResponseError } from './sent-response-error';
@inject('uiStore')
@inject('accountStore')
@observer
Expand Down Expand Up @@ -44,7 +45,7 @@ export class ResponsePane extends React.Component<{
exchange.isSuccessfulExchange()
? this.renderSuccessfulResponse(exchange)
: exchange.isCompletedExchange()
? this.renderAbortedResponse(exchange)
? this.renderFailedResponse(exchange)
: this.renderInProgressResponse()
}
</SendCardContainer>;
Expand Down Expand Up @@ -75,11 +76,28 @@ export class ResponsePane extends React.Component<{

}

renderAbortedResponse(exchange: HttpExchange) {
return <HttpAbortedResponseCard
cardProps={this.cardProps.responseHeaders}
exchange={exchange}
/>;
renderFailedResponse(exchange: CompletedExchange) {
const { uiStore } = this.props;

const errorType = tagsToErrorType(exchange.tags);

if (!errorType) {
logError(`Sent response failed with no error tags: ${
JSON.stringify(exchange.tags)
} (${exchange.abortMessage})`);
}

return <>
<FailedResponseStatusSection
exchange={exchange}
errorType={errorType ?? 'unknown'}
theme={uiStore!.theme}
/>
<SentResponseError
errorType={errorType ?? 'unknown'}
errorMessage={exchange.abortMessage}
/>
</>;
}

renderInProgressResponse() {
Expand Down
102 changes: 102 additions & 0 deletions src/components/send/sent-response-error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import * as React from 'react';

import { styled } from '../../styles';
import { WarningIcon } from '../../icons';
import { unreachableCheck } from '../../util/error';
import { logError } from '../../errors';

import {
ErrorType,
wasNotForwarded,
wasServerIssue
} from '../../model/http/error-types';

import { SendCardSection } from './send-card-section';
import { ContentMonoValue } from '../common/text-content';

const ExplanationBlock = styled.p`
margin-bottom: 10px;
line-height: 1.3;
`;

const FailureBlock = styled(ExplanationBlock)`
font-weight: bold;
`;

export const SentResponseError = (props: {
errorType: ErrorType,
errorMessage: string | undefined
}) => {
const { errorType, errorMessage } = props;

if (
!wasNotForwarded(errorType) &&
!wasServerIssue(errorType)
) {
logError(`Unexpected Send error type: ${errorType}`);
}

return <SendCardSection
ariaLabel='HTTP failure section'
collapsed={false}
>
<header>
<h1>
Request Failure
</h1>
</header>
<FailureBlock>
<WarningIcon /> {
wasNotForwarded(errorType)
? 'This request was not sent successfully'
: wasServerIssue(errorType)
? 'This response was not received successfully'
: `The request failed because of an unexpected error: ${errorType}`
} <WarningIcon />
</FailureBlock>
{
wasNotForwarded(errorType)
? <ExplanationBlock>
The upstream server {
errorType === 'wrong-host'
? 'responded with an HTTPS certificate for the wrong hostname'
: errorType === 'expired'
? 'has an expired HTTPS certificate'
: errorType === 'not-yet-valid'
? 'has an HTTPS certificate with a start date in the future'
: errorType === 'untrusted'
? 'has an untrusted HTTPS certificate'
: errorType === 'tls-error'
? 'failed to complete a TLS handshake'
: errorType === 'host-unreachable'
? 'was not reachable on your network connection'
: errorType === 'host-not-found' || errorType === 'dns-error'
? 'hostname could be not found'
: errorType === 'connection-refused'
? 'refused the connection'
: unreachableCheck(errorType)
}, so HTTP Toolkit did not send the request.
</ExplanationBlock>
: wasServerIssue(errorType)
? <ExplanationBlock>
The upstream request failed because {
errorType === 'connection-reset'
? 'the connection to the server was reset'
: errorType === 'server-unparseable'
? 'the response from the server was unparseable'
: errorType === 'server-timeout'
? 'of a timeout waiting for a response from the server'
: unreachableCheck(errorType)
}.
</ExplanationBlock>
: <ExplanationBlock>
It's not clear what's gone wrong here, but for some reason HTTP Toolkit
couldn't successfully and/or securely complete this request. This might be an
intermittent issue, and may be resolved by retrying the request.
</ExplanationBlock>
}
{ !!errorMessage &&
<ContentMonoValue>{ errorMessage }</ContentMonoValue>
}
</SendCardSection>
}
28 changes: 26 additions & 2 deletions src/components/send/sent-response-status.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as _ from 'lodash';
import * as React from 'react';

import { Theme, styled } from '../../styles';
import { getReadableSize } from '../../util/buffer';

import { getStatusColor } from '../../model/events/categorization';
import { getStatusMessage } from '../../model/http/http-docs';
import { getReadableSize } from '../../util/buffer';
import { SuccessfulExchange } from '../../model/http/exchange';
import { CompletedExchange, SuccessfulExchange } from '../../model/http/exchange';
import { ErrorType } from '../../model/http/error-types';

import { SendCardSection } from './send-card-section';
import { Pill } from '../common/pill';
Expand Down Expand Up @@ -69,4 +71,26 @@ export const PendingResponseStatusSection = (props: {
</Pill>
</header>
</ResponseStatusSectionCard>;
}

export const FailedResponseStatusSection = (props: {
exchange: CompletedExchange,
errorType: ErrorType
theme: Theme
}) => {
return <ResponseStatusSectionCard
className='ignores-expanded' // This always shows, even if something is expanded
ariaLabel='Response status section'
collapsed={false}
headerAlignment='left'
>
<header>
<Pill
color={getStatusColor('aborted', props.theme)}
>
Failed: { _.startCase(props.errorType) }
</Pill>
<DurationPill timingEvents={props.exchange.timingEvents} />
</header>
</ResponseStatusSectionCard>;
}
3 changes: 2 additions & 1 deletion src/components/view/http/http-details-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { buildRuleFromRequest } from '../../../model/rules/rule-creation';
import { findItem } from '../../../model/rules/rules-structure';
import { HtkMockRule, getRulePartKey } from '../../../model/rules/rules';
import { WebSocketStream } from '../../../model/websockets/websocket-stream';
import { tagsToErrorType } from '../../../model/http/error-types';

import { PaneOuterContainer, PaneScrollContainer } from '../view-details-pane';
import { StreamMessageListCard } from '../stream-message-list-card';
Expand All @@ -29,7 +30,7 @@ import { HttpAbortedResponseCard } from './http-aborted-card';
import { HttpPerformanceCard } from './http-performance-card';
import { HttpExportCard } from './http-export-card';
import { SelfSizedEditor } from '../../editor/base-editor';
import { HttpErrorHeader, tagsToErrorType } from './http-error-header';
import { HttpErrorHeader } from './http-error-header';
import { HttpDetailsFooter } from './http-details-footer';
import { HttpRequestBreakpointHeader, HttpResponseBreakpointHeader } from './http-breakpoint-header';
import { HttpBreakpointRequestCard } from './http-breakpoint-request-card';
Expand Down
Loading

0 comments on commit a018fee

Please sign in to comment.