mirror of
https://github.com/dstotijn/hetty.git
synced 2025-07-01 18:47:29 -04:00
Add support for intercepting HTTP responses
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
import CancelIcon from "@mui/icons-material/Cancel";
|
import CancelIcon from "@mui/icons-material/Cancel";
|
||||||
|
import DownloadIcon from "@mui/icons-material/Download";
|
||||||
import SendIcon from "@mui/icons-material/Send";
|
import SendIcon from "@mui/icons-material/Send";
|
||||||
import SettingsIcon from "@mui/icons-material/Settings";
|
import SettingsIcon from "@mui/icons-material/Settings";
|
||||||
import { Alert, Box, Button, CircularProgress, IconButton, Tooltip, Typography } from "@mui/material";
|
import { Alert, Box, Button, CircularProgress, IconButton, Tooltip, Typography } from "@mui/material";
|
||||||
@ -9,15 +10,17 @@ import { useInterceptedRequests } from "lib/InterceptedRequestsContext";
|
|||||||
import { KeyValuePair, sortKeyValuePairs } from "lib/components/KeyValuePair";
|
import { KeyValuePair, sortKeyValuePairs } from "lib/components/KeyValuePair";
|
||||||
import Link from "lib/components/Link";
|
import Link from "lib/components/Link";
|
||||||
import RequestTabs from "lib/components/RequestTabs";
|
import RequestTabs from "lib/components/RequestTabs";
|
||||||
import Response from "lib/components/Response";
|
import ResponseStatus from "lib/components/ResponseStatus";
|
||||||
import SplitPane from "lib/components/SplitPane";
|
import ResponseTabs from "lib/components/ResponseTabs";
|
||||||
import UrlBar, { HttpMethod, HttpProto, httpProtoMap } from "lib/components/UrlBar";
|
import UrlBar, { HttpMethod, HttpProto, httpProtoMap } from "lib/components/UrlBar";
|
||||||
import {
|
import {
|
||||||
HttpProtocol,
|
HttpProtocol,
|
||||||
HttpRequest,
|
HttpRequest,
|
||||||
useCancelRequestMutation,
|
useCancelRequestMutation,
|
||||||
|
useCancelResponseMutation,
|
||||||
useGetInterceptedRequestQuery,
|
useGetInterceptedRequestQuery,
|
||||||
useModifyRequestMutation,
|
useModifyRequestMutation,
|
||||||
|
useModifyResponseMutation,
|
||||||
} from "lib/graphql/generated";
|
} from "lib/graphql/generated";
|
||||||
import { queryParamsFromURL } from "lib/queryParamsFromURL";
|
import { queryParamsFromURL } from "lib/queryParamsFromURL";
|
||||||
import updateKeyPairItem from "lib/updateKeyPairItem";
|
import updateKeyPairItem from "lib/updateKeyPairItem";
|
||||||
@ -43,8 +46,10 @@ function EditRequest(): JSX.Element {
|
|||||||
const [url, setURL] = useState("");
|
const [url, setURL] = useState("");
|
||||||
const [proto, setProto] = useState(HttpProto.Http20);
|
const [proto, setProto] = useState(HttpProto.Http20);
|
||||||
const [queryParams, setQueryParams] = useState<KeyValuePair[]>([{ key: "", value: "" }]);
|
const [queryParams, setQueryParams] = useState<KeyValuePair[]>([{ key: "", value: "" }]);
|
||||||
const [headers, setHeaders] = useState<KeyValuePair[]>([{ key: "", value: "" }]);
|
const [reqHeaders, setReqHeaders] = useState<KeyValuePair[]>([{ key: "", value: "" }]);
|
||||||
const [body, setBody] = useState("");
|
const [resHeaders, setResHeaders] = useState<KeyValuePair[]>([{ key: "", value: "" }]);
|
||||||
|
const [reqBody, setReqBody] = useState("");
|
||||||
|
const [resBody, setResBody] = useState("");
|
||||||
|
|
||||||
const handleQueryParamChange = (key: string, value: string, idx: number) => {
|
const handleQueryParamChange = (key: string, value: string, idx: number) => {
|
||||||
setQueryParams((prev) => {
|
setQueryParams((prev) => {
|
||||||
@ -61,11 +66,18 @@ function EditRequest(): JSX.Element {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleHeaderChange = (key: string, value: string, idx: number) => {
|
const handleReqHeaderChange = (key: string, value: string, idx: number) => {
|
||||||
setHeaders((prev) => updateKeyPairItem(key, value, idx, prev));
|
setReqHeaders((prev) => updateKeyPairItem(key, value, idx, prev));
|
||||||
};
|
};
|
||||||
const handleHeaderDelete = (idx: number) => {
|
const handleReqHeaderDelete = (idx: number) => {
|
||||||
setHeaders((prev) => prev.slice(0, idx).concat(prev.slice(idx + 1, prev.length)));
|
setReqHeaders((prev) => prev.slice(0, idx).concat(prev.slice(idx + 1, prev.length)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleResHeaderChange = (key: string, value: string, idx: number) => {
|
||||||
|
setResHeaders((prev) => updateKeyPairItem(key, value, idx, prev));
|
||||||
|
};
|
||||||
|
const handleResHeaderDelete = (idx: number) => {
|
||||||
|
setResHeaders((prev) => prev.slice(0, idx).concat(prev.slice(idx + 1, prev.length)));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleURLChange = (url: string) => {
|
const handleURLChange = (url: string) => {
|
||||||
@ -93,38 +105,44 @@ function EditRequest(): JSX.Element {
|
|||||||
|
|
||||||
setURL(interceptedRequest.url);
|
setURL(interceptedRequest.url);
|
||||||
setMethod(interceptedRequest.method);
|
setMethod(interceptedRequest.method);
|
||||||
setBody(interceptedRequest.body || "");
|
setReqBody(interceptedRequest.body || "");
|
||||||
|
|
||||||
const newQueryParams = queryParamsFromURL(interceptedRequest.url);
|
const newQueryParams = queryParamsFromURL(interceptedRequest.url);
|
||||||
// Push empty row.
|
// Push empty row.
|
||||||
newQueryParams.push({ key: "", value: "" });
|
newQueryParams.push({ key: "", value: "" });
|
||||||
setQueryParams(newQueryParams);
|
setQueryParams(newQueryParams);
|
||||||
|
|
||||||
const newHeaders = sortKeyValuePairs(interceptedRequest.headers || []);
|
const newReqHeaders = sortKeyValuePairs(interceptedRequest.headers || []);
|
||||||
setHeaders([...newHeaders.map(({ key, value }) => ({ key, value })), { key: "", value: "" }]);
|
setReqHeaders([...newReqHeaders.map(({ key, value }) => ({ key, value })), { key: "", value: "" }]);
|
||||||
|
|
||||||
|
setResBody(interceptedRequest.response?.body || "");
|
||||||
|
const newResHeaders = sortKeyValuePairs(interceptedRequest.response?.headers || []);
|
||||||
|
setResHeaders([...newResHeaders.map(({ key, value }) => ({ key, value })), { key: "", value: "" }]);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const interceptedReq = reqId ? getReqResult?.data?.interceptedRequest : undefined;
|
const interceptedReq =
|
||||||
|
reqId && !getReqResult?.data?.interceptedRequest?.response ? getReqResult?.data?.interceptedRequest : undefined;
|
||||||
|
const interceptedRes = reqId ? getReqResult?.data?.interceptedRequest?.response : undefined;
|
||||||
|
|
||||||
const [modifyRequest, modifyResult] = useModifyRequestMutation();
|
const [modifyRequest, modifyReqResult] = useModifyRequestMutation();
|
||||||
const [cancelRequest, cancelResult] = useCancelRequestMutation();
|
const [cancelRequest, cancelReqResult] = useCancelRequestMutation();
|
||||||
|
|
||||||
|
const [modifyResponse, modifyResResult] = useModifyResponseMutation();
|
||||||
|
const [cancelResponse, cancelResResult] = useCancelResponseMutation();
|
||||||
|
|
||||||
const onActionCompleted = () => {
|
const onActionCompleted = () => {
|
||||||
setURL("");
|
setURL("");
|
||||||
setMethod(HttpMethod.Get);
|
setMethod(HttpMethod.Get);
|
||||||
setBody("");
|
setReqBody("");
|
||||||
setQueryParams([]);
|
setQueryParams([]);
|
||||||
setHeaders([]);
|
setReqHeaders([]);
|
||||||
router.replace(`/proxy/intercept`);
|
router.replace(`/proxy/intercept`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFormSubmit: React.FormEventHandler = (e) => {
|
const handleFormSubmit: React.FormEventHandler = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!interceptedReq) {
|
if (interceptedReq) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequest({
|
modifyRequest({
|
||||||
variables: {
|
variables: {
|
||||||
request: {
|
request: {
|
||||||
@ -132,8 +150,8 @@ function EditRequest(): JSX.Element {
|
|||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
proto: httpProtoMap.get(proto) || HttpProtocol.Http20,
|
proto: httpProtoMap.get(proto) || HttpProtocol.Http20,
|
||||||
headers: headers.filter((kv) => kv.key !== ""),
|
headers: reqHeaders.filter((kv) => kv.key !== ""),
|
||||||
body: body || undefined,
|
body: reqBody || undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update(cache) {
|
update(cache) {
|
||||||
@ -147,9 +165,35 @@ function EditRequest(): JSX.Element {
|
|||||||
},
|
},
|
||||||
onCompleted: onActionCompleted,
|
onCompleted: onActionCompleted,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interceptedRes) {
|
||||||
|
modifyResponse({
|
||||||
|
variables: {
|
||||||
|
response: {
|
||||||
|
requestID: interceptedRes.id,
|
||||||
|
proto: interceptedRes.proto, // TODO: Allow modifying
|
||||||
|
statusCode: interceptedRes.statusCode, // TODO: Allow modifying
|
||||||
|
statusReason: interceptedRes.statusReason, // TODO: Allow modifying
|
||||||
|
headers: resHeaders.filter((kv) => kv.key !== ""),
|
||||||
|
body: resBody || undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update(cache) {
|
||||||
|
cache.modify({
|
||||||
|
fields: {
|
||||||
|
interceptedRequests(existing: HttpRequest[], { readField }) {
|
||||||
|
return existing.filter((ref) => interceptedRes.id !== readField("id", ref));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onCompleted: onActionCompleted,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelClick = () => {
|
const handleReqCancelClick = () => {
|
||||||
if (!interceptedReq) {
|
if (!interceptedReq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -171,6 +215,28 @@ function EditRequest(): JSX.Element {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleResCancelClick = () => {
|
||||||
|
if (!interceptedRes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelResponse({
|
||||||
|
variables: {
|
||||||
|
requestID: interceptedRes.id,
|
||||||
|
},
|
||||||
|
update(cache) {
|
||||||
|
cache.modify({
|
||||||
|
fields: {
|
||||||
|
interceptedRequests(existing: HttpRequest[], { readField }) {
|
||||||
|
return existing.filter((ref) => interceptedRes.id !== readField("id", ref));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onCompleted: onActionCompleted,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box display="flex" flexDirection="column" height="100%" gap={2}>
|
<Box display="flex" flexDirection="column" height="100%" gap={2}>
|
||||||
<Box component="form" autoComplete="off" onSubmit={handleFormSubmit}>
|
<Box component="form" autoComplete="off" onSubmit={handleFormSubmit}>
|
||||||
@ -184,12 +250,14 @@ function EditRequest(): JSX.Element {
|
|||||||
onProtoChange={interceptedReq ? setProto : undefined}
|
onProtoChange={interceptedReq ? setProto : undefined}
|
||||||
sx={{ flex: "1 auto" }}
|
sx={{ flex: "1 auto" }}
|
||||||
/>
|
/>
|
||||||
|
{!interceptedRes && (
|
||||||
|
<>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
disableElevation
|
disableElevation
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!interceptedReq || modifyResult.loading || cancelResult.loading}
|
disabled={!interceptedReq || modifyReqResult.loading || cancelReqResult.loading}
|
||||||
startIcon={modifyResult.loading ? <CircularProgress size={22} /> : <SendIcon />}
|
startIcon={modifyReqResult.loading ? <CircularProgress size={22} /> : <SendIcon />}
|
||||||
>
|
>
|
||||||
Send
|
Send
|
||||||
</Button>
|
</Button>
|
||||||
@ -197,51 +265,99 @@ function EditRequest(): JSX.Element {
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
color="error"
|
color="error"
|
||||||
disableElevation
|
disableElevation
|
||||||
onClick={handleCancelClick}
|
onClick={handleReqCancelClick}
|
||||||
disabled={!interceptedReq || modifyResult.loading || cancelResult.loading}
|
disabled={!interceptedReq || modifyReqResult.loading || cancelReqResult.loading}
|
||||||
startIcon={cancelResult.loading ? <CircularProgress size={22} /> : <CancelIcon />}
|
startIcon={cancelReqResult.loading ? <CircularProgress size={22} /> : <CancelIcon />}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{interceptedRes && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
disableElevation
|
||||||
|
type="submit"
|
||||||
|
disabled={modifyResResult.loading || cancelResResult.loading}
|
||||||
|
endIcon={modifyResResult.loading ? <CircularProgress size={22} /> : <DownloadIcon />}
|
||||||
|
>
|
||||||
|
Receive
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="error"
|
||||||
|
disableElevation
|
||||||
|
onClick={handleResCancelClick}
|
||||||
|
disabled={modifyResResult.loading || cancelResResult.loading}
|
||||||
|
endIcon={cancelResResult.loading ? <CircularProgress size={22} /> : <CancelIcon />}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Tooltip title="Intercept settings">
|
<Tooltip title="Intercept settings">
|
||||||
<IconButton LinkComponent={Link} href="/settings#intercept">
|
<IconButton LinkComponent={Link} href="/settings#intercept">
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
{modifyResult.error && (
|
{modifyReqResult.error && (
|
||||||
<Alert severity="error" sx={{ mt: 1 }}>
|
<Alert severity="error" sx={{ mt: 1 }}>
|
||||||
{modifyResult.error.message}
|
{modifyReqResult.error.message}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
{cancelResult.error && (
|
{cancelReqResult.error && (
|
||||||
<Alert severity="error" sx={{ mt: 1 }}>
|
<Alert severity="error" sx={{ mt: 1 }}>
|
||||||
{cancelResult.error.message}
|
{cancelReqResult.error.message}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box flex="1 auto" position="relative">
|
<Box flex="1 auto" overflow="scroll">
|
||||||
<SplitPane split="vertical" size={"50%"}>
|
{interceptedReq && (
|
||||||
<Box sx={{ height: "100%", mr: 2, pb: 2, position: "relative" }}>
|
<Box sx={{ height: "100%", pb: 2 }}>
|
||||||
<Typography variant="overline" color="textSecondary" sx={{ position: "absolute", right: 0, mt: 1.2 }}>
|
<Typography variant="overline" color="textSecondary" sx={{ position: "absolute", right: 0, mt: 1.2 }}>
|
||||||
Request
|
Request
|
||||||
</Typography>
|
</Typography>
|
||||||
<RequestTabs
|
<RequestTabs
|
||||||
queryParams={interceptedReq ? queryParams : []}
|
queryParams={interceptedReq ? queryParams : []}
|
||||||
headers={interceptedReq ? headers : []}
|
headers={interceptedReq ? reqHeaders : []}
|
||||||
body={body}
|
body={reqBody}
|
||||||
onQueryParamChange={interceptedReq ? handleQueryParamChange : undefined}
|
onQueryParamChange={interceptedReq ? handleQueryParamChange : undefined}
|
||||||
onQueryParamDelete={interceptedReq ? handleQueryParamDelete : undefined}
|
onQueryParamDelete={interceptedReq ? handleQueryParamDelete : undefined}
|
||||||
onHeaderChange={interceptedReq ? handleHeaderChange : undefined}
|
onHeaderChange={interceptedReq ? handleReqHeaderChange : undefined}
|
||||||
onHeaderDelete={interceptedReq ? handleHeaderDelete : undefined}
|
onHeaderDelete={interceptedReq ? handleReqHeaderDelete : undefined}
|
||||||
onBodyChange={interceptedReq ? setBody : undefined}
|
onBodyChange={interceptedReq ? setReqBody : undefined}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ height: "100%", position: "relative", ml: 2, pb: 2 }}>
|
)}
|
||||||
<Response response={null} />
|
{interceptedRes && (
|
||||||
|
<Box sx={{ height: "100%", pb: 2 }}>
|
||||||
|
<Box sx={{ position: "absolute", right: 0, mt: 1.4 }}>
|
||||||
|
<Typography variant="overline" color="textSecondary" sx={{ float: "right", ml: 3 }}>
|
||||||
|
Response
|
||||||
|
</Typography>
|
||||||
|
{interceptedRes && (
|
||||||
|
<Box sx={{ float: "right", mt: 0.2 }}>
|
||||||
|
<ResponseStatus
|
||||||
|
proto={interceptedRes.proto}
|
||||||
|
statusCode={interceptedRes.statusCode}
|
||||||
|
statusReason={interceptedRes.statusReason}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</SplitPane>
|
)}
|
||||||
|
</Box>
|
||||||
|
<ResponseTabs
|
||||||
|
headers={interceptedRes ? resHeaders : []}
|
||||||
|
body={resBody}
|
||||||
|
onHeaderChange={interceptedRes ? handleResHeaderChange : undefined}
|
||||||
|
onHeaderDelete={interceptedRes ? handleResHeaderDelete : undefined}
|
||||||
|
onBodyChange={interceptedRes ? setResBody : undefined}
|
||||||
|
hasResponse={interceptedRes !== undefined && interceptedRes !== null}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
mutation CancelResponse($requestID: ID!) {
|
||||||
|
cancelResponse(requestID: $requestID) {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
@ -9,5 +9,16 @@ query GetInterceptedRequest($id: ID!) {
|
|||||||
value
|
value
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
|
response {
|
||||||
|
id
|
||||||
|
proto
|
||||||
|
statusCode
|
||||||
|
statusReason
|
||||||
|
headers {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
body
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
mutation ModifyResponse($response: ModifyResponseInput!) {
|
||||||
|
modifyResponse(response: $response) {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,16 @@ import { TabContext, TabList, TabPanel } from "@mui/lab";
|
|||||||
import { Box, Paper, Tab, Typography } from "@mui/material";
|
import { Box, Paper, Tab, Typography } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
import { KeyValuePairTable, KeyValuePair, KeyValuePairTableProps } from "./KeyValuePair";
|
||||||
|
|
||||||
import Editor from "lib/components/Editor";
|
import Editor from "lib/components/Editor";
|
||||||
import { KeyValuePairTable } from "lib/components/KeyValuePair";
|
|
||||||
import { HttpResponseLog } from "lib/graphql/generated";
|
|
||||||
|
|
||||||
interface ResponseTabsProps {
|
interface ResponseTabsProps {
|
||||||
headers: HttpResponseLog["headers"];
|
headers: KeyValuePair[];
|
||||||
body: HttpResponseLog["body"];
|
onHeaderChange?: KeyValuePairTableProps["onChange"];
|
||||||
|
onHeaderDelete?: KeyValuePairTableProps["onDelete"];
|
||||||
|
body?: string | null;
|
||||||
|
onBodyChange?: (value: string) => void;
|
||||||
hasResponse: boolean;
|
hasResponse: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +27,7 @@ const reqNotSent = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
function ResponseTabs(props: ResponseTabsProps): JSX.Element {
|
function ResponseTabs(props: ResponseTabsProps): JSX.Element {
|
||||||
const { headers, body, hasResponse } = props;
|
const { headers, onHeaderChange, onHeaderDelete, body, onBodyChange, hasResponse } = props;
|
||||||
const [tabValue, setTabValue] = useState(TabValue.Body);
|
const [tabValue, setTabValue] = useState(TabValue.Body);
|
||||||
|
|
||||||
const contentType = headers.find((header) => header.key.toLowerCase() === "content-type")?.value;
|
const contentType = headers.find((header) => header.key.toLowerCase() === "content-type")?.value;
|
||||||
@ -33,6 +36,8 @@ function ResponseTabs(props: ResponseTabsProps): JSX.Element {
|
|||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const headersLength = onHeaderChange ? headers.length - 1 : headers.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box height="100%" sx={{ display: "flex", flexDirection: "column" }}>
|
<Box height="100%" sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
<TabContext value={tabValue}>
|
<TabContext value={tabValue}>
|
||||||
@ -43,20 +48,25 @@ function ResponseTabs(props: ResponseTabsProps): JSX.Element {
|
|||||||
label={"Body" + (body?.length ? ` (${body.length} byte` + (body.length > 1 ? "s" : "") + ")" : "")}
|
label={"Body" + (body?.length ? ` (${body.length} byte` + (body.length > 1 ? "s" : "") + ")" : "")}
|
||||||
sx={tabSx}
|
sx={tabSx}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab value={TabValue.Headers} label={"Headers" + (headersLength ? ` (${headersLength})` : "")} sx={tabSx} />
|
||||||
value={TabValue.Headers}
|
|
||||||
label={"Headers" + (headers.length ? ` (${headers.length})` : "")}
|
|
||||||
sx={tabSx}
|
|
||||||
/>
|
|
||||||
</TabList>
|
</TabList>
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex="1 auto" overflow="hidden">
|
<Box flex="1 auto" overflow="hidden">
|
||||||
<TabPanel value={TabValue.Body} sx={{ p: 0, height: "100%" }}>
|
<TabPanel value={TabValue.Body} sx={{ p: 0, height: "100%" }}>
|
||||||
{body && <Editor content={body} contentType={contentType} />}
|
{hasResponse && (
|
||||||
|
<Editor
|
||||||
|
content={body || ""}
|
||||||
|
onChange={(value) => {
|
||||||
|
onBodyChange && onBodyChange(value || "");
|
||||||
|
}}
|
||||||
|
monacoOptions={{ readOnly: onBodyChange === undefined }}
|
||||||
|
contentType={contentType}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{!hasResponse && reqNotSent}
|
{!hasResponse && reqNotSent}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value={TabValue.Headers} sx={{ p: 0, height: "100%", overflow: "scroll" }}>
|
<TabPanel value={TabValue.Headers} sx={{ p: 0, height: "100%", overflow: "scroll" }}>
|
||||||
{headers.length > 0 && <KeyValuePairTable items={headers} />}
|
{hasResponse && <KeyValuePairTable items={headers} onChange={onHeaderChange} onDelete={onHeaderDelete} />}
|
||||||
{!hasResponse && reqNotSent}
|
{!hasResponse && reqNotSent}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -23,6 +23,11 @@ export type CancelRequestResult = {
|
|||||||
success: Scalars['Boolean'];
|
success: Scalars['Boolean'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CancelResponseResult = {
|
||||||
|
__typename?: 'CancelResponseResult';
|
||||||
|
success: Scalars['Boolean'];
|
||||||
|
};
|
||||||
|
|
||||||
export type ClearHttpRequestLogResult = {
|
export type ClearHttpRequestLogResult = {
|
||||||
__typename?: 'ClearHTTPRequestLogResult';
|
__typename?: 'ClearHTTPRequestLogResult';
|
||||||
success: Scalars['Boolean'];
|
success: Scalars['Boolean'];
|
||||||
@ -79,6 +84,7 @@ export type HttpRequest = {
|
|||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
method: HttpMethod;
|
method: HttpMethod;
|
||||||
proto: HttpProtocol;
|
proto: HttpProtocol;
|
||||||
|
response?: Maybe<HttpResponse>;
|
||||||
url: Scalars['URL'];
|
url: Scalars['URL'];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -105,6 +111,17 @@ export type HttpRequestLogFilterInput = {
|
|||||||
searchExpression?: InputMaybe<Scalars['String']>;
|
searchExpression?: InputMaybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type HttpResponse = {
|
||||||
|
__typename?: 'HttpResponse';
|
||||||
|
body?: Maybe<Scalars['String']>;
|
||||||
|
headers: Array<HttpHeader>;
|
||||||
|
/** Will be the same ID as its related request ID. */
|
||||||
|
id: Scalars['ID'];
|
||||||
|
proto: HttpProtocol;
|
||||||
|
statusCode: Scalars['Int'];
|
||||||
|
statusReason: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
export type HttpResponseLog = {
|
export type HttpResponseLog = {
|
||||||
__typename?: 'HttpResponseLog';
|
__typename?: 'HttpResponseLog';
|
||||||
body?: Maybe<Scalars['String']>;
|
body?: Maybe<Scalars['String']>;
|
||||||
@ -127,6 +144,7 @@ export type ModifyRequestInput = {
|
|||||||
headers?: InputMaybe<Array<HttpHeaderInput>>;
|
headers?: InputMaybe<Array<HttpHeaderInput>>;
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
method: HttpMethod;
|
method: HttpMethod;
|
||||||
|
modifyResponse?: InputMaybe<Scalars['Boolean']>;
|
||||||
proto: HttpProtocol;
|
proto: HttpProtocol;
|
||||||
url: Scalars['URL'];
|
url: Scalars['URL'];
|
||||||
};
|
};
|
||||||
@ -136,9 +154,24 @@ export type ModifyRequestResult = {
|
|||||||
success: Scalars['Boolean'];
|
success: Scalars['Boolean'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ModifyResponseInput = {
|
||||||
|
body?: InputMaybe<Scalars['String']>;
|
||||||
|
headers?: InputMaybe<Array<HttpHeaderInput>>;
|
||||||
|
proto: HttpProtocol;
|
||||||
|
requestID: Scalars['ID'];
|
||||||
|
statusCode: Scalars['Int'];
|
||||||
|
statusReason: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ModifyResponseResult = {
|
||||||
|
__typename?: 'ModifyResponseResult';
|
||||||
|
success: Scalars['Boolean'];
|
||||||
|
};
|
||||||
|
|
||||||
export type Mutation = {
|
export type Mutation = {
|
||||||
__typename?: 'Mutation';
|
__typename?: 'Mutation';
|
||||||
cancelRequest: CancelRequestResult;
|
cancelRequest: CancelRequestResult;
|
||||||
|
cancelResponse: CancelResponseResult;
|
||||||
clearHTTPRequestLog: ClearHttpRequestLogResult;
|
clearHTTPRequestLog: ClearHttpRequestLogResult;
|
||||||
closeProject: CloseProjectResult;
|
closeProject: CloseProjectResult;
|
||||||
createOrUpdateSenderRequest: SenderRequest;
|
createOrUpdateSenderRequest: SenderRequest;
|
||||||
@ -147,6 +180,7 @@ export type Mutation = {
|
|||||||
deleteProject: DeleteProjectResult;
|
deleteProject: DeleteProjectResult;
|
||||||
deleteSenderRequests: DeleteSenderRequestsResult;
|
deleteSenderRequests: DeleteSenderRequestsResult;
|
||||||
modifyRequest: ModifyRequestResult;
|
modifyRequest: ModifyRequestResult;
|
||||||
|
modifyResponse: ModifyResponseResult;
|
||||||
openProject?: Maybe<Project>;
|
openProject?: Maybe<Project>;
|
||||||
sendRequest: SenderRequest;
|
sendRequest: SenderRequest;
|
||||||
setHttpRequestLogFilter?: Maybe<HttpRequestLogFilter>;
|
setHttpRequestLogFilter?: Maybe<HttpRequestLogFilter>;
|
||||||
@ -161,6 +195,11 @@ export type MutationCancelRequestArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationCancelResponseArgs = {
|
||||||
|
requestID: Scalars['ID'];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateOrUpdateSenderRequestArgs = {
|
export type MutationCreateOrUpdateSenderRequestArgs = {
|
||||||
request: SenderRequestInput;
|
request: SenderRequestInput;
|
||||||
};
|
};
|
||||||
@ -186,6 +225,11 @@ export type MutationModifyRequestArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationModifyResponseArgs = {
|
||||||
|
response: ModifyResponseInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationOpenProjectArgs = {
|
export type MutationOpenProjectArgs = {
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
};
|
};
|
||||||
@ -326,12 +370,19 @@ export type CancelRequestMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type CancelRequestMutation = { __typename?: 'Mutation', cancelRequest: { __typename?: 'CancelRequestResult', success: boolean } };
|
export type CancelRequestMutation = { __typename?: 'Mutation', cancelRequest: { __typename?: 'CancelRequestResult', success: boolean } };
|
||||||
|
|
||||||
|
export type CancelResponseMutationVariables = Exact<{
|
||||||
|
requestID: Scalars['ID'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type CancelResponseMutation = { __typename?: 'Mutation', cancelResponse: { __typename?: 'CancelResponseResult', success: boolean } };
|
||||||
|
|
||||||
export type GetInterceptedRequestQueryVariables = Exact<{
|
export type GetInterceptedRequestQueryVariables = Exact<{
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type GetInterceptedRequestQuery = { __typename?: 'Query', interceptedRequest?: { __typename?: 'HttpRequest', id: string, url: any, method: HttpMethod, proto: HttpProtocol, body?: string | null, headers: Array<{ __typename?: 'HttpHeader', key: string, value: string }> } | null };
|
export type GetInterceptedRequestQuery = { __typename?: 'Query', interceptedRequest?: { __typename?: 'HttpRequest', id: string, url: any, method: HttpMethod, proto: HttpProtocol, body?: string | null, headers: Array<{ __typename?: 'HttpHeader', key: string, value: string }>, response?: { __typename?: 'HttpResponse', id: string, proto: HttpProtocol, statusCode: number, statusReason: string, body?: string | null, headers: Array<{ __typename?: 'HttpHeader', key: string, value: string }> } | null } | null };
|
||||||
|
|
||||||
export type ModifyRequestMutationVariables = Exact<{
|
export type ModifyRequestMutationVariables = Exact<{
|
||||||
request: ModifyRequestInput;
|
request: ModifyRequestInput;
|
||||||
@ -340,6 +391,13 @@ export type ModifyRequestMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type ModifyRequestMutation = { __typename?: 'Mutation', modifyRequest: { __typename?: 'ModifyRequestResult', success: boolean } };
|
export type ModifyRequestMutation = { __typename?: 'Mutation', modifyRequest: { __typename?: 'ModifyRequestResult', success: boolean } };
|
||||||
|
|
||||||
|
export type ModifyResponseMutationVariables = Exact<{
|
||||||
|
response: ModifyResponseInput;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ModifyResponseMutation = { __typename?: 'Mutation', modifyResponse: { __typename?: 'ModifyResponseResult', success: boolean } };
|
||||||
|
|
||||||
export type ActiveProjectQueryVariables = Exact<{ [key: string]: never; }>;
|
export type ActiveProjectQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
@ -460,7 +518,7 @@ export type UpdateInterceptSettingsMutation = { __typename?: 'Mutation', updateI
|
|||||||
export type GetInterceptedRequestsQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetInterceptedRequestsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetInterceptedRequestsQuery = { __typename?: 'Query', interceptedRequests: Array<{ __typename?: 'HttpRequest', id: string, url: any, method: HttpMethod }> };
|
export type GetInterceptedRequestsQuery = { __typename?: 'Query', interceptedRequests: Array<{ __typename?: 'HttpRequest', id: string, url: any, method: HttpMethod, response?: { __typename?: 'HttpResponse', statusCode: number, statusReason: string } | null }> };
|
||||||
|
|
||||||
|
|
||||||
export const CancelRequestDocument = gql`
|
export const CancelRequestDocument = gql`
|
||||||
@ -496,6 +554,39 @@ export function useCancelRequestMutation(baseOptions?: Apollo.MutationHookOption
|
|||||||
export type CancelRequestMutationHookResult = ReturnType<typeof useCancelRequestMutation>;
|
export type CancelRequestMutationHookResult = ReturnType<typeof useCancelRequestMutation>;
|
||||||
export type CancelRequestMutationResult = Apollo.MutationResult<CancelRequestMutation>;
|
export type CancelRequestMutationResult = Apollo.MutationResult<CancelRequestMutation>;
|
||||||
export type CancelRequestMutationOptions = Apollo.BaseMutationOptions<CancelRequestMutation, CancelRequestMutationVariables>;
|
export type CancelRequestMutationOptions = Apollo.BaseMutationOptions<CancelRequestMutation, CancelRequestMutationVariables>;
|
||||||
|
export const CancelResponseDocument = gql`
|
||||||
|
mutation CancelResponse($requestID: ID!) {
|
||||||
|
cancelResponse(requestID: $requestID) {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type CancelResponseMutationFn = Apollo.MutationFunction<CancelResponseMutation, CancelResponseMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useCancelResponseMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useCancelResponseMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useCancelResponseMutation` returns a tuple that includes:
|
||||||
|
* - A mutate function that you can call at any time to execute the mutation
|
||||||
|
* - An object with fields that represent the current status of the mutation's execution
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const [cancelResponseMutation, { data, loading, error }] = useCancelResponseMutation({
|
||||||
|
* variables: {
|
||||||
|
* requestID: // value for 'requestID'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useCancelResponseMutation(baseOptions?: Apollo.MutationHookOptions<CancelResponseMutation, CancelResponseMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<CancelResponseMutation, CancelResponseMutationVariables>(CancelResponseDocument, options);
|
||||||
|
}
|
||||||
|
export type CancelResponseMutationHookResult = ReturnType<typeof useCancelResponseMutation>;
|
||||||
|
export type CancelResponseMutationResult = Apollo.MutationResult<CancelResponseMutation>;
|
||||||
|
export type CancelResponseMutationOptions = Apollo.BaseMutationOptions<CancelResponseMutation, CancelResponseMutationVariables>;
|
||||||
export const GetInterceptedRequestDocument = gql`
|
export const GetInterceptedRequestDocument = gql`
|
||||||
query GetInterceptedRequest($id: ID!) {
|
query GetInterceptedRequest($id: ID!) {
|
||||||
interceptedRequest(id: $id) {
|
interceptedRequest(id: $id) {
|
||||||
@ -508,6 +599,17 @@ export const GetInterceptedRequestDocument = gql`
|
|||||||
value
|
value
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
|
response {
|
||||||
|
id
|
||||||
|
proto
|
||||||
|
statusCode
|
||||||
|
statusReason
|
||||||
|
headers {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
body
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -572,6 +674,39 @@ export function useModifyRequestMutation(baseOptions?: Apollo.MutationHookOption
|
|||||||
export type ModifyRequestMutationHookResult = ReturnType<typeof useModifyRequestMutation>;
|
export type ModifyRequestMutationHookResult = ReturnType<typeof useModifyRequestMutation>;
|
||||||
export type ModifyRequestMutationResult = Apollo.MutationResult<ModifyRequestMutation>;
|
export type ModifyRequestMutationResult = Apollo.MutationResult<ModifyRequestMutation>;
|
||||||
export type ModifyRequestMutationOptions = Apollo.BaseMutationOptions<ModifyRequestMutation, ModifyRequestMutationVariables>;
|
export type ModifyRequestMutationOptions = Apollo.BaseMutationOptions<ModifyRequestMutation, ModifyRequestMutationVariables>;
|
||||||
|
export const ModifyResponseDocument = gql`
|
||||||
|
mutation ModifyResponse($response: ModifyResponseInput!) {
|
||||||
|
modifyResponse(response: $response) {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type ModifyResponseMutationFn = Apollo.MutationFunction<ModifyResponseMutation, ModifyResponseMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useModifyResponseMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useModifyResponseMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useModifyResponseMutation` returns a tuple that includes:
|
||||||
|
* - A mutate function that you can call at any time to execute the mutation
|
||||||
|
* - An object with fields that represent the current status of the mutation's execution
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const [modifyResponseMutation, { data, loading, error }] = useModifyResponseMutation({
|
||||||
|
* variables: {
|
||||||
|
* response: // value for 'response'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useModifyResponseMutation(baseOptions?: Apollo.MutationHookOptions<ModifyResponseMutation, ModifyResponseMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<ModifyResponseMutation, ModifyResponseMutationVariables>(ModifyResponseDocument, options);
|
||||||
|
}
|
||||||
|
export type ModifyResponseMutationHookResult = ReturnType<typeof useModifyResponseMutation>;
|
||||||
|
export type ModifyResponseMutationResult = Apollo.MutationResult<ModifyResponseMutation>;
|
||||||
|
export type ModifyResponseMutationOptions = Apollo.BaseMutationOptions<ModifyResponseMutation, ModifyResponseMutationVariables>;
|
||||||
export const ActiveProjectDocument = gql`
|
export const ActiveProjectDocument = gql`
|
||||||
query ActiveProject {
|
query ActiveProject {
|
||||||
activeProject {
|
activeProject {
|
||||||
@ -1283,6 +1418,10 @@ export const GetInterceptedRequestsDocument = gql`
|
|||||||
id
|
id
|
||||||
url
|
url
|
||||||
method
|
method
|
||||||
|
response {
|
||||||
|
statusCode
|
||||||
|
statusReason
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -3,5 +3,9 @@ query GetInterceptedRequests {
|
|||||||
id
|
id
|
||||||
url
|
url
|
||||||
method
|
method
|
||||||
|
response {
|
||||||
|
statusCode
|
||||||
|
statusReason
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,6 +208,7 @@ func (cmd *HettyCommand) Exec(ctx context.Context, _ []string) error {
|
|||||||
proxy.UseRequestModifier(reqLogService.RequestModifier)
|
proxy.UseRequestModifier(reqLogService.RequestModifier)
|
||||||
proxy.UseResponseModifier(reqLogService.ResponseModifier)
|
proxy.UseResponseModifier(reqLogService.ResponseModifier)
|
||||||
proxy.UseRequestModifier(interceptService.RequestModifier)
|
proxy.UseRequestModifier(interceptService.RequestModifier)
|
||||||
|
proxy.UseResponseModifier(interceptService.ResponseModifier)
|
||||||
|
|
||||||
fsSub, err := fs.Sub(adminContent, "admin")
|
fsSub, err := fs.Sub(adminContent, "admin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,6 +49,10 @@ type ComplexityRoot struct {
|
|||||||
Success func(childComplexity int) int
|
Success func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CancelResponseResult struct {
|
||||||
|
Success func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
ClearHTTPRequestLogResult struct {
|
ClearHTTPRequestLogResult struct {
|
||||||
Success func(childComplexity int) int
|
Success func(childComplexity int) int
|
||||||
}
|
}
|
||||||
@ -76,6 +80,7 @@ type ComplexityRoot struct {
|
|||||||
ID func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
Method func(childComplexity int) int
|
Method func(childComplexity int) int
|
||||||
Proto func(childComplexity int) int
|
Proto func(childComplexity int) int
|
||||||
|
Response func(childComplexity int) int
|
||||||
URL func(childComplexity int) int
|
URL func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +100,15 @@ type ComplexityRoot struct {
|
|||||||
SearchExpression func(childComplexity int) int
|
SearchExpression func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HTTPResponse struct {
|
||||||
|
Body func(childComplexity int) int
|
||||||
|
Headers func(childComplexity int) int
|
||||||
|
ID func(childComplexity int) int
|
||||||
|
Proto func(childComplexity int) int
|
||||||
|
StatusCode func(childComplexity int) int
|
||||||
|
StatusReason func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
HTTPResponseLog struct {
|
HTTPResponseLog struct {
|
||||||
Body func(childComplexity int) int
|
Body func(childComplexity int) int
|
||||||
Headers func(childComplexity int) int
|
Headers func(childComplexity int) int
|
||||||
@ -113,8 +127,13 @@ type ComplexityRoot struct {
|
|||||||
Success func(childComplexity int) int
|
Success func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModifyResponseResult struct {
|
||||||
|
Success func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
Mutation struct {
|
Mutation struct {
|
||||||
CancelRequest func(childComplexity int, id ulid.ULID) int
|
CancelRequest func(childComplexity int, id ulid.ULID) int
|
||||||
|
CancelResponse func(childComplexity int, requestID ulid.ULID) int
|
||||||
ClearHTTPRequestLog func(childComplexity int) int
|
ClearHTTPRequestLog func(childComplexity int) int
|
||||||
CloseProject func(childComplexity int) int
|
CloseProject func(childComplexity int) int
|
||||||
CreateOrUpdateSenderRequest func(childComplexity int, request SenderRequestInput) int
|
CreateOrUpdateSenderRequest func(childComplexity int, request SenderRequestInput) int
|
||||||
@ -123,6 +142,7 @@ type ComplexityRoot struct {
|
|||||||
DeleteProject func(childComplexity int, id ulid.ULID) int
|
DeleteProject func(childComplexity int, id ulid.ULID) int
|
||||||
DeleteSenderRequests func(childComplexity int) int
|
DeleteSenderRequests func(childComplexity int) int
|
||||||
ModifyRequest func(childComplexity int, request ModifyRequestInput) int
|
ModifyRequest func(childComplexity int, request ModifyRequestInput) int
|
||||||
|
ModifyResponse func(childComplexity int, response ModifyResponseInput) int
|
||||||
OpenProject func(childComplexity int, id ulid.ULID) int
|
OpenProject func(childComplexity int, id ulid.ULID) int
|
||||||
SendRequest func(childComplexity int, id ulid.ULID) int
|
SendRequest func(childComplexity int, id ulid.ULID) int
|
||||||
SetHTTPRequestLogFilter func(childComplexity int, filter *HTTPRequestLogFilterInput) int
|
SetHTTPRequestLogFilter func(childComplexity int, filter *HTTPRequestLogFilterInput) int
|
||||||
@ -199,6 +219,8 @@ type MutationResolver interface {
|
|||||||
DeleteSenderRequests(ctx context.Context) (*DeleteSenderRequestsResult, error)
|
DeleteSenderRequests(ctx context.Context) (*DeleteSenderRequestsResult, error)
|
||||||
ModifyRequest(ctx context.Context, request ModifyRequestInput) (*ModifyRequestResult, error)
|
ModifyRequest(ctx context.Context, request ModifyRequestInput) (*ModifyRequestResult, error)
|
||||||
CancelRequest(ctx context.Context, id ulid.ULID) (*CancelRequestResult, error)
|
CancelRequest(ctx context.Context, id ulid.ULID) (*CancelRequestResult, error)
|
||||||
|
ModifyResponse(ctx context.Context, response ModifyResponseInput) (*ModifyResponseResult, error)
|
||||||
|
CancelResponse(ctx context.Context, requestID ulid.ULID) (*CancelResponseResult, error)
|
||||||
UpdateInterceptSettings(ctx context.Context, input UpdateInterceptSettingsInput) (*InterceptSettings, error)
|
UpdateInterceptSettings(ctx context.Context, input UpdateInterceptSettingsInput) (*InterceptSettings, error)
|
||||||
}
|
}
|
||||||
type QueryResolver interface {
|
type QueryResolver interface {
|
||||||
@ -236,6 +258,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.CancelRequestResult.Success(childComplexity), true
|
return e.complexity.CancelRequestResult.Success(childComplexity), true
|
||||||
|
|
||||||
|
case "CancelResponseResult.success":
|
||||||
|
if e.complexity.CancelResponseResult.Success == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.CancelResponseResult.Success(childComplexity), true
|
||||||
|
|
||||||
case "ClearHTTPRequestLogResult.success":
|
case "ClearHTTPRequestLogResult.success":
|
||||||
if e.complexity.ClearHTTPRequestLogResult.Success == nil {
|
if e.complexity.ClearHTTPRequestLogResult.Success == nil {
|
||||||
break
|
break
|
||||||
@ -313,6 +342,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.HTTPRequest.Proto(childComplexity), true
|
return e.complexity.HTTPRequest.Proto(childComplexity), true
|
||||||
|
|
||||||
|
case "HttpRequest.response":
|
||||||
|
if e.complexity.HTTPRequest.Response == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.HTTPRequest.Response(childComplexity), true
|
||||||
|
|
||||||
case "HttpRequest.url":
|
case "HttpRequest.url":
|
||||||
if e.complexity.HTTPRequest.URL == nil {
|
if e.complexity.HTTPRequest.URL == nil {
|
||||||
break
|
break
|
||||||
@ -390,6 +426,48 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.HTTPRequestLogFilter.SearchExpression(childComplexity), true
|
return e.complexity.HTTPRequestLogFilter.SearchExpression(childComplexity), true
|
||||||
|
|
||||||
|
case "HttpResponse.body":
|
||||||
|
if e.complexity.HTTPResponse.Body == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.HTTPResponse.Body(childComplexity), true
|
||||||
|
|
||||||
|
case "HttpResponse.headers":
|
||||||
|
if e.complexity.HTTPResponse.Headers == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.HTTPResponse.Headers(childComplexity), true
|
||||||
|
|
||||||
|
case "HttpResponse.id":
|
||||||
|
if e.complexity.HTTPResponse.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.HTTPResponse.ID(childComplexity), true
|
||||||
|
|
||||||
|
case "HttpResponse.proto":
|
||||||
|
if e.complexity.HTTPResponse.Proto == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.HTTPResponse.Proto(childComplexity), true
|
||||||
|
|
||||||
|
case "HttpResponse.statusCode":
|
||||||
|
if e.complexity.HTTPResponse.StatusCode == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.HTTPResponse.StatusCode(childComplexity), true
|
||||||
|
|
||||||
|
case "HttpResponse.statusReason":
|
||||||
|
if e.complexity.HTTPResponse.StatusReason == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.HTTPResponse.StatusReason(childComplexity), true
|
||||||
|
|
||||||
case "HttpResponseLog.body":
|
case "HttpResponseLog.body":
|
||||||
if e.complexity.HTTPResponseLog.Body == nil {
|
if e.complexity.HTTPResponseLog.Body == nil {
|
||||||
break
|
break
|
||||||
@ -453,6 +531,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.ModifyRequestResult.Success(childComplexity), true
|
return e.complexity.ModifyRequestResult.Success(childComplexity), true
|
||||||
|
|
||||||
|
case "ModifyResponseResult.success":
|
||||||
|
if e.complexity.ModifyResponseResult.Success == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ModifyResponseResult.Success(childComplexity), true
|
||||||
|
|
||||||
case "Mutation.cancelRequest":
|
case "Mutation.cancelRequest":
|
||||||
if e.complexity.Mutation.CancelRequest == nil {
|
if e.complexity.Mutation.CancelRequest == nil {
|
||||||
break
|
break
|
||||||
@ -465,6 +550,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Mutation.CancelRequest(childComplexity, args["id"].(ulid.ULID)), true
|
return e.complexity.Mutation.CancelRequest(childComplexity, args["id"].(ulid.ULID)), true
|
||||||
|
|
||||||
|
case "Mutation.cancelResponse":
|
||||||
|
if e.complexity.Mutation.CancelResponse == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_cancelResponse_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.CancelResponse(childComplexity, args["requestID"].(ulid.ULID)), true
|
||||||
|
|
||||||
case "Mutation.clearHTTPRequestLog":
|
case "Mutation.clearHTTPRequestLog":
|
||||||
if e.complexity.Mutation.ClearHTTPRequestLog == nil {
|
if e.complexity.Mutation.ClearHTTPRequestLog == nil {
|
||||||
break
|
break
|
||||||
@ -546,6 +643,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Mutation.ModifyRequest(childComplexity, args["request"].(ModifyRequestInput)), true
|
return e.complexity.Mutation.ModifyRequest(childComplexity, args["request"].(ModifyRequestInput)), true
|
||||||
|
|
||||||
|
case "Mutation.modifyResponse":
|
||||||
|
if e.complexity.Mutation.ModifyResponse == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_modifyResponse_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.ModifyResponse(childComplexity, args["response"].(ModifyResponseInput)), true
|
||||||
|
|
||||||
case "Mutation.openProject":
|
case "Mutation.openProject":
|
||||||
if e.complexity.Mutation.OpenProject == nil {
|
if e.complexity.Mutation.OpenProject == nil {
|
||||||
break
|
break
|
||||||
@ -1044,6 +1153,19 @@ type HttpRequest {
|
|||||||
proto: HttpProtocol!
|
proto: HttpProtocol!
|
||||||
headers: [HttpHeader!]!
|
headers: [HttpHeader!]!
|
||||||
body: String
|
body: String
|
||||||
|
response: HttpResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpResponse {
|
||||||
|
"""
|
||||||
|
Will be the same ID as its related request ID.
|
||||||
|
"""
|
||||||
|
id: ID!
|
||||||
|
proto: HttpProtocol!
|
||||||
|
statusCode: Int!
|
||||||
|
statusReason: String!
|
||||||
|
body: String
|
||||||
|
headers: [HttpHeader!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ModifyRequestInput {
|
input ModifyRequestInput {
|
||||||
@ -1053,6 +1175,7 @@ input ModifyRequestInput {
|
|||||||
proto: HttpProtocol!
|
proto: HttpProtocol!
|
||||||
headers: [HttpHeaderInput!]
|
headers: [HttpHeaderInput!]
|
||||||
body: String
|
body: String
|
||||||
|
modifyResponse: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModifyRequestResult {
|
type ModifyRequestResult {
|
||||||
@ -1063,6 +1186,23 @@ type CancelRequestResult {
|
|||||||
success: Boolean!
|
success: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input ModifyResponseInput {
|
||||||
|
requestID: ID!
|
||||||
|
proto: HttpProtocol!
|
||||||
|
headers: [HttpHeaderInput!]
|
||||||
|
body: String
|
||||||
|
statusCode: Int!
|
||||||
|
statusReason: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModifyResponseResult {
|
||||||
|
success: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
|
type CancelResponseResult {
|
||||||
|
success: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
input UpdateInterceptSettingsInput {
|
input UpdateInterceptSettingsInput {
|
||||||
enabled: Boolean!
|
enabled: Boolean!
|
||||||
requestFilter: String
|
requestFilter: String
|
||||||
@ -1103,6 +1243,8 @@ type Mutation {
|
|||||||
deleteSenderRequests: DeleteSenderRequestsResult!
|
deleteSenderRequests: DeleteSenderRequestsResult!
|
||||||
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
|
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
|
||||||
cancelRequest(id: ID!): CancelRequestResult!
|
cancelRequest(id: ID!): CancelRequestResult!
|
||||||
|
modifyResponse(response: ModifyResponseInput!): ModifyResponseResult!
|
||||||
|
cancelResponse(requestID: ID!): CancelResponseResult!
|
||||||
updateInterceptSettings(
|
updateInterceptSettings(
|
||||||
input: UpdateInterceptSettingsInput!
|
input: UpdateInterceptSettingsInput!
|
||||||
): InterceptSettings!
|
): InterceptSettings!
|
||||||
@ -1152,6 +1294,21 @@ func (ec *executionContext) field_Mutation_cancelRequest_args(ctx context.Contex
|
|||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_cancelResponse_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 ulid.ULID
|
||||||
|
if tmp, ok := rawArgs["requestID"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("requestID"))
|
||||||
|
arg0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["requestID"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_createOrUpdateSenderRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation_createOrUpdateSenderRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
@ -1227,6 +1384,21 @@ func (ec *executionContext) field_Mutation_modifyRequest_args(ctx context.Contex
|
|||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_modifyResponse_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 ModifyResponseInput
|
||||||
|
if tmp, ok := rawArgs["response"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("response"))
|
||||||
|
arg0, err = ec.unmarshalNModifyResponseInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseInput(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["response"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_openProject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation_openProject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
@ -1450,6 +1622,41 @@ func (ec *executionContext) _CancelRequestResult_success(ctx context.Context, fi
|
|||||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _CancelResponseResult_success(ctx context.Context, field graphql.CollectedField, obj *CancelResponseResult) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "CancelResponseResult",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Success, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ClearHTTPRequestLogResult_success(ctx context.Context, field graphql.CollectedField, obj *ClearHTTPRequestLogResult) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ClearHTTPRequestLogResult_success(ctx context.Context, field graphql.CollectedField, obj *ClearHTTPRequestLogResult) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -1867,6 +2074,38 @@ func (ec *executionContext) _HttpRequest_body(ctx context.Context, field graphql
|
|||||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _HttpRequest_response(ctx context.Context, field graphql.CollectedField, obj *HTTPRequest) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "HttpRequest",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Response, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*HTTPResponse)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOHttpResponse2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponse(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _HttpRequestLog_id(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {
|
func (ec *executionContext) _HttpRequestLog_id(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -2208,6 +2447,213 @@ func (ec *executionContext) _HttpRequestLogFilter_searchExpression(ctx context.C
|
|||||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _HttpResponse_id(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "HttpResponse",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.ID, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(ulid.ULID)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _HttpResponse_proto(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "HttpResponse",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Proto, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(HTTPProtocol)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _HttpResponse_statusCode(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "HttpResponse",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.StatusCode, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(int)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNInt2int(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _HttpResponse_statusReason(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "HttpResponse",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.StatusReason, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _HttpResponse_body(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "HttpResponse",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Body, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _HttpResponse_headers(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "HttpResponse",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Headers, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.([]HTTPHeader)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _HttpResponseLog_id(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {
|
func (ec *executionContext) _HttpResponseLog_id(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -2517,6 +2963,41 @@ func (ec *executionContext) _ModifyRequestResult_success(ctx context.Context, fi
|
|||||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ModifyResponseResult_success(ctx context.Context, field graphql.CollectedField, obj *ModifyResponseResult) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "ModifyResponseResult",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Success, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_createProject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_createProject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -3072,6 +3553,90 @@ func (ec *executionContext) _Mutation_cancelRequest(ctx context.Context, field g
|
|||||||
return ec.marshalNCancelRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelRequestResult(ctx, field.Selections, res)
|
return ec.marshalNCancelRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelRequestResult(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_modifyResponse(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation_modifyResponse_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
fc.Args = args
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().ModifyResponse(rctx, args["response"].(ModifyResponseInput))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*ModifyResponseResult)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNModifyResponseResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseResult(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_cancelResponse(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation_cancelResponse_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
fc.Args = args
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().CancelResponse(rctx, args["requestID"].(ulid.ULID))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*CancelResponseResult)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNCancelResponseResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelResponseResult(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_updateInterceptSettings(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_updateInterceptSettings(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -5487,6 +6052,77 @@ func (ec *executionContext) unmarshalInputModifyRequestInput(ctx context.Context
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
|
case "modifyResponse":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifyResponse"))
|
||||||
|
it.ModifyResponse, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputModifyResponseInput(ctx context.Context, obj interface{}) (ModifyResponseInput, error) {
|
||||||
|
var it ModifyResponseInput
|
||||||
|
asMap := map[string]interface{}{}
|
||||||
|
for k, v := range obj.(map[string]interface{}) {
|
||||||
|
asMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range asMap {
|
||||||
|
switch k {
|
||||||
|
case "requestID":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("requestID"))
|
||||||
|
it.RequestID, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "proto":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("proto"))
|
||||||
|
it.Proto, err = ec.unmarshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "headers":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("headers"))
|
||||||
|
it.Headers, err = ec.unmarshalOHttpHeaderInput2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderInputᚄ(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "body":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("body"))
|
||||||
|
it.Body, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "statusCode":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("statusCode"))
|
||||||
|
it.StatusCode, err = ec.unmarshalNInt2int(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "statusReason":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("statusReason"))
|
||||||
|
it.StatusReason, err = ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5723,6 +6359,33 @@ func (ec *executionContext) _CancelRequestResult(ctx context.Context, sel ast.Se
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cancelResponseResultImplementors = []string{"CancelResponseResult"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _CancelResponseResult(ctx context.Context, sel ast.SelectionSet, obj *CancelResponseResult) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, cancelResponseResultImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
var invalids uint32
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("CancelResponseResult")
|
||||||
|
case "success":
|
||||||
|
out.Values[i] = ec._CancelResponseResult_success(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch()
|
||||||
|
if invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var clearHTTPRequestLogResultImplementors = []string{"ClearHTTPRequestLogResult"}
|
var clearHTTPRequestLogResultImplementors = []string{"ClearHTTPRequestLogResult"}
|
||||||
|
|
||||||
func (ec *executionContext) _ClearHTTPRequestLogResult(ctx context.Context, sel ast.SelectionSet, obj *ClearHTTPRequestLogResult) graphql.Marshaler {
|
func (ec *executionContext) _ClearHTTPRequestLogResult(ctx context.Context, sel ast.SelectionSet, obj *ClearHTTPRequestLogResult) graphql.Marshaler {
|
||||||
@ -5901,6 +6564,8 @@ func (ec *executionContext) _HttpRequest(ctx context.Context, sel ast.SelectionS
|
|||||||
}
|
}
|
||||||
case "body":
|
case "body":
|
||||||
out.Values[i] = ec._HttpRequest_body(ctx, field, obj)
|
out.Values[i] = ec._HttpRequest_body(ctx, field, obj)
|
||||||
|
case "response":
|
||||||
|
out.Values[i] = ec._HttpRequest_response(ctx, field, obj)
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
@ -5997,6 +6662,55 @@ func (ec *executionContext) _HttpRequestLogFilter(ctx context.Context, sel ast.S
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var httpResponseImplementors = []string{"HttpResponse"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _HttpResponse(ctx context.Context, sel ast.SelectionSet, obj *HTTPResponse) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, httpResponseImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
var invalids uint32
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("HttpResponse")
|
||||||
|
case "id":
|
||||||
|
out.Values[i] = ec._HttpResponse_id(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "proto":
|
||||||
|
out.Values[i] = ec._HttpResponse_proto(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "statusCode":
|
||||||
|
out.Values[i] = ec._HttpResponse_statusCode(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "statusReason":
|
||||||
|
out.Values[i] = ec._HttpResponse_statusReason(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "body":
|
||||||
|
out.Values[i] = ec._HttpResponse_body(ctx, field, obj)
|
||||||
|
case "headers":
|
||||||
|
out.Values[i] = ec._HttpResponse_headers(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch()
|
||||||
|
if invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var httpResponseLogImplementors = []string{"HttpResponseLog"}
|
var httpResponseLogImplementors = []string{"HttpResponseLog"}
|
||||||
|
|
||||||
func (ec *executionContext) _HttpResponseLog(ctx context.Context, sel ast.SelectionSet, obj *HTTPResponseLog) graphql.Marshaler {
|
func (ec *executionContext) _HttpResponseLog(ctx context.Context, sel ast.SelectionSet, obj *HTTPResponseLog) graphql.Marshaler {
|
||||||
@ -6102,6 +6816,33 @@ func (ec *executionContext) _ModifyRequestResult(ctx context.Context, sel ast.Se
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var modifyResponseResultImplementors = []string{"ModifyResponseResult"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ModifyResponseResult(ctx context.Context, sel ast.SelectionSet, obj *ModifyResponseResult) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, modifyResponseResultImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
var invalids uint32
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("ModifyResponseResult")
|
||||||
|
case "success":
|
||||||
|
out.Values[i] = ec._ModifyResponseResult_success(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch()
|
||||||
|
if invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var mutationImplementors = []string{"Mutation"}
|
var mutationImplementors = []string{"Mutation"}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
|
func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
|
||||||
@ -6175,6 +6916,16 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "modifyResponse":
|
||||||
|
out.Values[i] = ec._Mutation_modifyResponse(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "cancelResponse":
|
||||||
|
out.Values[i] = ec._Mutation_cancelResponse(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
case "updateInterceptSettings":
|
case "updateInterceptSettings":
|
||||||
out.Values[i] = ec._Mutation_updateInterceptSettings(ctx, field)
|
out.Values[i] = ec._Mutation_updateInterceptSettings(ctx, field)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
@ -6832,6 +7583,20 @@ func (ec *executionContext) marshalNCancelRequestResult2ᚖgithubᚗcomᚋdstoti
|
|||||||
return ec._CancelRequestResult(ctx, sel, v)
|
return ec._CancelRequestResult(ctx, sel, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNCancelResponseResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelResponseResult(ctx context.Context, sel ast.SelectionSet, v CancelResponseResult) graphql.Marshaler {
|
||||||
|
return ec._CancelResponseResult(ctx, sel, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNCancelResponseResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelResponseResult(ctx context.Context, sel ast.SelectionSet, v *CancelResponseResult) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._CancelResponseResult(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalNClearHTTPRequestLogResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐClearHTTPRequestLogResult(ctx context.Context, sel ast.SelectionSet, v ClearHTTPRequestLogResult) graphql.Marshaler {
|
func (ec *executionContext) marshalNClearHTTPRequestLogResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐClearHTTPRequestLogResult(ctx context.Context, sel ast.SelectionSet, v ClearHTTPRequestLogResult) graphql.Marshaler {
|
||||||
return ec._ClearHTTPRequestLogResult(ctx, sel, &v)
|
return ec._ClearHTTPRequestLogResult(ctx, sel, &v)
|
||||||
}
|
}
|
||||||
@ -7120,6 +7885,25 @@ func (ec *executionContext) marshalNModifyRequestResult2ᚖgithubᚗcomᚋdstoti
|
|||||||
return ec._ModifyRequestResult(ctx, sel, v)
|
return ec._ModifyRequestResult(ctx, sel, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalNModifyResponseInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseInput(ctx context.Context, v interface{}) (ModifyResponseInput, error) {
|
||||||
|
res, err := ec.unmarshalInputModifyResponseInput(ctx, v)
|
||||||
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNModifyResponseResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseResult(ctx context.Context, sel ast.SelectionSet, v ModifyResponseResult) graphql.Marshaler {
|
||||||
|
return ec._ModifyResponseResult(ctx, sel, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNModifyResponseResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseResult(ctx context.Context, sel ast.SelectionSet, v *ModifyResponseResult) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._ModifyResponseResult(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalNProject2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProject(ctx context.Context, sel ast.SelectionSet, v Project) graphql.Marshaler {
|
func (ec *executionContext) marshalNProject2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProject(ctx context.Context, sel ast.SelectionSet, v Project) graphql.Marshaler {
|
||||||
return ec._Project(ctx, sel, &v)
|
return ec._Project(ctx, sel, &v)
|
||||||
}
|
}
|
||||||
@ -7784,6 +8568,13 @@ func (ec *executionContext) unmarshalOHttpRequestLogFilterInput2ᚖgithubᚗcom
|
|||||||
return &res, graphql.ErrorOnPath(ctx, err)
|
return &res, graphql.ErrorOnPath(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalOHttpResponse2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponse(ctx context.Context, sel ast.SelectionSet, v *HTTPResponse) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._HttpResponse(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalOHttpResponseLog2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponseLog(ctx context.Context, sel ast.SelectionSet, v *HTTPResponseLog) graphql.Marshaler {
|
func (ec *executionContext) marshalOHttpResponseLog2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponseLog(ctx context.Context, sel ast.SelectionSet, v *HTTPResponseLog) graphql.Marshaler {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
|
@ -16,6 +16,10 @@ type CancelRequestResult struct {
|
|||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CancelResponseResult struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
type ClearHTTPRequestLogResult struct {
|
type ClearHTTPRequestLogResult struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
}
|
}
|
||||||
@ -49,6 +53,7 @@ type HTTPRequest struct {
|
|||||||
Proto HTTPProtocol `json:"proto"`
|
Proto HTTPProtocol `json:"proto"`
|
||||||
Headers []HTTPHeader `json:"headers"`
|
Headers []HTTPHeader `json:"headers"`
|
||||||
Body *string `json:"body"`
|
Body *string `json:"body"`
|
||||||
|
Response *HTTPResponse `json:"response"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPRequestLog struct {
|
type HTTPRequestLog struct {
|
||||||
@ -72,6 +77,16 @@ type HTTPRequestLogFilterInput struct {
|
|||||||
SearchExpression *string `json:"searchExpression"`
|
SearchExpression *string `json:"searchExpression"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HTTPResponse struct {
|
||||||
|
// Will be the same ID as its related request ID.
|
||||||
|
ID ulid.ULID `json:"id"`
|
||||||
|
Proto HTTPProtocol `json:"proto"`
|
||||||
|
StatusCode int `json:"statusCode"`
|
||||||
|
StatusReason string `json:"statusReason"`
|
||||||
|
Body *string `json:"body"`
|
||||||
|
Headers []HTTPHeader `json:"headers"`
|
||||||
|
}
|
||||||
|
|
||||||
type HTTPResponseLog struct {
|
type HTTPResponseLog struct {
|
||||||
// Will be the same ID as its related request ID.
|
// Will be the same ID as its related request ID.
|
||||||
ID ulid.ULID `json:"id"`
|
ID ulid.ULID `json:"id"`
|
||||||
@ -94,12 +109,26 @@ type ModifyRequestInput struct {
|
|||||||
Proto HTTPProtocol `json:"proto"`
|
Proto HTTPProtocol `json:"proto"`
|
||||||
Headers []HTTPHeaderInput `json:"headers"`
|
Headers []HTTPHeaderInput `json:"headers"`
|
||||||
Body *string `json:"body"`
|
Body *string `json:"body"`
|
||||||
|
ModifyResponse *bool `json:"modifyResponse"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModifyRequestResult struct {
|
type ModifyRequestResult struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ModifyResponseInput struct {
|
||||||
|
RequestID ulid.ULID `json:"requestID"`
|
||||||
|
Proto HTTPProtocol `json:"proto"`
|
||||||
|
Headers []HTTPHeaderInput `json:"headers"`
|
||||||
|
Body *string `json:"body"`
|
||||||
|
StatusCode int `json:"statusCode"`
|
||||||
|
StatusReason string `json:"statusReason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModifyResponseResult struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
ID ulid.ULID `json:"id"`
|
ID ulid.ULID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -515,36 +516,35 @@ func (r *mutationResolver) DeleteSenderRequests(ctx context.Context) (*DeleteSen
|
|||||||
return &DeleteSenderRequestsResult{true}, nil
|
return &DeleteSenderRequestsResult{true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) InterceptedRequests(ctx context.Context) ([]HTTPRequest, error) {
|
func (r *queryResolver) InterceptedRequests(ctx context.Context) (httpReqs []HTTPRequest, err error) {
|
||||||
reqs := r.InterceptService.Requests()
|
items := r.InterceptService.Items()
|
||||||
httpReqs := make([]HTTPRequest, len(reqs))
|
|
||||||
|
|
||||||
for i, req := range reqs {
|
for _, item := range items {
|
||||||
req, err := parseHTTPRequest(req)
|
req, err := parseInterceptItem(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
httpReqs[i] = req
|
httpReqs = append(httpReqs, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
return httpReqs, nil
|
return httpReqs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) InterceptedRequest(ctx context.Context, id ulid.ULID) (*HTTPRequest, error) {
|
func (r *queryResolver) InterceptedRequest(ctx context.Context, id ulid.ULID) (*HTTPRequest, error) {
|
||||||
req, err := r.InterceptService.RequestByID(id)
|
item, err := r.InterceptService.ItemByID(id)
|
||||||
if errors.Is(err, intercept.ErrRequestNotFound) {
|
if errors.Is(err, intercept.ErrRequestNotFound) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, fmt.Errorf("could not get request by ID: %w", err)
|
return nil, fmt.Errorf("could not get request by ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
httpReq, err := parseHTTPRequest(req)
|
req, err := parseInterceptItem(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &httpReq, nil
|
return &req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) ModifyRequest(ctx context.Context, input ModifyRequestInput) (*ModifyRequestResult, error) {
|
func (r *mutationResolver) ModifyRequest(ctx context.Context, input ModifyRequestInput) (*ModifyRequestResult, error) {
|
||||||
@ -563,7 +563,7 @@ func (r *mutationResolver) ModifyRequest(ctx context.Context, input ModifyReques
|
|||||||
req.Header.Add(header.Key, header.Value)
|
req.Header.Add(header.Key, header.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = r.InterceptService.ModifyRequest(input.ID, req)
|
err = r.InterceptService.ModifyRequest(input.ID, req, input.ModifyResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not modify http request: %w", err)
|
return nil, fmt.Errorf("could not modify http request: %w", err)
|
||||||
}
|
}
|
||||||
@ -580,6 +580,47 @@ func (r *mutationResolver) CancelRequest(ctx context.Context, id ulid.ULID) (*Ca
|
|||||||
return &CancelRequestResult{Success: true}, nil
|
return &CancelRequestResult{Success: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) ModifyResponse(
|
||||||
|
ctx context.Context,
|
||||||
|
input ModifyResponseInput,
|
||||||
|
) (*ModifyResponseResult, error) {
|
||||||
|
res := &http.Response{
|
||||||
|
Header: make(http.Header),
|
||||||
|
Status: fmt.Sprintf("%v %v", input.StatusCode, input.StatusReason),
|
||||||
|
StatusCode: input.StatusCode,
|
||||||
|
Proto: revHTTPProtocolMap[input.Proto],
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
if res.ProtoMajor, res.ProtoMinor, ok = http.ParseHTTPVersion(res.Proto); !ok {
|
||||||
|
return nil, fmt.Errorf("malformed HTTP version: %q", res.Proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.Body != nil {
|
||||||
|
res.Body = io.NopCloser(strings.NewReader(*input.Body))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, header := range input.Headers {
|
||||||
|
res.Header.Add(header.Key, header.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.InterceptService.ModifyResponse(input.RequestID, res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not modify http request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ModifyResponseResult{Success: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) CancelResponse(ctx context.Context, requestID ulid.ULID) (*CancelResponseResult, error) {
|
||||||
|
err := r.InterceptService.CancelResponse(requestID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not cancel http response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CancelResponseResult{Success: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) UpdateInterceptSettings(
|
func (r *mutationResolver) UpdateInterceptSettings(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
input UpdateInterceptSettingsInput,
|
input UpdateInterceptSettingsInput,
|
||||||
@ -721,6 +762,79 @@ func parseHTTPRequest(req *http.Request) (HTTPRequest, error) {
|
|||||||
return httpReq, nil
|
return httpReq, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseHTTPResponse(res *http.Response) (HTTPResponse, error) {
|
||||||
|
resProto := httpProtocolMap[res.Proto]
|
||||||
|
if !resProto.IsValid() {
|
||||||
|
return HTTPResponse{}, fmt.Errorf("http response has invalid protocol: %v", res.Proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
id, ok := proxy.RequestIDFromContext(res.Request.Context())
|
||||||
|
if !ok {
|
||||||
|
return HTTPResponse{}, errors.New("http response has missing ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRes := HTTPResponse{
|
||||||
|
ID: id,
|
||||||
|
Proto: resProto,
|
||||||
|
StatusCode: res.StatusCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
statusReasonSubs := strings.SplitN(res.Status, " ", 2)
|
||||||
|
|
||||||
|
if len(statusReasonSubs) == 2 {
|
||||||
|
httpRes.StatusReason = statusReasonSubs[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Header != nil {
|
||||||
|
httpRes.Headers = make([]HTTPHeader, 0)
|
||||||
|
|
||||||
|
for key, values := range res.Header {
|
||||||
|
for _, value := range values {
|
||||||
|
httpRes.Headers = append(httpRes.Headers, HTTPHeader{
|
||||||
|
Key: key,
|
||||||
|
Value: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Body != nil {
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return HTTPResponse{}, fmt.Errorf("failed to read response body: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Body = ioutil.NopCloser(bytes.NewBuffer(body))
|
||||||
|
bodyStr := string(body)
|
||||||
|
httpRes.Body = &bodyStr
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpRes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInterceptItem(item intercept.Item) (req HTTPRequest, err error) {
|
||||||
|
if item.Response != nil {
|
||||||
|
req, err = parseHTTPRequest(item.Response.Request)
|
||||||
|
if err != nil {
|
||||||
|
return HTTPRequest{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := parseHTTPResponse(item.Response)
|
||||||
|
if err != nil {
|
||||||
|
return HTTPRequest{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Response = &res
|
||||||
|
} else if item.Request != nil {
|
||||||
|
req, err = parseHTTPRequest(item.Request)
|
||||||
|
if err != nil {
|
||||||
|
return HTTPRequest{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseProject(projSvc proj.Service, p proj.Project) Project {
|
func parseProject(projSvc proj.Service, p proj.Project) Project {
|
||||||
project := Project{
|
project := Project{
|
||||||
ID: p.ID,
|
ID: p.ID,
|
||||||
|
@ -128,6 +128,19 @@ type HttpRequest {
|
|||||||
proto: HttpProtocol!
|
proto: HttpProtocol!
|
||||||
headers: [HttpHeader!]!
|
headers: [HttpHeader!]!
|
||||||
body: String
|
body: String
|
||||||
|
response: HttpResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpResponse {
|
||||||
|
"""
|
||||||
|
Will be the same ID as its related request ID.
|
||||||
|
"""
|
||||||
|
id: ID!
|
||||||
|
proto: HttpProtocol!
|
||||||
|
statusCode: Int!
|
||||||
|
statusReason: String!
|
||||||
|
body: String
|
||||||
|
headers: [HttpHeader!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ModifyRequestInput {
|
input ModifyRequestInput {
|
||||||
@ -137,6 +150,7 @@ input ModifyRequestInput {
|
|||||||
proto: HttpProtocol!
|
proto: HttpProtocol!
|
||||||
headers: [HttpHeaderInput!]
|
headers: [HttpHeaderInput!]
|
||||||
body: String
|
body: String
|
||||||
|
modifyResponse: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModifyRequestResult {
|
type ModifyRequestResult {
|
||||||
@ -147,6 +161,23 @@ type CancelRequestResult {
|
|||||||
success: Boolean!
|
success: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input ModifyResponseInput {
|
||||||
|
requestID: ID!
|
||||||
|
proto: HttpProtocol!
|
||||||
|
headers: [HttpHeaderInput!]
|
||||||
|
body: String
|
||||||
|
statusCode: Int!
|
||||||
|
statusReason: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModifyResponseResult {
|
||||||
|
success: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
|
type CancelResponseResult {
|
||||||
|
success: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
input UpdateInterceptSettingsInput {
|
input UpdateInterceptSettingsInput {
|
||||||
enabled: Boolean!
|
enabled: Boolean!
|
||||||
requestFilter: String
|
requestFilter: String
|
||||||
@ -187,6 +218,8 @@ type Mutation {
|
|||||||
deleteSenderRequests: DeleteSenderRequestsResult!
|
deleteSenderRequests: DeleteSenderRequestsResult!
|
||||||
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
|
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
|
||||||
cancelRequest(id: ID!): CancelRequestResult!
|
cancelRequest(id: ID!): CancelRequestResult!
|
||||||
|
modifyResponse(response: ModifyResponseInput!): ModifyResponseResult!
|
||||||
|
cancelResponse(requestID: ID!): CancelResponseResult!
|
||||||
updateInterceptSettings(
|
updateInterceptSettings(
|
||||||
input: UpdateInterceptSettingsInput!
|
input: UpdateInterceptSettingsInput!
|
||||||
): InterceptSettings!
|
): InterceptSettings!
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/dstotijn/hetty/pkg/search"
|
"github.com/dstotijn/hetty/pkg/search"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:unparam
|
||||||
var reqFilterKeyFns = map[string]func(req *http.Request) (string, error){
|
var reqFilterKeyFns = map[string]func(req *http.Request) (string, error){
|
||||||
"proto": func(req *http.Request) (string, error) { return req.Proto, nil },
|
"proto": func(req *http.Request) (string, error) { return req.Proto, nil },
|
||||||
"url": func(req *http.Request) (string, error) {
|
"url": func(req *http.Request) (string, error) {
|
||||||
|
@ -19,8 +19,13 @@ var (
|
|||||||
ErrRequestAborted = errors.New("intercept: request was aborted")
|
ErrRequestAborted = errors.New("intercept: request was aborted")
|
||||||
ErrRequestNotFound = errors.New("intercept: request not found")
|
ErrRequestNotFound = errors.New("intercept: request not found")
|
||||||
ErrRequestDone = errors.New("intercept: request is done")
|
ErrRequestDone = errors.New("intercept: request is done")
|
||||||
|
ErrResponseNotFound = errors.New("intercept: response not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type contextKey int
|
||||||
|
|
||||||
|
const interceptResponseKey contextKey = 0
|
||||||
|
|
||||||
// Request represents a server received HTTP request, alongside a channel for sending a modified version of it to the
|
// Request represents a server received HTTP request, alongside a channel for sending a modified version of it to the
|
||||||
// routine that's awaiting it. Also contains a channel for receiving a cancellation signal.
|
// routine that's awaiting it. Also contains a channel for receiving a cancellation signal.
|
||||||
type Request struct {
|
type Request struct {
|
||||||
@ -29,9 +34,24 @@ type Request struct {
|
|||||||
done <-chan struct{}
|
done <-chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Response represents an HTTP response from a proxied request, alongside a channel for sending a modified version of it
|
||||||
|
// to the routine that's awaiting it. Also contains a channel for receiving a cancellation signal.
|
||||||
|
type Response struct {
|
||||||
|
res *http.Response
|
||||||
|
ch chan<- *http.Response
|
||||||
|
done <-chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
Request *http.Request
|
||||||
|
Response *http.Response
|
||||||
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
mu *sync.RWMutex
|
reqMu *sync.RWMutex
|
||||||
|
resMu *sync.RWMutex
|
||||||
requests map[ulid.ULID]Request
|
requests map[ulid.ULID]Request
|
||||||
|
responses map[ulid.ULID]Response
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
enabled bool
|
enabled bool
|
||||||
reqFilter search.Expression
|
reqFilter search.Expression
|
||||||
@ -48,8 +68,10 @@ type RequestIDs []ulid.ULID
|
|||||||
|
|
||||||
func NewService(cfg Config) *Service {
|
func NewService(cfg Config) *Service {
|
||||||
s := &Service{
|
s := &Service{
|
||||||
mu: &sync.RWMutex{},
|
reqMu: &sync.RWMutex{},
|
||||||
|
resMu: &sync.RWMutex{},
|
||||||
requests: make(map[ulid.ULID]Request),
|
requests: make(map[ulid.ULID]Request),
|
||||||
|
responses: make(map[ulid.ULID]Response),
|
||||||
logger: cfg.Logger,
|
logger: cfg.Logger,
|
||||||
enabled: cfg.Enabled,
|
enabled: cfg.Enabled,
|
||||||
reqFilter: cfg.RequestFilter,
|
reqFilter: cfg.RequestFilter,
|
||||||
@ -62,13 +84,12 @@ func NewService(cfg Config) *Service {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestModifier is a proxy.RequestModifyMiddleware for intercepting HTTP
|
// RequestModifier is a proxy.RequestModifyMiddleware for intercepting HTTP requests.
|
||||||
// requests.
|
|
||||||
func (svc *Service) RequestModifier(next proxy.RequestModifyFunc) proxy.RequestModifyFunc {
|
func (svc *Service) RequestModifier(next proxy.RequestModifyFunc) proxy.RequestModifyFunc {
|
||||||
return func(req *http.Request) {
|
return func(req *http.Request) {
|
||||||
// This is a blocking operation, that gets unblocked when either a modified request is returned or an error
|
// This is a blocking operation, that gets unblocked when either a modified request is returned or an error
|
||||||
// (typically `context.Canceled`).
|
// (typically `context.Canceled`).
|
||||||
modifiedReq, err := svc.Intercept(req.Context(), req)
|
modifiedReq, err := svc.InterceptRequest(req.Context(), req)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, ErrRequestAborted):
|
case errors.Is(err, ErrRequestAborted):
|
||||||
@ -86,24 +107,24 @@ func (svc *Service) RequestModifier(next proxy.RequestModifyFunc) proxy.RequestM
|
|||||||
svc.logger.Errorw("Failed to intercept request.",
|
svc.logger.Errorw("Failed to intercept request.",
|
||||||
"error", err)
|
"error", err)
|
||||||
default:
|
default:
|
||||||
*req = *modifiedReq.WithContext(req.Context())
|
*req = *modifiedReq
|
||||||
next(req)
|
next(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intercept adds an HTTP request to an array of pending intercepted requests, alongside channels used for sending a
|
// InterceptRequest adds an HTTP request to an array of pending intercepted requests, alongside channels used for
|
||||||
// cancellation signal and receiving a modified request. It's safe for concurrent use.
|
// sending a cancellation signal and receiving a modified request. It's safe for concurrent use.
|
||||||
func (svc *Service) Intercept(ctx context.Context, req *http.Request) (*http.Request, error) {
|
func (svc *Service) InterceptRequest(ctx context.Context, req *http.Request) (*http.Request, error) {
|
||||||
reqID, ok := proxy.RequestIDFromContext(ctx)
|
reqID, ok := proxy.RequestIDFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
svc.logger.Errorw("Failed to intercept: request doesn't have an ID.")
|
svc.logger.Errorw("Failed to intercept: context doesn't have an ID.")
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !svc.enabled {
|
if !svc.enabled {
|
||||||
// If intercept is disabled, return the incoming request as-is.
|
// If request intercept is disabled, return the incoming request as-is.
|
||||||
svc.logger.Debugw("Bypassed interception: module disabled.")
|
svc.logger.Debugw("Bypassed request interception: feature disabled.")
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +137,7 @@ func (svc *Service) Intercept(ctx context.Context, req *http.Request) (*http.Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !match {
|
if !match {
|
||||||
svc.logger.Debugw("Bypassed interception: request rules don't match.")
|
svc.logger.Debugw("Bypassed request interception: request rules don't match.")
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,20 +145,20 @@ func (svc *Service) Intercept(ctx context.Context, req *http.Request) (*http.Req
|
|||||||
ch := make(chan *http.Request)
|
ch := make(chan *http.Request)
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
svc.mu.Lock()
|
svc.reqMu.Lock()
|
||||||
svc.requests[reqID] = Request{
|
svc.requests[reqID] = Request{
|
||||||
req: req,
|
req: req,
|
||||||
ch: ch,
|
ch: ch,
|
||||||
done: done,
|
done: done,
|
||||||
}
|
}
|
||||||
svc.mu.Unlock()
|
svc.reqMu.Unlock()
|
||||||
|
|
||||||
// Whatever happens next (modified request returned, or a context cancelled error), any blocked channel senders
|
// Whatever happens next (modified request returned, or a context cancelled error), any blocked channel senders
|
||||||
// should be unblocked, and the request should be removed from the requests queue.
|
// should be unblocked, and the request should be removed from the requests queue.
|
||||||
defer func() {
|
defer func() {
|
||||||
close(done)
|
close(done)
|
||||||
svc.mu.Lock()
|
svc.reqMu.Lock()
|
||||||
defer svc.mu.Unlock()
|
defer svc.reqMu.Unlock()
|
||||||
delete(svc.requests, reqID)
|
delete(svc.requests, reqID)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -155,15 +176,20 @@ func (svc *Service) Intercept(ctx context.Context, req *http.Request) (*http.Req
|
|||||||
|
|
||||||
// ModifyRequest sends a modified HTTP request to the related channel, or returns ErrRequestDone when the request was
|
// ModifyRequest sends a modified HTTP request to the related channel, or returns ErrRequestDone when the request was
|
||||||
// cancelled. It's safe for concurrent use.
|
// cancelled. It's safe for concurrent use.
|
||||||
func (svc *Service) ModifyRequest(reqID ulid.ULID, modReq *http.Request) error {
|
func (svc *Service) ModifyRequest(reqID ulid.ULID, modReq *http.Request, modifyResponse *bool) error {
|
||||||
svc.mu.RLock()
|
svc.reqMu.RLock()
|
||||||
req, ok := svc.requests[reqID]
|
req, ok := svc.requests[reqID]
|
||||||
svc.mu.RUnlock()
|
svc.reqMu.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrRequestNotFound
|
return ErrRequestNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*modReq = *modReq.WithContext(req.req.Context())
|
||||||
|
if modifyResponse != nil {
|
||||||
|
*modReq = *modReq.WithContext(WithInterceptResponse(modReq.Context(), *modifyResponse))
|
||||||
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-req.done:
|
case <-req.done:
|
||||||
return ErrRequestDone
|
return ErrRequestDone
|
||||||
@ -174,12 +200,12 @@ func (svc *Service) ModifyRequest(reqID ulid.ULID, modReq *http.Request) error {
|
|||||||
|
|
||||||
// CancelRequest ensures an intercepted request is dropped.
|
// CancelRequest ensures an intercepted request is dropped.
|
||||||
func (svc *Service) CancelRequest(reqID ulid.ULID) error {
|
func (svc *Service) CancelRequest(reqID ulid.ULID) error {
|
||||||
return svc.ModifyRequest(reqID, nil)
|
return svc.ModifyRequest(reqID, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *Service) ClearRequests() {
|
func (svc *Service) ClearRequests() {
|
||||||
svc.mu.Lock()
|
svc.reqMu.Lock()
|
||||||
defer svc.mu.Unlock()
|
defer svc.reqMu.Unlock()
|
||||||
|
|
||||||
for _, req := range svc.requests {
|
for _, req := range svc.requests {
|
||||||
select {
|
select {
|
||||||
@ -189,47 +215,94 @@ func (svc *Service) ClearRequests() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requests returns a list of pending intercepted requests. It's safe for concurrent use.
|
func (svc *Service) ClearResponses() {
|
||||||
func (svc *Service) Requests() []*http.Request {
|
svc.resMu.Lock()
|
||||||
svc.mu.RLock()
|
defer svc.resMu.Unlock()
|
||||||
defer svc.mu.RUnlock()
|
|
||||||
|
for _, res := range svc.responses {
|
||||||
|
select {
|
||||||
|
case <-res.done:
|
||||||
|
case res.ch <- nil:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items returns a list of pending items (requests and responses). It's safe for concurrent use.
|
||||||
|
func (svc *Service) Items() []Item {
|
||||||
|
svc.reqMu.RLock()
|
||||||
|
defer svc.reqMu.RUnlock()
|
||||||
|
|
||||||
|
svc.resMu.RLock()
|
||||||
|
defer svc.resMu.RUnlock()
|
||||||
|
|
||||||
|
reqIDs := make([]ulid.ULID, 0, len(svc.requests)+len(svc.responses))
|
||||||
|
|
||||||
ids := make([]ulid.ULID, 0, len(svc.requests))
|
|
||||||
for id := range svc.requests {
|
for id := range svc.requests {
|
||||||
ids = append(ids, id)
|
reqIDs = append(reqIDs, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(RequestIDs(ids))
|
for id := range svc.responses {
|
||||||
|
reqIDs = append(reqIDs, id)
|
||||||
reqs := make([]*http.Request, len(ids))
|
|
||||||
for i, id := range ids {
|
|
||||||
reqs[i] = svc.requests[id].req
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return reqs
|
sort.Sort(RequestIDs(reqIDs))
|
||||||
|
|
||||||
|
items := make([]Item, len(reqIDs))
|
||||||
|
|
||||||
|
for i, id := range reqIDs {
|
||||||
|
item := Item{}
|
||||||
|
|
||||||
|
if req, ok := svc.requests[id]; ok {
|
||||||
|
item.Request = req.req
|
||||||
|
}
|
||||||
|
|
||||||
|
if res, ok := svc.responses[id]; ok {
|
||||||
|
item.Response = res.res
|
||||||
|
}
|
||||||
|
|
||||||
|
items[i] = item
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *Service) UpdateSettings(settings Settings) {
|
func (svc *Service) UpdateSettings(settings Settings) {
|
||||||
// When updating from `enabled` -> `disabled`, clear any pending reqs.
|
// When updating from `enabled` -> `disabled`, clear any pending reqs.
|
||||||
if svc.enabled && !settings.Enabled {
|
if svc.enabled && !settings.Enabled {
|
||||||
svc.ClearRequests()
|
svc.ClearRequests()
|
||||||
|
svc.ClearResponses()
|
||||||
}
|
}
|
||||||
|
|
||||||
svc.enabled = settings.Enabled
|
svc.enabled = settings.Enabled
|
||||||
svc.reqFilter = settings.RequestFilter
|
svc.reqFilter = settings.RequestFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request returns an intercepted request by ID. It's safe for concurrent use.
|
// ItemByID returns an intercepted item (request and possible response) by ID. It's safe for concurrent use.
|
||||||
func (svc *Service) RequestByID(id ulid.ULID) (*http.Request, error) {
|
func (svc *Service) ItemByID(id ulid.ULID) (Item, error) {
|
||||||
svc.mu.RLock()
|
svc.reqMu.RLock()
|
||||||
defer svc.mu.RUnlock()
|
defer svc.reqMu.RUnlock()
|
||||||
|
|
||||||
req, ok := svc.requests[id]
|
svc.resMu.RLock()
|
||||||
if !ok {
|
defer svc.resMu.RUnlock()
|
||||||
return nil, ErrRequestNotFound
|
|
||||||
|
item := Item{}
|
||||||
|
found := false
|
||||||
|
|
||||||
|
if req, ok := svc.requests[id]; ok {
|
||||||
|
item.Request = req.req
|
||||||
|
found = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return req.req, nil
|
if res, ok := svc.responses[id]; ok {
|
||||||
|
item.Response = res.res
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return Item{}, ErrRequestNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ids RequestIDs) Len() int {
|
func (ids RequestIDs) Len() int {
|
||||||
@ -243,3 +316,124 @@ func (ids RequestIDs) Less(i, j int) bool {
|
|||||||
func (ids RequestIDs) Swap(i, j int) {
|
func (ids RequestIDs) Swap(i, j int) {
|
||||||
ids[i], ids[j] = ids[j], ids[i]
|
ids[i], ids[j] = ids[j], ids[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithInterceptResponse(ctx context.Context, value bool) context.Context {
|
||||||
|
return context.WithValue(ctx, interceptResponseKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShouldInterceptResponseFromContext(ctx context.Context) (bool, bool) {
|
||||||
|
shouldIntercept, ok := ctx.Value(interceptResponseKey).(bool)
|
||||||
|
return shouldIntercept, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseModifier is a proxy.ResponseModifyMiddleware for intercepting HTTP responses.
|
||||||
|
func (svc *Service) ResponseModifier(next proxy.ResponseModifyFunc) proxy.ResponseModifyFunc {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
// This is a blocking operation, that gets unblocked when either a modified response is returned or an error.
|
||||||
|
//nolint:bodyclose
|
||||||
|
modifiedRes, err := svc.InterceptResponse(res.Request.Context(), res)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to intercept response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*res = *modifiedRes
|
||||||
|
|
||||||
|
return next(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterceptResponse adds an HTTP response to an array of pending intercepted responses, alongside channels used for
|
||||||
|
// sending a cancellation signal and receiving a modified response. It's safe for concurrent use.
|
||||||
|
func (svc *Service) InterceptResponse(ctx context.Context, res *http.Response) (*http.Response, error) {
|
||||||
|
reqID, ok := proxy.RequestIDFromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
svc.logger.Errorw("Failed to intercept: context doesn't have an ID.")
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldIntercept, ok := ShouldInterceptResponseFromContext(ctx)
|
||||||
|
if ok && !shouldIntercept {
|
||||||
|
// If the related request explicitly disabled response intercept, return the response as-is.
|
||||||
|
svc.logger.Debugw("Bypassed response interception: related request explicitly disabled response intercept.")
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !svc.enabled {
|
||||||
|
// If the feature is disabled, return the response as-is.
|
||||||
|
svc.logger.Debugw("Bypassed response interception: feature disabled.")
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// if svc.reqFilter != nil {
|
||||||
|
// match, err := MatchRequestFilter(req, svc.reqFilter)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("intercept: failed to match request rules for request (id: %v): %w",
|
||||||
|
// reqID.String(), err,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if !match {
|
||||||
|
// svc.logger.Debugw("Bypassed interception: request rules don't match.")
|
||||||
|
// return req, nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
ch := make(chan *http.Response)
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
svc.resMu.Lock()
|
||||||
|
svc.responses[reqID] = Response{
|
||||||
|
res: res,
|
||||||
|
ch: ch,
|
||||||
|
done: done,
|
||||||
|
}
|
||||||
|
svc.resMu.Unlock()
|
||||||
|
|
||||||
|
// Whatever happens next (modified response returned, or a context cancelled error), any blocked channel senders
|
||||||
|
// should be unblocked, and the response should be removed from the responses queue.
|
||||||
|
defer func() {
|
||||||
|
close(done)
|
||||||
|
svc.resMu.Lock()
|
||||||
|
defer svc.resMu.Unlock()
|
||||||
|
delete(svc.responses, reqID)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case modRes := <-ch:
|
||||||
|
if modRes == nil {
|
||||||
|
return nil, ErrRequestAborted
|
||||||
|
}
|
||||||
|
|
||||||
|
return modRes, nil
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyResponse sends a modified HTTP response to the related channel, or returns ErrRequestDone when the related
|
||||||
|
// request was cancelled. It's safe for concurrent use.
|
||||||
|
func (svc *Service) ModifyResponse(reqID ulid.ULID, modRes *http.Response) error {
|
||||||
|
svc.resMu.RLock()
|
||||||
|
res, ok := svc.responses[reqID]
|
||||||
|
svc.resMu.RUnlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return ErrRequestNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if modRes != nil {
|
||||||
|
modRes.Request = res.res.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-res.done:
|
||||||
|
return ErrRequestDone
|
||||||
|
case res.ch <- modRes:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelResponse ensures an intercepted response is dropped.
|
||||||
|
func (svc *Service) CancelResponse(reqID ulid.ULID) error {
|
||||||
|
return svc.ModifyResponse(reqID, nil)
|
||||||
|
}
|
||||||
|
@ -34,7 +34,7 @@ func TestRequestModifier(t *testing.T) {
|
|||||||
|
|
||||||
reqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)
|
reqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)
|
||||||
|
|
||||||
err := svc.ModifyRequest(reqID, nil)
|
err := svc.ModifyRequest(reqID, nil, nil)
|
||||||
if !errors.Is(err, intercept.ErrRequestNotFound) {
|
if !errors.Is(err, intercept.ErrRequestNotFound) {
|
||||||
t.Fatalf("expected `intercept.ErrRequestNotFound`, got: %v", err)
|
t.Fatalf("expected `intercept.ErrRequestNotFound`, got: %v", err)
|
||||||
}
|
}
|
||||||
@ -65,7 +65,10 @@ func TestRequestModifier(t *testing.T) {
|
|||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
err := svc.ModifyRequest(reqID, nil)
|
modReq := req.Clone(req.Context())
|
||||||
|
modReq.Header.Set("X-Foo", "bar")
|
||||||
|
|
||||||
|
err := svc.ModifyRequest(reqID, modReq, nil)
|
||||||
if !errors.Is(err, intercept.ErrRequestDone) {
|
if !errors.Is(err, intercept.ErrRequestDone) {
|
||||||
t.Fatalf("expected `intercept.ErrRequestDone`, got: %v", err)
|
t.Fatalf("expected `intercept.ErrRequestDone`, got: %v", err)
|
||||||
}
|
}
|
||||||
@ -107,7 +110,7 @@ func TestRequestModifier(t *testing.T) {
|
|||||||
// array of intercepted reqs.
|
// array of intercepted reqs.
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
err := svc.ModifyRequest(reqID, modReq)
|
err := svc.ModifyRequest(reqID, modReq, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,9 @@ import (
|
|||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dstotijn/hetty/pkg/log"
|
|
||||||
"github.com/oklog/ulid"
|
"github.com/oklog/ulid"
|
||||||
|
|
||||||
|
"github.com/dstotijn/hetty/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:gosec
|
//nolint:gosec
|
||||||
@ -189,9 +190,12 @@ func (p *Proxy) clientTLSConn(conn net.Conn) (*tls.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proxy) errorHandler(w http.ResponseWriter, r *http.Request, err error) {
|
func (p *Proxy) errorHandler(w http.ResponseWriter, r *http.Request, err error) {
|
||||||
if !errors.Is(err, context.Canceled) {
|
switch {
|
||||||
|
case !errors.Is(err, context.Canceled):
|
||||||
p.logger.Errorw("Failed to proxy request.",
|
p.logger.Errorw("Failed to proxy request.",
|
||||||
"error", err)
|
"error", err)
|
||||||
|
case errors.Is(err, context.Canceled):
|
||||||
|
p.logger.Debugw("Proxy request was cancelled.")
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusBadGateway)
|
w.WriteHeader(http.StatusBadGateway)
|
||||||
|
Reference in New Issue
Block a user