Skip to content

Commit 7b99a67

Browse files
authored
Merge pull request #1010 from rust-lang/parse-responses
Parse the HTTP responses instead of assuming they are valid
2 parents ac0aeb9 + 04051ca commit 7b99a67

File tree

4 files changed

+38
-29
lines changed

4 files changed

+38
-29
lines changed

ui/frontend/actions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,13 @@ export const reExecuteWithBacktrace = (): ThunkAction => dispatch => {
150150

151151
type FetchArg = Parameters<typeof fetch>[0];
152152

153-
export function jsonGet(url: FetchArg) {
153+
export function jsonGet(url: FetchArg): Promise<unknown> {
154154
return fetchJson(url, {
155155
method: 'get',
156156
});
157157
}
158158

159-
export function jsonPost<T>(url: FetchArg, body: Record<string, any>): Promise<T> {
159+
export function jsonPost(url: FetchArg, body: Record<string, any>): Promise<unknown> {
160160
return fetchJson(url, {
161161
method: 'post',
162162
body: JSON.stringify(body),

ui/frontend/compileActions.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { AsyncThunk, createAsyncThunk } from '@reduxjs/toolkit';
2+
import * as z from 'zod';
23

34
import { SimpleThunkAction, adaptFetchError, jsonPost, routes } from './actions';
45
import { compileRequestPayloadSelector } from './selectors';
@@ -17,11 +18,12 @@ interface CompileRequestBody {
1718
processAssembly: string;
1819
}
1920

20-
interface CompileResponseBody {
21-
code: string;
22-
stdout: string;
23-
stderr: string;
24-
}
21+
const CompileResponseBody = z.object({
22+
code: z.string(),
23+
stdout: z.string(),
24+
stderr: z.string(),
25+
});
26+
type CompileResponseBody = z.infer<typeof CompileResponseBody>;
2527

2628
interface Props {
2729
sliceName: string;
@@ -34,9 +36,10 @@ interface CompileActions {
3436
}
3537

3638
export const makeCompileActions = ({ sliceName, target }: Props): CompileActions => {
37-
const action = createAsyncThunk(sliceName, async (payload: CompileRequestBody) =>
38-
adaptFetchError(() => jsonPost<CompileResponseBody>(routes.compile, payload)),
39-
);
39+
const action = createAsyncThunk(sliceName, async (payload: CompileRequestBody) => {
40+
const d = await adaptFetchError(() => jsonPost(routes.compile, payload));
41+
return CompileResponseBody.parseAsync(d);
42+
});
4043

4144
const performCompile = (): SimpleThunkAction => (dispatch, getState) => {
4245
const state = getState();

ui/frontend/reducers/output/execute.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,18 @@ export interface ExecuteRequestBody {
6767
backtrace: boolean;
6868
}
6969

70-
interface ExecuteResponseBody {
71-
success: boolean;
72-
exitDetail: string;
73-
stdout: string;
74-
stderr: string;
75-
}
70+
const ExecuteResponseBody = z.object({
71+
success: z.boolean(),
72+
exitDetail: z.string(),
73+
stdout: z.string(),
74+
stderr: z.string(),
75+
});
76+
type ExecuteResponseBody = z.infer<typeof ExecuteResponseBody>;
7677

77-
export const performExecute = createAsyncThunk(sliceName, async (payload: ExecuteRequestBody) =>
78-
adaptFetchError(() => jsonPost<ExecuteResponseBody>(routes.execute, payload)),
79-
);
78+
export const performExecute = createAsyncThunk(sliceName, async (payload: ExecuteRequestBody) => {
79+
const d = await adaptFetchError(() => jsonPost(routes.execute, payload));
80+
return ExecuteResponseBody.parseAsync(d);
81+
});
8082

8183
const prepareWithCurrentSequenceNumber = <P>(payload: P, sequenceNumber: number) => ({
8284
payload,

ui/frontend/reducers/output/gist.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Draft, PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit';
2+
import * as z from 'zod';
23

3-
import { jsonGet, jsonPost, routes } from '../../actions';
4+
import { adaptFetchError, jsonGet, jsonPost, routes } from '../../actions';
45
import { baseUrlSelector, codeSelector } from '../../selectors';
56
import RootState from '../../state';
67
import { Channel, Edition, Mode } from '../../types';
@@ -39,11 +40,12 @@ type PerformGistLoadProps = Pick<
3940
Exclude<keyof SuccessProps, 'url' | 'code' | 'stdout' | 'stderr'>
4041
>;
4142

42-
interface GistResponseBody {
43-
id: string;
44-
url: string;
45-
code: string;
46-
}
43+
const GistResponseBody = z.object({
44+
id: z.string(),
45+
url: z.string(),
46+
code: z.string(),
47+
});
48+
type GistResponseBody = z.infer<typeof GistResponseBody>;
4749

4850
export const performGistLoad = createAsyncThunk<
4951
SuccessProps,
@@ -55,8 +57,9 @@ export const performGistLoad = createAsyncThunk<
5557
const gistUrl = new URL(routes.meta.gistLoad, baseUrl);
5658
const u = new URL(id, gistUrl);
5759

58-
const gist = await jsonGet(u);
59-
return { channel, mode, edition, ...gist };
60+
const d = await adaptFetchError(() => jsonGet(u));
61+
const gist = await GistResponseBody.parseAsync(d);
62+
return { ...gist, channel, mode, edition, stdout: '', stderr: '' };
6063
});
6164

6265
export const performGistSave = createAsyncThunk<SuccessProps, void, { state: RootState }>(
@@ -71,8 +74,9 @@ export const performGistSave = createAsyncThunk<SuccessProps, void, { state: Roo
7174
},
7275
} = state;
7376

74-
const json = await jsonPost<GistResponseBody>(routes.meta.gistSave, { code });
75-
return { ...json, code, stdout, stderr, channel, mode, edition };
77+
const d = await adaptFetchError(() => jsonPost(routes.meta.gistSave, { code }));
78+
const gist = await GistResponseBody.parseAsync(d);
79+
return { ...gist, code, stdout, stderr, channel, mode, edition };
7680
},
7781
);
7882

0 commit comments

Comments
 (0)