mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-06-30 10:01:42 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a9be57e6d9 | |||
| c3aecfdc0c |
@@ -13,6 +13,7 @@ import {
|
|||||||
modelSupportsSetting,
|
modelSupportsSetting,
|
||||||
type RequestSettingDefinition,
|
type RequestSettingDefinition,
|
||||||
SETTING_FOLLOW_REDIRECTS,
|
SETTING_FOLLOW_REDIRECTS,
|
||||||
|
SETTING_REQUEST_MESSAGE_SIZE,
|
||||||
SETTING_REQUEST_TIMEOUT,
|
SETTING_REQUEST_TIMEOUT,
|
||||||
SETTING_SEND_COOKIES,
|
SETTING_SEND_COOKIES,
|
||||||
SETTING_STORE_COOKIES,
|
SETTING_STORE_COOKIES,
|
||||||
@@ -22,21 +23,45 @@ import { Checkbox } from "./core/Checkbox";
|
|||||||
import { PlainInput } from "./core/PlainInput";
|
import { PlainInput } from "./core/PlainInput";
|
||||||
import {
|
import {
|
||||||
SettingOverrideRow,
|
SettingOverrideRow,
|
||||||
|
SettingRow,
|
||||||
SettingRowBoolean,
|
SettingRowBoolean,
|
||||||
SettingRowNumber,
|
SettingRowNumber,
|
||||||
SettingsList,
|
SettingsList,
|
||||||
SettingsSection,
|
SettingsSection,
|
||||||
} from "./core/SettingRow";
|
} from "./core/SettingRow";
|
||||||
|
|
||||||
|
const BYTES_PER_MB = 1024 * 1024;
|
||||||
|
const MAX_REQUEST_MESSAGE_SIZE_BYTES = 2_147_483_647;
|
||||||
|
const MAX_MESSAGE_SIZE_MB = MAX_REQUEST_MESSAGE_SIZE_BYTES / BYTES_PER_MB;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
showSectionTitles?: boolean;
|
showSectionTitles?: boolean;
|
||||||
model: ModelWithSettings;
|
model: ModelWithSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModelWithSettings = Workspace | Folder | HttpRequest | WebsocketRequest | GrpcRequest;
|
type ModelWithSettings =
|
||||||
|
| Workspace
|
||||||
|
| Folder
|
||||||
|
| HttpRequest
|
||||||
|
| WebsocketRequest
|
||||||
|
| GrpcRequest;
|
||||||
type ModelWithHttpSettings = Workspace | Folder | HttpRequest;
|
type ModelWithHttpSettings = Workspace | Folder | HttpRequest;
|
||||||
type ModelWithTlsSettings = Workspace | Folder | HttpRequest | WebsocketRequest | GrpcRequest;
|
type ModelWithTlsSettings =
|
||||||
type ModelWithCookieSettings = Workspace | Folder | HttpRequest | WebsocketRequest;
|
| Workspace
|
||||||
|
| Folder
|
||||||
|
| HttpRequest
|
||||||
|
| WebsocketRequest
|
||||||
|
| GrpcRequest;
|
||||||
|
type ModelWithCookieSettings =
|
||||||
|
| Workspace
|
||||||
|
| Folder
|
||||||
|
| HttpRequest
|
||||||
|
| WebsocketRequest;
|
||||||
|
type ModelWithMessageSizeSettings =
|
||||||
|
| Workspace
|
||||||
|
| Folder
|
||||||
|
| WebsocketRequest
|
||||||
|
| GrpcRequest;
|
||||||
type BooleanSetting = boolean | InheritedBoolSetting;
|
type BooleanSetting = boolean | InheritedBoolSetting;
|
||||||
type IntegerSetting = number | InheritedIntSetting;
|
type IntegerSetting = number | InheritedIntSetting;
|
||||||
type CookieSettingsPatch = {
|
type CookieSettingsPatch = {
|
||||||
@@ -50,12 +75,19 @@ type HttpSettingsPatch = {
|
|||||||
type TlsSettingsPatch = {
|
type TlsSettingsPatch = {
|
||||||
settingValidateCertificates?: ModelWithTlsSettings["settingValidateCertificates"];
|
settingValidateCertificates?: ModelWithTlsSettings["settingValidateCertificates"];
|
||||||
};
|
};
|
||||||
|
type MessageSizeSettingsPatch = {
|
||||||
|
settingRequestMessageSize?: ModelWithMessageSizeSettings["settingRequestMessageSize"];
|
||||||
|
};
|
||||||
|
|
||||||
export function ModelSettingsEditor({ model, showSectionTitles = false }: Props) {
|
export function ModelSettingsEditor({
|
||||||
|
model,
|
||||||
|
showSectionTitles = false,
|
||||||
|
}: Props) {
|
||||||
const ancestors = useModelAncestors(model);
|
const ancestors = useModelAncestors(model);
|
||||||
const supportsHttpSettings = modelSupportsHttpSettings(model);
|
const supportsHttpSettings = modelSupportsHttpSettings(model);
|
||||||
const supportsCookieSettings = modelSupportsCookieSettings(model);
|
const supportsCookieSettings = modelSupportsCookieSettings(model);
|
||||||
const supportsTlsSettings = modelSupportsTlsSettings(model);
|
const supportsTlsSettings = modelSupportsTlsSettings(model);
|
||||||
|
const supportsMessageSizeSettings = modelSupportsMessageSizeSettings(model);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsList className="space-y-8">
|
<SettingsList className="space-y-8">
|
||||||
@@ -77,6 +109,22 @@ export function ModelSettingsEditor({ model, showSectionTitles = false }: Props)
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{supportsMessageSizeSettings && (
|
||||||
|
<MessageSizeSettingRow
|
||||||
|
settingDefinition={SETTING_REQUEST_MESSAGE_SIZE}
|
||||||
|
setting={model.settingRequestMessageSize}
|
||||||
|
inheritedValue={resolveInheritedValue(
|
||||||
|
ancestors,
|
||||||
|
SETTING_REQUEST_MESSAGE_SIZE.modelKey,
|
||||||
|
model.settingRequestMessageSize,
|
||||||
|
)}
|
||||||
|
onChange={(settingRequestMessageSize) =>
|
||||||
|
patchMessageSizeSettings(model, {
|
||||||
|
settingRequestMessageSize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<BooleanSettingRow
|
<BooleanSettingRow
|
||||||
settingDefinition={SETTING_VALIDATE_CERTIFICATES}
|
settingDefinition={SETTING_VALIDATE_CERTIFICATES}
|
||||||
setting={model.settingValidateCertificates}
|
setting={model.settingValidateCertificates}
|
||||||
@@ -110,7 +158,9 @@ export function ModelSettingsEditor({ model, showSectionTitles = false }: Props)
|
|||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
)}
|
)}
|
||||||
{supportsCookieSettings && (
|
{supportsCookieSettings && (
|
||||||
<SettingsSection title={supportsTlsSettings || showSectionTitles ? "Cookies" : null}>
|
<SettingsSection
|
||||||
|
title={supportsTlsSettings || showSectionTitles ? "Cookies" : null}
|
||||||
|
>
|
||||||
<BooleanSettingRow
|
<BooleanSettingRow
|
||||||
settingDefinition={SETTING_SEND_COOKIES}
|
settingDefinition={SETTING_SEND_COOKIES}
|
||||||
setting={model.settingSendCookies}
|
setting={model.settingSendCookies}
|
||||||
@@ -158,46 +208,93 @@ export function countOverriddenSettings(model: ModelWithSettings) {
|
|||||||
settings.push(model.settingFollowRedirects, model.settingRequestTimeout);
|
settings.push(model.settingFollowRedirects, model.settingRequestTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings.filter((setting) => isInheritedSetting(setting) && setting.enabled === true)
|
if (modelSupportsMessageSizeSettings(model)) {
|
||||||
.length;
|
settings.push(model.settingRequestMessageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings.filter(
|
||||||
|
(setting) => isInheritedSetting(setting) && setting.enabled === true,
|
||||||
|
).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function patchCookieSettings(model: ModelWithCookieSettings, patch: Partial<CookieSettingsPatch>) {
|
function patchCookieSettings(
|
||||||
if (model.model === "workspace") return patchModel(model, patch as Partial<Workspace>);
|
model: ModelWithCookieSettings,
|
||||||
if (model.model === "folder") return patchModel(model, patch as Partial<Folder>);
|
patch: Partial<CookieSettingsPatch>,
|
||||||
if (model.model === "http_request") return patchModel(model, patch as Partial<HttpRequest>);
|
) {
|
||||||
|
if (model.model === "workspace")
|
||||||
|
return patchModel(model, patch as Partial<Workspace>);
|
||||||
|
if (model.model === "folder")
|
||||||
|
return patchModel(model, patch as Partial<Folder>);
|
||||||
|
if (model.model === "http_request")
|
||||||
|
return patchModel(model, patch as Partial<HttpRequest>);
|
||||||
if (model.model === "websocket_request")
|
if (model.model === "websocket_request")
|
||||||
return patchModel(model, patch as Partial<WebsocketRequest>);
|
return patchModel(model, patch as Partial<WebsocketRequest>);
|
||||||
throw new Error("Unsupported cookie settings model");
|
throw new Error("Unsupported cookie settings model");
|
||||||
}
|
}
|
||||||
|
|
||||||
function patchHttpSettings(model: ModelWithHttpSettings, patch: Partial<HttpSettingsPatch>) {
|
function patchHttpSettings(
|
||||||
if (model.model === "workspace") return patchModel(model, patch as Partial<Workspace>);
|
model: ModelWithHttpSettings,
|
||||||
if (model.model === "folder") return patchModel(model, patch as Partial<Folder>);
|
patch: Partial<HttpSettingsPatch>,
|
||||||
|
) {
|
||||||
|
if (model.model === "workspace")
|
||||||
|
return patchModel(model, patch as Partial<Workspace>);
|
||||||
|
if (model.model === "folder")
|
||||||
|
return patchModel(model, patch as Partial<Folder>);
|
||||||
return patchModel(model, patch as Partial<HttpRequest>);
|
return patchModel(model, patch as Partial<HttpRequest>);
|
||||||
}
|
}
|
||||||
|
|
||||||
function patchTlsSettings(model: ModelWithTlsSettings, patch: Partial<TlsSettingsPatch>) {
|
function patchTlsSettings(
|
||||||
if (model.model === "workspace") return patchModel(model, patch as Partial<Workspace>);
|
model: ModelWithTlsSettings,
|
||||||
if (model.model === "folder") return patchModel(model, patch as Partial<Folder>);
|
patch: Partial<TlsSettingsPatch>,
|
||||||
if (model.model === "http_request") return patchModel(model, patch as Partial<HttpRequest>);
|
) {
|
||||||
|
if (model.model === "workspace")
|
||||||
|
return patchModel(model, patch as Partial<Workspace>);
|
||||||
|
if (model.model === "folder")
|
||||||
|
return patchModel(model, patch as Partial<Folder>);
|
||||||
|
if (model.model === "http_request")
|
||||||
|
return patchModel(model, patch as Partial<HttpRequest>);
|
||||||
if (model.model === "websocket_request")
|
if (model.model === "websocket_request")
|
||||||
return patchModel(model, patch as Partial<WebsocketRequest>);
|
return patchModel(model, patch as Partial<WebsocketRequest>);
|
||||||
return patchModel(model, patch as Partial<GrpcRequest>);
|
return patchModel(model, patch as Partial<GrpcRequest>);
|
||||||
}
|
}
|
||||||
|
|
||||||
function modelSupportsHttpSettings(model: ModelWithSettings): model is ModelWithHttpSettings {
|
function patchMessageSizeSettings(
|
||||||
|
model: ModelWithMessageSizeSettings,
|
||||||
|
patch: Partial<MessageSizeSettingsPatch>,
|
||||||
|
) {
|
||||||
|
if (model.model === "workspace")
|
||||||
|
return patchModel(model, patch as Partial<Workspace>);
|
||||||
|
if (model.model === "folder")
|
||||||
|
return patchModel(model, patch as Partial<Folder>);
|
||||||
|
if (model.model === "websocket_request")
|
||||||
|
return patchModel(model, patch as Partial<WebsocketRequest>);
|
||||||
|
return patchModel(model, patch as Partial<GrpcRequest>);
|
||||||
|
}
|
||||||
|
|
||||||
|
function modelSupportsHttpSettings(
|
||||||
|
model: ModelWithSettings,
|
||||||
|
): model is ModelWithHttpSettings {
|
||||||
return modelSupportsSetting(model, SETTING_REQUEST_TIMEOUT);
|
return modelSupportsSetting(model, SETTING_REQUEST_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
function modelSupportsCookieSettings(model: ModelWithSettings): model is ModelWithCookieSettings {
|
function modelSupportsCookieSettings(
|
||||||
|
model: ModelWithSettings,
|
||||||
|
): model is ModelWithCookieSettings {
|
||||||
return modelSupportsSetting(model, SETTING_SEND_COOKIES);
|
return modelSupportsSetting(model, SETTING_SEND_COOKIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
function modelSupportsTlsSettings(model: ModelWithSettings): model is ModelWithTlsSettings {
|
function modelSupportsTlsSettings(
|
||||||
|
model: ModelWithSettings,
|
||||||
|
): model is ModelWithTlsSettings {
|
||||||
return modelSupportsSetting(model, SETTING_VALIDATE_CERTIFICATES);
|
return modelSupportsSetting(model, SETTING_VALIDATE_CERTIFICATES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function modelSupportsMessageSizeSettings(
|
||||||
|
model: ModelWithSettings,
|
||||||
|
): model is ModelWithMessageSizeSettings {
|
||||||
|
return modelSupportsSetting(model, SETTING_REQUEST_MESSAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
function BooleanSettingRow({
|
function BooleanSettingRow({
|
||||||
inheritedValue,
|
inheritedValue,
|
||||||
setting,
|
setting,
|
||||||
@@ -211,7 +308,11 @@ function BooleanSettingRow({
|
|||||||
}) {
|
}) {
|
||||||
const inherited = isInheritedSetting(setting);
|
const inherited = isInheritedSetting(setting);
|
||||||
const overridden = inherited ? setting.enabled === true : false;
|
const overridden = inherited ? setting.enabled === true : false;
|
||||||
const value = inherited ? (overridden ? setting.value : inheritedValue) : setting;
|
const value = inherited
|
||||||
|
? overridden
|
||||||
|
? setting.value
|
||||||
|
: inheritedValue
|
||||||
|
: setting;
|
||||||
|
|
||||||
if (!inherited) {
|
if (!inherited) {
|
||||||
return (
|
return (
|
||||||
@@ -250,12 +351,18 @@ function IntegerSettingRow({
|
|||||||
}: {
|
}: {
|
||||||
inheritedValue: number;
|
inheritedValue: number;
|
||||||
setting: IntegerSetting;
|
setting: IntegerSetting;
|
||||||
settingDefinition: RequestSettingDefinition<"settingRequestTimeout">;
|
settingDefinition: RequestSettingDefinition<
|
||||||
|
"settingRequestTimeout" | "settingRequestMessageSize"
|
||||||
|
>;
|
||||||
onChange: (setting: IntegerSetting) => void;
|
onChange: (setting: IntegerSetting) => void;
|
||||||
}) {
|
}) {
|
||||||
const inherited = isInheritedSetting(setting);
|
const inherited = isInheritedSetting(setting);
|
||||||
const overridden = inherited ? setting.enabled === true : false;
|
const overridden = inherited ? setting.enabled === true : false;
|
||||||
const value = inherited ? (overridden ? setting.value : inheritedValue) : setting;
|
const value = inherited
|
||||||
|
? overridden
|
||||||
|
? setting.value
|
||||||
|
: inheritedValue
|
||||||
|
: setting;
|
||||||
|
|
||||||
if (!inherited) {
|
if (!inherited) {
|
||||||
return (
|
return (
|
||||||
@@ -300,6 +407,99 @@ function IntegerSettingRow({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function MessageSizeSettingRow({
|
||||||
|
inheritedValue,
|
||||||
|
setting,
|
||||||
|
settingDefinition,
|
||||||
|
onChange,
|
||||||
|
}: {
|
||||||
|
inheritedValue: number;
|
||||||
|
setting: IntegerSetting;
|
||||||
|
settingDefinition: RequestSettingDefinition<"settingRequestMessageSize">;
|
||||||
|
onChange: (setting: IntegerSetting) => void;
|
||||||
|
}) {
|
||||||
|
const inherited = isInheritedSetting(setting);
|
||||||
|
const overridden = inherited ? setting.enabled === true : false;
|
||||||
|
const value = inherited
|
||||||
|
? overridden
|
||||||
|
? setting.value
|
||||||
|
: inheritedValue
|
||||||
|
: setting;
|
||||||
|
const displayValue = formatMegabytes(value);
|
||||||
|
const placeholder = formatMegabytes(settingDefinition.defaultValue);
|
||||||
|
|
||||||
|
if (!inherited) {
|
||||||
|
return (
|
||||||
|
<SettingRow
|
||||||
|
title={settingDefinition.title}
|
||||||
|
description={settingDefinition.description}
|
||||||
|
>
|
||||||
|
<MessageSizeInput
|
||||||
|
name={settingDefinition.modelKey}
|
||||||
|
label={settingDefinition.title}
|
||||||
|
value={displayValue}
|
||||||
|
placeholder={placeholder}
|
||||||
|
onChange={(value) => onChange(parseMegabytes(value))}
|
||||||
|
/>
|
||||||
|
</SettingRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingOverrideRow
|
||||||
|
title={settingDefinition.title}
|
||||||
|
description={settingDefinition.description}
|
||||||
|
overridden={overridden}
|
||||||
|
onResetOverride={() => onChange({ ...setting, enabled: false })}
|
||||||
|
>
|
||||||
|
<MessageSizeInput
|
||||||
|
name={settingDefinition.modelKey}
|
||||||
|
label={settingDefinition.title}
|
||||||
|
value={displayValue}
|
||||||
|
placeholder={placeholder}
|
||||||
|
onChange={(value) =>
|
||||||
|
onChange({
|
||||||
|
...setting,
|
||||||
|
enabled: true,
|
||||||
|
value: parseMegabytes(value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</SettingOverrideRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MessageSizeInput({
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
onChange,
|
||||||
|
placeholder,
|
||||||
|
value,
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
name: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
placeholder: string;
|
||||||
|
value: string;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<PlainInput
|
||||||
|
hideLabel
|
||||||
|
name={name}
|
||||||
|
label={label}
|
||||||
|
size="sm"
|
||||||
|
type="number"
|
||||||
|
step={0.1}
|
||||||
|
placeholder={placeholder}
|
||||||
|
defaultValue={value}
|
||||||
|
containerClassName="!w-48"
|
||||||
|
validate={isValidMegabytes}
|
||||||
|
rightSlot={<span className="px-2 text-xs text-text-subtle">MB</span>}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function isInheritedSetting<T>(
|
function isInheritedSetting<T>(
|
||||||
setting: T | { enabled?: boolean; value: T },
|
setting: T | { enabled?: boolean; value: T },
|
||||||
): setting is { enabled?: boolean; value: T } {
|
): setting is { enabled?: boolean; value: T } {
|
||||||
@@ -308,7 +508,7 @@ function isInheritedSetting<T>(
|
|||||||
|
|
||||||
function resolveInheritedValue(
|
function resolveInheritedValue(
|
||||||
ancestors: (Folder | Workspace)[],
|
ancestors: (Folder | Workspace)[],
|
||||||
key: "settingRequestTimeout",
|
key: "settingRequestTimeout" | "settingRequestMessageSize",
|
||||||
fallback: IntegerSetting,
|
fallback: IntegerSetting,
|
||||||
): number;
|
): number;
|
||||||
function resolveInheritedValue(
|
function resolveInheritedValue(
|
||||||
@@ -338,10 +538,36 @@ function resolveInheritedValue(
|
|||||||
type WorkspaceSettings = Pick<
|
type WorkspaceSettings = Pick<
|
||||||
Workspace,
|
Workspace,
|
||||||
| "settingFollowRedirects"
|
| "settingFollowRedirects"
|
||||||
|
| "settingRequestMessageSize"
|
||||||
| "settingRequestTimeout"
|
| "settingRequestTimeout"
|
||||||
| "settingSendCookies"
|
| "settingSendCookies"
|
||||||
| "settingStoreCookies"
|
| "settingStoreCookies"
|
||||||
| "settingValidateCertificates"
|
| "settingValidateCertificates"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type BooleanWorkspaceSettingKey = Exclude<keyof WorkspaceSettings, "settingRequestTimeout">;
|
type BooleanWorkspaceSettingKey = Exclude<
|
||||||
|
keyof WorkspaceSettings,
|
||||||
|
"settingRequestTimeout" | "settingRequestMessageSize"
|
||||||
|
>;
|
||||||
|
|
||||||
|
function formatMegabytes(bytes: number) {
|
||||||
|
const megabytes = bytes / BYTES_PER_MB;
|
||||||
|
return Number.isInteger(megabytes)
|
||||||
|
? `${megabytes}`
|
||||||
|
: megabytes.toFixed(3).replace(/\.?0+$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseMegabytes(value: string) {
|
||||||
|
const megabytes = Number(value);
|
||||||
|
return Number.isFinite(megabytes) ? Math.round(megabytes * BYTES_PER_MB) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidMegabytes(value: string) {
|
||||||
|
if (value === "") return true;
|
||||||
|
const megabytes = Number(value);
|
||||||
|
return (
|
||||||
|
Number.isFinite(megabytes) &&
|
||||||
|
megabytes >= 0 &&
|
||||||
|
megabytes <= MAX_MESSAGE_SIZE_MB
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ export const PlainInput = forwardRef<{ focus: () => void }, PlainInputProps>(fun
|
|||||||
required,
|
required,
|
||||||
rightSlot,
|
rightSlot,
|
||||||
size = "md",
|
size = "md",
|
||||||
|
step,
|
||||||
tint,
|
tint,
|
||||||
type = "text",
|
type = "text",
|
||||||
validate,
|
validate,
|
||||||
@@ -210,6 +211,7 @@ export const PlainInput = forwardRef<{ focus: () => void }, PlainInputProps>(fun
|
|||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
required={required}
|
required={required}
|
||||||
|
step={step}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onKeyDownCapture={onKeyDownCapture}
|
onKeyDownCapture={onKeyDownCapture}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ type ModelType = AnyModel["model"];
|
|||||||
type WorkspaceRequestSettings = Pick<
|
type WorkspaceRequestSettings = Pick<
|
||||||
Workspace,
|
Workspace,
|
||||||
| "settingFollowRedirects"
|
| "settingFollowRedirects"
|
||||||
|
| "settingRequestMessageSize"
|
||||||
| "settingRequestTimeout"
|
| "settingRequestTimeout"
|
||||||
| "settingSendCookies"
|
| "settingSendCookies"
|
||||||
| "settingStoreCookies"
|
| "settingStoreCookies"
|
||||||
@@ -17,7 +18,9 @@ type ModelTypeWithSetting<K extends RequestSettingKey> = {
|
|||||||
[M in ModelType]: K extends keyof ModelForType<M> ? M : never;
|
[M in ModelType]: K extends keyof ModelForType<M> ? M : never;
|
||||||
}[ModelType];
|
}[ModelType];
|
||||||
|
|
||||||
export type RequestSettingDefinition<K extends RequestSettingKey = RequestSettingKey> = {
|
export type RequestSettingDefinition<
|
||||||
|
K extends RequestSettingKey = RequestSettingKey,
|
||||||
|
> = {
|
||||||
defaultValue: WorkspaceRequestSettings[K];
|
defaultValue: WorkspaceRequestSettings[K];
|
||||||
description: string;
|
description: string;
|
||||||
modelKey: K;
|
modelKey: K;
|
||||||
@@ -41,11 +44,26 @@ export const SETTING_REQUEST_TIMEOUT = defineRequestSetting({
|
|||||||
title: "Request Timeout",
|
title: "Request Timeout",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const SETTING_REQUEST_MESSAGE_SIZE = defineRequestSetting({
|
||||||
|
defaultValue: 64 * 1024 * 1024,
|
||||||
|
description:
|
||||||
|
"Maximum gRPC or WebSocket message size in MB. Set to 0 to disable.",
|
||||||
|
modelKey: "settingRequestMessageSize",
|
||||||
|
models: ["workspace", "folder", "websocket_request", "grpc_request"],
|
||||||
|
title: "Message Size Limit",
|
||||||
|
});
|
||||||
|
|
||||||
export const SETTING_VALIDATE_CERTIFICATES = defineRequestSetting({
|
export const SETTING_VALIDATE_CERTIFICATES = defineRequestSetting({
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
description: "When disabled, skip validation of server certificates.",
|
description: "When disabled, skip validation of server certificates.",
|
||||||
modelKey: "settingValidateCertificates",
|
modelKey: "settingValidateCertificates",
|
||||||
models: ["workspace", "folder", "http_request", "websocket_request", "grpc_request"],
|
models: [
|
||||||
|
"workspace",
|
||||||
|
"folder",
|
||||||
|
"http_request",
|
||||||
|
"websocket_request",
|
||||||
|
"grpc_request",
|
||||||
|
],
|
||||||
title: "Validate TLS certificates",
|
title: "Validate TLS certificates",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,7 +77,8 @@ export const SETTING_FOLLOW_REDIRECTS = defineRequestSetting({
|
|||||||
|
|
||||||
export const SETTING_SEND_COOKIES = defineRequestSetting({
|
export const SETTING_SEND_COOKIES = defineRequestSetting({
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
description: "Attach matching cookies from the active cookie jar to outgoing requests.",
|
description:
|
||||||
|
"Attach matching cookies from the active cookie jar to outgoing requests.",
|
||||||
modelKey: "settingSendCookies",
|
modelKey: "settingSendCookies",
|
||||||
models: ["workspace", "folder", "http_request", "websocket_request"],
|
models: ["workspace", "folder", "http_request", "websocket_request"],
|
||||||
title: "Automatically send cookies",
|
title: "Automatically send cookies",
|
||||||
@@ -67,7 +86,8 @@ export const SETTING_SEND_COOKIES = defineRequestSetting({
|
|||||||
|
|
||||||
export const SETTING_STORE_COOKIES = defineRequestSetting({
|
export const SETTING_STORE_COOKIES = defineRequestSetting({
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
description: "Save cookies from Set-Cookie response headers to the active cookie jar.",
|
description:
|
||||||
|
"Save cookies from Set-Cookie response headers to the active cookie jar.",
|
||||||
modelKey: "settingStoreCookies",
|
modelKey: "settingStoreCookies",
|
||||||
models: ["workspace", "folder", "http_request", "websocket_request"],
|
models: ["workspace", "folder", "http_request", "websocket_request"],
|
||||||
title: "Automatically store cookies",
|
title: "Automatically store cookies",
|
||||||
|
|||||||
@@ -295,7 +295,8 @@ async fn cmd_grpc_reflect<R: Runtime>(
|
|||||||
unrendered_request.folder_id.as_deref(),
|
unrendered_request.folder_id.as_deref(),
|
||||||
environment_id,
|
environment_id,
|
||||||
)?;
|
)?;
|
||||||
let resolved_settings = app_handle.db().resolve_settings_for_grpc_request(&unrendered_request)?;
|
let resolved_settings =
|
||||||
|
app_handle.db().resolve_settings_for_grpc_request(&unrendered_request)?;
|
||||||
|
|
||||||
let plugin_manager = Arc::new((*app_handle.state::<PluginManager>()).clone());
|
let plugin_manager = Arc::new((*app_handle.state::<PluginManager>()).clone());
|
||||||
let encryption_manager = Arc::new((*app_handle.state::<EncryptionManager>()).clone());
|
let encryption_manager = Arc::new((*app_handle.state::<EncryptionManager>()).clone());
|
||||||
@@ -332,6 +333,7 @@ async fn cmd_grpc_reflect<R: Runtime>(
|
|||||||
&metadata,
|
&metadata,
|
||||||
resolved_settings.validate_certificates.value,
|
resolved_settings.validate_certificates.value,
|
||||||
client_certificate,
|
client_certificate,
|
||||||
|
resolved_settings.request_message_size.value,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| GenericError(e.to_string()))?)
|
.map_err(|e| GenericError(e.to_string()))?)
|
||||||
@@ -353,7 +355,8 @@ async fn cmd_grpc_go<R: Runtime>(
|
|||||||
unrendered_request.folder_id.as_deref(),
|
unrendered_request.folder_id.as_deref(),
|
||||||
environment_id,
|
environment_id,
|
||||||
)?;
|
)?;
|
||||||
let resolved_settings = app_handle.db().resolve_settings_for_grpc_request(&unrendered_request)?;
|
let resolved_settings =
|
||||||
|
app_handle.db().resolve_settings_for_grpc_request(&unrendered_request)?;
|
||||||
|
|
||||||
let plugin_manager = Arc::new((*app_handle.state::<PluginManager>()).clone());
|
let plugin_manager = Arc::new((*app_handle.state::<PluginManager>()).clone());
|
||||||
let encryption_manager = Arc::new((*app_handle.state::<EncryptionManager>()).clone());
|
let encryption_manager = Arc::new((*app_handle.state::<EncryptionManager>()).clone());
|
||||||
@@ -425,6 +428,7 @@ async fn cmd_grpc_go<R: Runtime>(
|
|||||||
&metadata,
|
&metadata,
|
||||||
resolved_settings.validate_certificates.value,
|
resolved_settings.validate_certificates.value,
|
||||||
client_cert.clone(),
|
client_cert.clone(),
|
||||||
|
resolved_settings.request_message_size.value,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
|||||||
receive_tx,
|
receive_tx,
|
||||||
resolved_settings.validate_certificates.value,
|
resolved_settings.validate_certificates.value,
|
||||||
client_cert,
|
client_cert,
|
||||||
|
resolved_settings.request_message_size.value,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|||||||
Generated
+4
@@ -46,6 +46,7 @@ export type Folder = {
|
|||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
settingFollowRedirects: InheritedBoolSetting;
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
settingRequestTimeout: InheritedIntSetting;
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GrpcRequest = {
|
export type GrpcRequest = {
|
||||||
@@ -69,6 +70,7 @@ export type GrpcRequest = {
|
|||||||
*/
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HttpRequest = {
|
export type HttpRequest = {
|
||||||
@@ -146,6 +148,7 @@ export type WebsocketRequest = {
|
|||||||
settingSendCookies: InheritedBoolSetting;
|
settingSendCookies: InheritedBoolSetting;
|
||||||
settingStoreCookies: InheritedBoolSetting;
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Workspace = {
|
export type Workspace = {
|
||||||
@@ -162,6 +165,7 @@ export type Workspace = {
|
|||||||
settingValidateCertificates: boolean;
|
settingValidateCertificates: boolean;
|
||||||
settingFollowRedirects: boolean;
|
settingFollowRedirects: boolean;
|
||||||
settingRequestTimeout: number;
|
settingRequestTimeout: number;
|
||||||
|
settingRequestMessageSize: number;
|
||||||
settingDnsOverrides: Array<DnsOverride>;
|
settingDnsOverrides: Array<DnsOverride>;
|
||||||
settingSendCookies: boolean;
|
settingSendCookies: boolean;
|
||||||
settingStoreCookies: boolean;
|
settingStoreCookies: boolean;
|
||||||
|
|||||||
@@ -33,15 +33,21 @@ impl AutoReflectionClient {
|
|||||||
uri: &Uri,
|
uri: &Uri,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
max_message_size: usize,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let client_v1 = v1::server_reflection_client::ServerReflectionClient::with_origin(
|
let client_v1 = v1::server_reflection_client::ServerReflectionClient::with_origin(
|
||||||
get_transport(validate_certificates, client_cert.clone())?,
|
get_transport(validate_certificates, client_cert.clone())?,
|
||||||
uri.clone(),
|
uri.clone(),
|
||||||
);
|
)
|
||||||
let client_v1alpha = v1alpha::server_reflection_client::ServerReflectionClient::with_origin(
|
.max_decoding_message_size(max_message_size)
|
||||||
|
.max_encoding_message_size(max_message_size);
|
||||||
|
let client_v1alpha =
|
||||||
|
v1alpha::server_reflection_client::ServerReflectionClient::with_origin(
|
||||||
get_transport(validate_certificates, client_cert.clone())?,
|
get_transport(validate_certificates, client_cert.clone())?,
|
||||||
uri.clone(),
|
uri.clone(),
|
||||||
);
|
)
|
||||||
|
.max_decoding_message_size(max_message_size)
|
||||||
|
.max_encoding_message_size(max_message_size);
|
||||||
Ok(AutoReflectionClient { use_v1alpha: false, client_v1, client_v1alpha })
|
Ok(AutoReflectionClient { use_v1alpha: false, client_v1, client_v1alpha })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ pub struct GrpcConnection {
|
|||||||
conn: Client<HttpsConnector<HttpConnector>, BoxBody>,
|
conn: Client<HttpsConnector<HttpConnector>, BoxBody>,
|
||||||
pub uri: Uri,
|
pub uri: Uri,
|
||||||
use_reflection: bool,
|
use_reflection: bool,
|
||||||
|
max_message_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
@@ -97,7 +98,14 @@ impl GrpcConnection {
|
|||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
) -> Result<Response<DynamicMessage>> {
|
) -> Result<Response<DynamicMessage>> {
|
||||||
if self.use_reflection {
|
if self.use_reflection {
|
||||||
reflect_types_for_message(self.pool.clone(), &self.uri, message, metadata, client_cert)
|
reflect_types_for_message(
|
||||||
|
self.pool.clone(),
|
||||||
|
&self.uri,
|
||||||
|
message,
|
||||||
|
metadata,
|
||||||
|
client_cert,
|
||||||
|
self.max_message_size,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
let method = &self.method(&service, &method).await?;
|
let method = &self.method(&service, &method).await?;
|
||||||
@@ -107,7 +115,7 @@ impl GrpcConnection {
|
|||||||
let req_message = DynamicMessage::deserialize(input_message, &mut deserializer)?;
|
let req_message = DynamicMessage::deserialize(input_message, &mut deserializer)?;
|
||||||
deserializer.end()?;
|
deserializer.end()?;
|
||||||
|
|
||||||
let mut client = tonic::client::Grpc::with_origin(self.conn.clone(), self.uri.clone());
|
let mut client = grpc_client(self.conn.clone(), self.uri.clone(), self.max_message_size);
|
||||||
|
|
||||||
let mut req = req_message.into_request();
|
let mut req = req_message.into_request();
|
||||||
decorate_req(metadata, &mut req)?;
|
decorate_req(metadata, &mut req)?;
|
||||||
@@ -132,6 +140,7 @@ impl GrpcConnection {
|
|||||||
message,
|
message,
|
||||||
metadata,
|
metadata,
|
||||||
client_cert,
|
client_cert,
|
||||||
|
self.max_message_size,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -171,6 +180,7 @@ impl GrpcConnection {
|
|||||||
let md = metadata.clone();
|
let md = metadata.clone();
|
||||||
let use_reflection = self.use_reflection.clone();
|
let use_reflection = self.use_reflection.clone();
|
||||||
let client_cert = client_cert.clone();
|
let client_cert = client_cert.clone();
|
||||||
|
let max_message_size = self.max_message_size;
|
||||||
stream
|
stream
|
||||||
.then(move |json| {
|
.then(move |json| {
|
||||||
let pool = pool.clone();
|
let pool = pool.clone();
|
||||||
@@ -183,8 +193,15 @@ impl GrpcConnection {
|
|||||||
let json_clone = json.clone();
|
let json_clone = json.clone();
|
||||||
async move {
|
async move {
|
||||||
if use_reflection {
|
if use_reflection {
|
||||||
if let Err(e) =
|
if let Err(e) = reflect_types_for_message(
|
||||||
reflect_types_for_message(pool, &uri, &json, &md, client_cert).await
|
pool,
|
||||||
|
&uri,
|
||||||
|
&json,
|
||||||
|
&md,
|
||||||
|
client_cert,
|
||||||
|
max_message_size,
|
||||||
|
)
|
||||||
|
.await
|
||||||
{
|
{
|
||||||
warn!("Failed to resolve Any types: {e}");
|
warn!("Failed to resolve Any types: {e}");
|
||||||
}
|
}
|
||||||
@@ -206,7 +223,7 @@ impl GrpcConnection {
|
|||||||
.filter_map(|x| x)
|
.filter_map(|x| x)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut client = tonic::client::Grpc::with_origin(self.conn.clone(), self.uri.clone());
|
let mut client = grpc_client(self.conn.clone(), self.uri.clone(), self.max_message_size);
|
||||||
let path = method_desc_to_path(method);
|
let path = method_desc_to_path(method);
|
||||||
let codec = DynamicCodec::new(method.clone());
|
let codec = DynamicCodec::new(method.clone());
|
||||||
|
|
||||||
@@ -237,6 +254,7 @@ impl GrpcConnection {
|
|||||||
let md = metadata.clone();
|
let md = metadata.clone();
|
||||||
let use_reflection = self.use_reflection.clone();
|
let use_reflection = self.use_reflection.clone();
|
||||||
let client_cert = client_cert.clone();
|
let client_cert = client_cert.clone();
|
||||||
|
let max_message_size = self.max_message_size;
|
||||||
stream
|
stream
|
||||||
.then(move |json| {
|
.then(move |json| {
|
||||||
let pool = pool.clone();
|
let pool = pool.clone();
|
||||||
@@ -249,8 +267,15 @@ impl GrpcConnection {
|
|||||||
let json_clone = json.clone();
|
let json_clone = json.clone();
|
||||||
async move {
|
async move {
|
||||||
if use_reflection {
|
if use_reflection {
|
||||||
if let Err(e) =
|
if let Err(e) = reflect_types_for_message(
|
||||||
reflect_types_for_message(pool, &uri, &json, &md, client_cert).await
|
pool,
|
||||||
|
&uri,
|
||||||
|
&json,
|
||||||
|
&md,
|
||||||
|
client_cert,
|
||||||
|
max_message_size,
|
||||||
|
)
|
||||||
|
.await
|
||||||
{
|
{
|
||||||
warn!("Failed to resolve Any types: {e}");
|
warn!("Failed to resolve Any types: {e}");
|
||||||
}
|
}
|
||||||
@@ -272,7 +297,7 @@ impl GrpcConnection {
|
|||||||
.filter_map(|x| x)
|
.filter_map(|x| x)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut client = tonic::client::Grpc::with_origin(self.conn.clone(), self.uri.clone());
|
let mut client = grpc_client(self.conn.clone(), self.uri.clone(), self.max_message_size);
|
||||||
let path = method_desc_to_path(method);
|
let path = method_desc_to_path(method);
|
||||||
let codec = DynamicCodec::new(method.clone());
|
let codec = DynamicCodec::new(method.clone());
|
||||||
|
|
||||||
@@ -300,7 +325,7 @@ impl GrpcConnection {
|
|||||||
let req_message = DynamicMessage::deserialize(input_message, &mut deserializer)?;
|
let req_message = DynamicMessage::deserialize(input_message, &mut deserializer)?;
|
||||||
deserializer.end()?;
|
deserializer.end()?;
|
||||||
|
|
||||||
let mut client = tonic::client::Grpc::with_origin(self.conn.clone(), self.uri.clone());
|
let mut client = grpc_client(self.conn.clone(), self.uri.clone(), self.max_message_size);
|
||||||
|
|
||||||
let mut req = req_message.into_request();
|
let mut req = req_message.into_request();
|
||||||
decorate_req(metadata, &mut req)?;
|
decorate_req(metadata, &mut req)?;
|
||||||
@@ -312,6 +337,23 @@ impl GrpcConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn grpc_client(
|
||||||
|
conn: Client<HttpsConnector<HttpConnector>, BoxBody>,
|
||||||
|
uri: Uri,
|
||||||
|
max_message_size: usize,
|
||||||
|
) -> tonic::client::Grpc<Client<HttpsConnector<HttpConnector>, BoxBody>> {
|
||||||
|
tonic::client::Grpc::with_origin(conn, uri)
|
||||||
|
.max_decoding_message_size(max_message_size)
|
||||||
|
.max_encoding_message_size(max_message_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn message_size_limit(setting: i32) -> usize {
|
||||||
|
match setting.try_into() {
|
||||||
|
Ok(0) | Err(_) => usize::MAX,
|
||||||
|
Ok(limit) => limit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration for GrpcHandle to compile proto files
|
/// Configuration for GrpcHandle to compile proto files
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GrpcConfig {
|
pub struct GrpcConfig {
|
||||||
@@ -348,6 +390,7 @@ impl GrpcHandle {
|
|||||||
metadata: &BTreeMap<String, String>,
|
metadata: &BTreeMap<String, String>,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
request_message_size: i32,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let server_reflection = proto_files.is_empty();
|
let server_reflection = proto_files.is_empty();
|
||||||
let key = make_pool_key(id, uri, proto_files);
|
let key = make_pool_key(id, uri, proto_files);
|
||||||
@@ -359,7 +402,14 @@ impl GrpcHandle {
|
|||||||
|
|
||||||
let pool = if server_reflection {
|
let pool = if server_reflection {
|
||||||
let full_uri = uri_from_str(uri)?;
|
let full_uri = uri_from_str(uri)?;
|
||||||
fill_pool_from_reflection(&full_uri, metadata, validate_certificates, client_cert).await
|
fill_pool_from_reflection(
|
||||||
|
&full_uri,
|
||||||
|
metadata,
|
||||||
|
validate_certificates,
|
||||||
|
client_cert,
|
||||||
|
message_size_limit(request_message_size),
|
||||||
|
)
|
||||||
|
.await
|
||||||
} else {
|
} else {
|
||||||
fill_pool_from_files(&self.config, proto_files).await
|
fill_pool_from_files(&self.config, proto_files).await
|
||||||
}?;
|
}?;
|
||||||
@@ -376,11 +426,20 @@ impl GrpcHandle {
|
|||||||
metadata: &BTreeMap<String, String>,
|
metadata: &BTreeMap<String, String>,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
request_message_size: i32,
|
||||||
) -> Result<Vec<ServiceDefinition>> {
|
) -> Result<Vec<ServiceDefinition>> {
|
||||||
// Ensure we have a pool; reflect only if missing
|
// Ensure we have a pool; reflect only if missing
|
||||||
if self.get_pool(id, uri, proto_files).is_none() {
|
if self.get_pool(id, uri, proto_files).is_none() {
|
||||||
info!("Reflecting gRPC services for {} at {}", id, uri);
|
info!("Reflecting gRPC services for {} at {}", id, uri);
|
||||||
self.reflect(id, uri, proto_files, metadata, validate_certificates, client_cert)
|
self.reflect(
|
||||||
|
id,
|
||||||
|
uri,
|
||||||
|
proto_files,
|
||||||
|
metadata,
|
||||||
|
validate_certificates,
|
||||||
|
client_cert,
|
||||||
|
request_message_size,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,8 +480,10 @@ impl GrpcHandle {
|
|||||||
metadata: &BTreeMap<String, String>,
|
metadata: &BTreeMap<String, String>,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
request_message_size: i32,
|
||||||
) -> Result<GrpcConnection> {
|
) -> Result<GrpcConnection> {
|
||||||
let use_reflection = proto_files.is_empty();
|
let use_reflection = proto_files.is_empty();
|
||||||
|
let max_message_size = message_size_limit(request_message_size);
|
||||||
if self.get_pool(id, uri, proto_files).is_none() {
|
if self.get_pool(id, uri, proto_files).is_none() {
|
||||||
self.reflect(
|
self.reflect(
|
||||||
id,
|
id,
|
||||||
@@ -431,6 +492,7 @@ impl GrpcHandle {
|
|||||||
metadata,
|
metadata,
|
||||||
validate_certificates,
|
validate_certificates,
|
||||||
client_cert.clone(),
|
client_cert.clone(),
|
||||||
|
request_message_size,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
@@ -440,7 +502,13 @@ impl GrpcHandle {
|
|||||||
.clone();
|
.clone();
|
||||||
let uri = uri_from_str(uri)?;
|
let uri = uri_from_str(uri)?;
|
||||||
let conn = get_transport(validate_certificates, client_cert.clone())?;
|
let conn = get_transport(validate_certificates, client_cert.clone())?;
|
||||||
Ok(GrpcConnection { pool: Arc::new(RwLock::new(pool)), use_reflection, conn, uri })
|
Ok(GrpcConnection {
|
||||||
|
pool: Arc::new(RwLock::new(pool)),
|
||||||
|
use_reflection,
|
||||||
|
conn,
|
||||||
|
uri,
|
||||||
|
max_message_size,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pool(&self, id: &str, uri: &str, proto_files: &Vec<PathBuf>) -> Option<&DescriptorPool> {
|
fn get_pool(&self, id: &str, uri: &str, proto_files: &Vec<PathBuf>) -> Option<&DescriptorPool> {
|
||||||
|
|||||||
@@ -119,9 +119,11 @@ pub async fn fill_pool_from_reflection(
|
|||||||
metadata: &BTreeMap<String, String>,
|
metadata: &BTreeMap<String, String>,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
max_message_size: usize,
|
||||||
) -> Result<DescriptorPool> {
|
) -> Result<DescriptorPool> {
|
||||||
let mut pool = DescriptorPool::new();
|
let mut pool = DescriptorPool::new();
|
||||||
let mut client = AutoReflectionClient::new(uri, validate_certificates, client_cert)?;
|
let mut client =
|
||||||
|
AutoReflectionClient::new(uri, validate_certificates, client_cert, max_message_size)?;
|
||||||
|
|
||||||
for service in list_services(&mut client, metadata).await? {
|
for service in list_services(&mut client, metadata).await? {
|
||||||
if service == "grpc.reflection.v1alpha.ServerReflection" {
|
if service == "grpc.reflection.v1alpha.ServerReflection" {
|
||||||
@@ -192,6 +194,7 @@ pub(crate) async fn reflect_types_for_message(
|
|||||||
json: &str,
|
json: &str,
|
||||||
metadata: &BTreeMap<String, String>,
|
metadata: &BTreeMap<String, String>,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
max_message_size: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// 1. Collect all Any types in the JSON
|
// 1. Collect all Any types in the JSON
|
||||||
let mut extra_types = Vec::new();
|
let mut extra_types = Vec::new();
|
||||||
@@ -201,7 +204,7 @@ pub(crate) async fn reflect_types_for_message(
|
|||||||
return Ok(()); // nothing to do
|
return Ok(()); // nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut client = AutoReflectionClient::new(uri, false, client_cert)?;
|
let mut client = AutoReflectionClient::new(uri, false, client_cert, max_message_size)?;
|
||||||
for extra_type in extra_types {
|
for extra_type in extra_types {
|
||||||
{
|
{
|
||||||
let guard = pool.read().await;
|
let guard = pool.read().await;
|
||||||
@@ -239,6 +242,7 @@ pub(crate) async fn reflect_types_for_dynamic_message(
|
|||||||
message: &DynamicMessage,
|
message: &DynamicMessage,
|
||||||
metadata: &BTreeMap<String, String>,
|
metadata: &BTreeMap<String, String>,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
max_message_size: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut extra_types = HashSet::new();
|
let mut extra_types = HashSet::new();
|
||||||
collect_any_types_from_dynamic_message(message, &mut extra_types);
|
collect_any_types_from_dynamic_message(message, &mut extra_types);
|
||||||
@@ -247,7 +251,7 @@ pub(crate) async fn reflect_types_for_dynamic_message(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut client = AutoReflectionClient::new(uri, false, client_cert)?;
|
let mut client = AutoReflectionClient::new(uri, false, client_cert, max_message_size)?;
|
||||||
for extra_type in extra_types {
|
for extra_type in extra_types {
|
||||||
{
|
{
|
||||||
let guard = pool.read().await;
|
let guard = pool.read().await;
|
||||||
|
|||||||
+4
@@ -109,6 +109,7 @@ export type Folder = {
|
|||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
settingFollowRedirects: InheritedBoolSetting;
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
settingRequestTimeout: InheritedIntSetting;
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GraphQlIntrospection = {
|
export type GraphQlIntrospection = {
|
||||||
@@ -184,6 +185,7 @@ export type GrpcRequest = {
|
|||||||
*/
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HttpRequest = {
|
export type HttpRequest = {
|
||||||
@@ -482,6 +484,7 @@ export type WebsocketRequest = {
|
|||||||
settingSendCookies: InheritedBoolSetting;
|
settingSendCookies: InheritedBoolSetting;
|
||||||
settingStoreCookies: InheritedBoolSetting;
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Workspace = {
|
export type Workspace = {
|
||||||
@@ -498,6 +501,7 @@ export type Workspace = {
|
|||||||
settingValidateCertificates: boolean;
|
settingValidateCertificates: boolean;
|
||||||
settingFollowRedirects: boolean;
|
settingFollowRedirects: boolean;
|
||||||
settingRequestTimeout: number;
|
settingRequestTimeout: number;
|
||||||
|
settingRequestMessageSize: number;
|
||||||
settingDnsOverrides: Array<DnsOverride>;
|
settingDnsOverrides: Array<DnsOverride>;
|
||||||
settingSendCookies: boolean;
|
settingSendCookies: boolean;
|
||||||
settingStoreCookies: boolean;
|
settingStoreCookies: boolean;
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
ALTER TABLE workspaces ADD COLUMN setting_request_message_size INTEGER DEFAULT 67108864 NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE folders ADD COLUMN setting_request_message_size TEXT DEFAULT '{"enabled":false,"value":67108864}' NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE websocket_requests ADD COLUMN setting_request_message_size TEXT DEFAULT '{"enabled":false,"value":67108864}' NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE grpc_requests ADD COLUMN setting_request_message_size TEXT DEFAULT '{"enabled":false,"value":67108864}' NOT NULL;
|
||||||
@@ -21,6 +21,8 @@ use ts_rs::TS;
|
|||||||
use yaak_database::{Result as DbResult, UpdateSource};
|
use yaak_database::{Result as DbResult, UpdateSource};
|
||||||
pub use yaak_database::{UpsertModelInfo, upsert_date};
|
pub use yaak_database::{UpsertModelInfo, upsert_date};
|
||||||
|
|
||||||
|
pub const DEFAULT_REQUEST_MESSAGE_SIZE: i32 = 64 * 1024 * 1024;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_model {
|
macro_rules! impl_model {
|
||||||
($t:ty, $variant:ident) => {
|
($t:ty, $variant:ident) => {
|
||||||
@@ -120,6 +122,7 @@ pub struct ResolvedHttpRequestSettings {
|
|||||||
pub validate_certificates: ResolvedSetting<bool>,
|
pub validate_certificates: ResolvedSetting<bool>,
|
||||||
pub follow_redirects: ResolvedSetting<bool>,
|
pub follow_redirects: ResolvedSetting<bool>,
|
||||||
pub request_timeout: ResolvedSetting<i32>,
|
pub request_timeout: ResolvedSetting<i32>,
|
||||||
|
pub request_message_size: ResolvedSetting<i32>,
|
||||||
pub send_cookies: ResolvedSetting<bool>,
|
pub send_cookies: ResolvedSetting<bool>,
|
||||||
pub store_cookies: ResolvedSetting<bool>,
|
pub store_cookies: ResolvedSetting<bool>,
|
||||||
}
|
}
|
||||||
@@ -130,6 +133,7 @@ impl Default for ResolvedHttpRequestSettings {
|
|||||||
validate_certificates: ResolvedSetting::default_source(true),
|
validate_certificates: ResolvedSetting::default_source(true),
|
||||||
follow_redirects: ResolvedSetting::default_source(true),
|
follow_redirects: ResolvedSetting::default_source(true),
|
||||||
request_timeout: ResolvedSetting::default_source(0),
|
request_timeout: ResolvedSetting::default_source(0),
|
||||||
|
request_message_size: ResolvedSetting::default_source(DEFAULT_REQUEST_MESSAGE_SIZE),
|
||||||
send_cookies: ResolvedSetting::default_source(true),
|
send_cookies: ResolvedSetting::default_source(true),
|
||||||
store_cookies: ResolvedSetting::default_source(true),
|
store_cookies: ResolvedSetting::default_source(true),
|
||||||
}
|
}
|
||||||
@@ -400,6 +404,8 @@ pub struct Workspace {
|
|||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub setting_follow_redirects: bool,
|
pub setting_follow_redirects: bool,
|
||||||
pub setting_request_timeout: i32,
|
pub setting_request_timeout: i32,
|
||||||
|
#[serde(default = "default_request_message_size")]
|
||||||
|
pub setting_request_message_size: i32,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub setting_dns_overrides: Vec<DnsOverride>,
|
pub setting_dns_overrides: Vec<DnsOverride>,
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
@@ -445,6 +451,7 @@ impl UpsertModelInfo for Workspace {
|
|||||||
(EncryptionKeyChallenge, self.encryption_key_challenge.into()),
|
(EncryptionKeyChallenge, self.encryption_key_challenge.into()),
|
||||||
(SettingFollowRedirects, self.setting_follow_redirects.into()),
|
(SettingFollowRedirects, self.setting_follow_redirects.into()),
|
||||||
(SettingRequestTimeout, self.setting_request_timeout.into()),
|
(SettingRequestTimeout, self.setting_request_timeout.into()),
|
||||||
|
(SettingRequestMessageSize, self.setting_request_message_size.into()),
|
||||||
(SettingValidateCertificates, self.setting_validate_certificates.into()),
|
(SettingValidateCertificates, self.setting_validate_certificates.into()),
|
||||||
(SettingDnsOverrides, serde_json::to_string(&self.setting_dns_overrides)?.into()),
|
(SettingDnsOverrides, serde_json::to_string(&self.setting_dns_overrides)?.into()),
|
||||||
(SettingSendCookies, self.setting_send_cookies.into()),
|
(SettingSendCookies, self.setting_send_cookies.into()),
|
||||||
@@ -463,7 +470,7 @@ impl UpsertModelInfo for Workspace {
|
|||||||
WorkspaceIden::EncryptionKeyChallenge,
|
WorkspaceIden::EncryptionKeyChallenge,
|
||||||
WorkspaceIden::SettingRequestTimeout,
|
WorkspaceIden::SettingRequestTimeout,
|
||||||
WorkspaceIden::SettingFollowRedirects,
|
WorkspaceIden::SettingFollowRedirects,
|
||||||
WorkspaceIden::SettingRequestTimeout,
|
WorkspaceIden::SettingRequestMessageSize,
|
||||||
WorkspaceIden::SettingValidateCertificates,
|
WorkspaceIden::SettingValidateCertificates,
|
||||||
WorkspaceIden::SettingDnsOverrides,
|
WorkspaceIden::SettingDnsOverrides,
|
||||||
WorkspaceIden::SettingSendCookies,
|
WorkspaceIden::SettingSendCookies,
|
||||||
@@ -491,6 +498,7 @@ impl UpsertModelInfo for Workspace {
|
|||||||
authentication_type: row.get("authentication_type")?,
|
authentication_type: row.get("authentication_type")?,
|
||||||
setting_follow_redirects: row.get("setting_follow_redirects")?,
|
setting_follow_redirects: row.get("setting_follow_redirects")?,
|
||||||
setting_request_timeout: row.get("setting_request_timeout")?,
|
setting_request_timeout: row.get("setting_request_timeout")?,
|
||||||
|
setting_request_message_size: row.get("setting_request_message_size")?,
|
||||||
setting_validate_certificates: row.get("setting_validate_certificates")?,
|
setting_validate_certificates: row.get("setting_validate_certificates")?,
|
||||||
setting_dns_overrides: serde_json::from_str(&setting_dns_overrides).unwrap_or_default(),
|
setting_dns_overrides: serde_json::from_str(&setting_dns_overrides).unwrap_or_default(),
|
||||||
setting_send_cookies: row.get("setting_send_cookies")?,
|
setting_send_cookies: row.get("setting_send_cookies")?,
|
||||||
@@ -962,6 +970,8 @@ pub struct Folder {
|
|||||||
pub setting_validate_certificates: InheritedBoolSetting,
|
pub setting_validate_certificates: InheritedBoolSetting,
|
||||||
pub setting_follow_redirects: InheritedBoolSetting,
|
pub setting_follow_redirects: InheritedBoolSetting,
|
||||||
pub setting_request_timeout: InheritedIntSetting,
|
pub setting_request_timeout: InheritedIntSetting,
|
||||||
|
#[serde(default = "default_request_message_size_setting")]
|
||||||
|
pub setting_request_message_size: InheritedIntSetting,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpsertModelInfo for Folder {
|
impl UpsertModelInfo for Folder {
|
||||||
@@ -1009,6 +1019,10 @@ impl UpsertModelInfo for Folder {
|
|||||||
),
|
),
|
||||||
(SettingFollowRedirects, serde_json::to_string(&self.setting_follow_redirects)?.into()),
|
(SettingFollowRedirects, serde_json::to_string(&self.setting_follow_redirects)?.into()),
|
||||||
(SettingRequestTimeout, serde_json::to_string(&self.setting_request_timeout)?.into()),
|
(SettingRequestTimeout, serde_json::to_string(&self.setting_request_timeout)?.into()),
|
||||||
|
(
|
||||||
|
SettingRequestMessageSize,
|
||||||
|
serde_json::to_string(&self.setting_request_message_size)?.into(),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,6 +1041,7 @@ impl UpsertModelInfo for Folder {
|
|||||||
FolderIden::SettingValidateCertificates,
|
FolderIden::SettingValidateCertificates,
|
||||||
FolderIden::SettingFollowRedirects,
|
FolderIden::SettingFollowRedirects,
|
||||||
FolderIden::SettingRequestTimeout,
|
FolderIden::SettingRequestTimeout,
|
||||||
|
FolderIden::SettingRequestMessageSize,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1041,6 +1056,7 @@ impl UpsertModelInfo for Folder {
|
|||||||
let setting_validate_certificates: String = row.get("setting_validate_certificates")?;
|
let setting_validate_certificates: String = row.get("setting_validate_certificates")?;
|
||||||
let setting_follow_redirects: String = row.get("setting_follow_redirects")?;
|
let setting_follow_redirects: String = row.get("setting_follow_redirects")?;
|
||||||
let setting_request_timeout: String = row.get("setting_request_timeout")?;
|
let setting_request_timeout: String = row.get("setting_request_timeout")?;
|
||||||
|
let setting_request_message_size: String = row.get("setting_request_message_size")?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id: row.get("id")?,
|
id: row.get("id")?,
|
||||||
model: row.get("model")?,
|
model: row.get("model")?,
|
||||||
@@ -1062,6 +1078,8 @@ impl UpsertModelInfo for Folder {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
setting_request_timeout: serde_json::from_str(&setting_request_timeout)
|
setting_request_timeout: serde_json::from_str(&setting_request_timeout)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
setting_request_message_size: serde_json::from_str(&setting_request_message_size)
|
||||||
|
.unwrap_or_else(|_| default_request_message_size_setting()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1398,6 +1416,8 @@ pub struct WebsocketRequest {
|
|||||||
pub setting_send_cookies: InheritedBoolSetting,
|
pub setting_send_cookies: InheritedBoolSetting,
|
||||||
pub setting_store_cookies: InheritedBoolSetting,
|
pub setting_store_cookies: InheritedBoolSetting,
|
||||||
pub setting_validate_certificates: InheritedBoolSetting,
|
pub setting_validate_certificates: InheritedBoolSetting,
|
||||||
|
#[serde(default = "default_request_message_size_setting")]
|
||||||
|
pub setting_request_message_size: InheritedIntSetting,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpsertModelInfo for WebsocketRequest {
|
impl UpsertModelInfo for WebsocketRequest {
|
||||||
@@ -1446,6 +1466,10 @@ impl UpsertModelInfo for WebsocketRequest {
|
|||||||
SettingValidateCertificates,
|
SettingValidateCertificates,
|
||||||
serde_json::to_string(&self.setting_validate_certificates)?.into(),
|
serde_json::to_string(&self.setting_validate_certificates)?.into(),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
SettingRequestMessageSize,
|
||||||
|
serde_json::to_string(&self.setting_request_message_size)?.into(),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1466,6 +1490,7 @@ impl UpsertModelInfo for WebsocketRequest {
|
|||||||
WebsocketRequestIden::SettingSendCookies,
|
WebsocketRequestIden::SettingSendCookies,
|
||||||
WebsocketRequestIden::SettingStoreCookies,
|
WebsocketRequestIden::SettingStoreCookies,
|
||||||
WebsocketRequestIden::SettingValidateCertificates,
|
WebsocketRequestIden::SettingValidateCertificates,
|
||||||
|
WebsocketRequestIden::SettingRequestMessageSize,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1479,6 +1504,7 @@ impl UpsertModelInfo for WebsocketRequest {
|
|||||||
let setting_send_cookies: String = row.get("setting_send_cookies")?;
|
let setting_send_cookies: String = row.get("setting_send_cookies")?;
|
||||||
let setting_store_cookies: String = row.get("setting_store_cookies")?;
|
let setting_store_cookies: String = row.get("setting_store_cookies")?;
|
||||||
let setting_validate_certificates: String = row.get("setting_validate_certificates")?;
|
let setting_validate_certificates: String = row.get("setting_validate_certificates")?;
|
||||||
|
let setting_request_message_size: String = row.get("setting_request_message_size")?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id: row.get("id")?,
|
id: row.get("id")?,
|
||||||
model: row.get("model")?,
|
model: row.get("model")?,
|
||||||
@@ -1499,6 +1525,8 @@ impl UpsertModelInfo for WebsocketRequest {
|
|||||||
setting_store_cookies: serde_json::from_str(&setting_store_cookies).unwrap_or_default(),
|
setting_store_cookies: serde_json::from_str(&setting_store_cookies).unwrap_or_default(),
|
||||||
setting_validate_certificates: serde_json::from_str(&setting_validate_certificates)
|
setting_validate_certificates: serde_json::from_str(&setting_validate_certificates)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
setting_request_message_size: serde_json::from_str(&setting_request_message_size)
|
||||||
|
.unwrap_or_else(|_| default_request_message_size_setting()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2039,6 +2067,8 @@ pub struct GrpcRequest {
|
|||||||
/// Server URL (http for plaintext or https for secure)
|
/// Server URL (http for plaintext or https for secure)
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub setting_validate_certificates: InheritedBoolSetting,
|
pub setting_validate_certificates: InheritedBoolSetting,
|
||||||
|
#[serde(default = "default_request_message_size_setting")]
|
||||||
|
pub setting_request_message_size: InheritedIntSetting,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpsertModelInfo for GrpcRequest {
|
impl UpsertModelInfo for GrpcRequest {
|
||||||
@@ -2086,6 +2116,10 @@ impl UpsertModelInfo for GrpcRequest {
|
|||||||
SettingValidateCertificates,
|
SettingValidateCertificates,
|
||||||
serde_json::to_string(&self.setting_validate_certificates)?.into(),
|
serde_json::to_string(&self.setting_validate_certificates)?.into(),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
SettingRequestMessageSize,
|
||||||
|
serde_json::to_string(&self.setting_request_message_size)?.into(),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2105,6 +2139,7 @@ impl UpsertModelInfo for GrpcRequest {
|
|||||||
GrpcRequestIden::Authentication,
|
GrpcRequestIden::Authentication,
|
||||||
GrpcRequestIden::Metadata,
|
GrpcRequestIden::Metadata,
|
||||||
GrpcRequestIden::SettingValidateCertificates,
|
GrpcRequestIden::SettingValidateCertificates,
|
||||||
|
GrpcRequestIden::SettingRequestMessageSize,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2115,6 +2150,7 @@ impl UpsertModelInfo for GrpcRequest {
|
|||||||
let authentication: String = row.get("authentication")?;
|
let authentication: String = row.get("authentication")?;
|
||||||
let metadata: String = row.get("metadata")?;
|
let metadata: String = row.get("metadata")?;
|
||||||
let setting_validate_certificates: String = row.get("setting_validate_certificates")?;
|
let setting_validate_certificates: String = row.get("setting_validate_certificates")?;
|
||||||
|
let setting_request_message_size: String = row.get("setting_request_message_size")?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id: row.get("id")?,
|
id: row.get("id")?,
|
||||||
model: row.get("model")?,
|
model: row.get("model")?,
|
||||||
@@ -2134,6 +2170,8 @@ impl UpsertModelInfo for GrpcRequest {
|
|||||||
metadata: serde_json::from_str(metadata.as_str()).unwrap_or_default(),
|
metadata: serde_json::from_str(metadata.as_str()).unwrap_or_default(),
|
||||||
setting_validate_certificates: serde_json::from_str(&setting_validate_certificates)
|
setting_validate_certificates: serde_json::from_str(&setting_validate_certificates)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
setting_request_message_size: serde_json::from_str(&setting_request_message_size)
|
||||||
|
.unwrap_or_else(|_| default_request_message_size_setting()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2684,6 +2722,14 @@ fn default_true() -> bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_request_message_size() -> i32 {
|
||||||
|
DEFAULT_REQUEST_MESSAGE_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_request_message_size_setting() -> InheritedIntSetting {
|
||||||
|
InheritedIntSetting { enabled: false, value: DEFAULT_REQUEST_MESSAGE_SIZE }
|
||||||
|
}
|
||||||
|
|
||||||
fn default_http_method() -> String {
|
fn default_http_method() -> String {
|
||||||
"GET".to_string()
|
"GET".to_string()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,6 +180,14 @@ impl<'a> ClientDb<'a> {
|
|||||||
} else {
|
} else {
|
||||||
parent.request_timeout
|
parent.request_timeout
|
||||||
},
|
},
|
||||||
|
request_message_size: if folder.setting_request_message_size.enabled {
|
||||||
|
ResolvedSetting::from_model(
|
||||||
|
folder.setting_request_message_size.value,
|
||||||
|
AnyModel::Folder(folder.clone()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
parent.request_message_size
|
||||||
|
},
|
||||||
send_cookies: if folder.setting_send_cookies.enabled {
|
send_cookies: if folder.setting_send_cookies.enabled {
|
||||||
ResolvedSetting::from_model(
|
ResolvedSetting::from_model(
|
||||||
folder.setting_send_cookies.value,
|
folder.setting_send_cookies.value,
|
||||||
|
|||||||
@@ -129,6 +129,14 @@ impl<'a> ClientDb<'a> {
|
|||||||
} else {
|
} else {
|
||||||
parent.validate_certificates
|
parent.validate_certificates
|
||||||
},
|
},
|
||||||
|
request_message_size: if grpc_request.setting_request_message_size.enabled {
|
||||||
|
ResolvedSetting::from_model(
|
||||||
|
grpc_request.setting_request_message_size.value,
|
||||||
|
AnyModel::GrpcRequest(grpc_request.clone()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
parent.request_message_size
|
||||||
|
},
|
||||||
..parent
|
..parent
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ impl<'a> ClientDb<'a> {
|
|||||||
} else {
|
} else {
|
||||||
parent.request_timeout
|
parent.request_timeout
|
||||||
},
|
},
|
||||||
|
request_message_size: parent.request_message_size,
|
||||||
send_cookies: if http_request.setting_send_cookies.enabled {
|
send_cookies: if http_request.setting_send_cookies.enabled {
|
||||||
ResolvedSetting::from_model(
|
ResolvedSetting::from_model(
|
||||||
http_request.setting_send_cookies.value,
|
http_request.setting_send_cookies.value,
|
||||||
|
|||||||
@@ -139,6 +139,14 @@ impl<'a> ClientDb<'a> {
|
|||||||
} else {
|
} else {
|
||||||
parent.validate_certificates
|
parent.validate_certificates
|
||||||
},
|
},
|
||||||
|
request_message_size: if websocket_request.setting_request_message_size.enabled {
|
||||||
|
ResolvedSetting::from_model(
|
||||||
|
websocket_request.setting_request_message_size.value,
|
||||||
|
AnyModel::WebsocketRequest(websocket_request.clone()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
parent.request_message_size
|
||||||
|
},
|
||||||
send_cookies: if websocket_request.setting_send_cookies.enabled {
|
send_cookies: if websocket_request.setting_send_cookies.enabled {
|
||||||
ResolvedSetting::from_model(
|
ResolvedSetting::from_model(
|
||||||
websocket_request.setting_send_cookies.value,
|
websocket_request.setting_send_cookies.value,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ impl<'a> ClientDb<'a> {
|
|||||||
&Workspace {
|
&Workspace {
|
||||||
name: "Yaak".to_string(),
|
name: "Yaak".to_string(),
|
||||||
setting_follow_redirects: true,
|
setting_follow_redirects: true,
|
||||||
|
setting_request_message_size: crate::models::DEFAULT_REQUEST_MESSAGE_SIZE,
|
||||||
setting_validate_certificates: true,
|
setting_validate_certificates: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
@@ -102,6 +103,10 @@ impl<'a> ClientDb<'a> {
|
|||||||
workspace.setting_request_timeout,
|
workspace.setting_request_timeout,
|
||||||
AnyModel::Workspace(workspace.clone()),
|
AnyModel::Workspace(workspace.clone()),
|
||||||
),
|
),
|
||||||
|
request_message_size: ResolvedSetting::from_model(
|
||||||
|
workspace.setting_request_message_size,
|
||||||
|
AnyModel::Workspace(workspace.clone()),
|
||||||
|
),
|
||||||
send_cookies: ResolvedSetting::from_model(
|
send_cookies: ResolvedSetting::from_model(
|
||||||
workspace.setting_send_cookies,
|
workspace.setting_send_cookies,
|
||||||
AnyModel::Workspace(workspace.clone()),
|
AnyModel::Workspace(workspace.clone()),
|
||||||
|
|||||||
+4
@@ -108,6 +108,7 @@ export type Folder = {
|
|||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
settingFollowRedirects: InheritedBoolSetting;
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
settingRequestTimeout: InheritedIntSetting;
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GraphQlIntrospection = {
|
export type GraphQlIntrospection = {
|
||||||
@@ -183,6 +184,7 @@ export type GrpcRequest = {
|
|||||||
*/
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HttpRequest = {
|
export type HttpRequest = {
|
||||||
@@ -450,6 +452,7 @@ export type WebsocketRequest = {
|
|||||||
settingSendCookies: InheritedBoolSetting;
|
settingSendCookies: InheritedBoolSetting;
|
||||||
settingStoreCookies: InheritedBoolSetting;
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Workspace = {
|
export type Workspace = {
|
||||||
@@ -466,6 +469,7 @@ export type Workspace = {
|
|||||||
settingValidateCertificates: boolean;
|
settingValidateCertificates: boolean;
|
||||||
settingFollowRedirects: boolean;
|
settingFollowRedirects: boolean;
|
||||||
settingRequestTimeout: number;
|
settingRequestTimeout: number;
|
||||||
|
settingRequestMessageSize: number;
|
||||||
settingDnsOverrides: Array<DnsOverride>;
|
settingDnsOverrides: Array<DnsOverride>;
|
||||||
settingSendCookies: boolean;
|
settingSendCookies: boolean;
|
||||||
settingStoreCookies: boolean;
|
settingStoreCookies: boolean;
|
||||||
|
|||||||
Generated
+4
@@ -46,6 +46,7 @@ export type Folder = {
|
|||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
settingFollowRedirects: InheritedBoolSetting;
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
settingRequestTimeout: InheritedIntSetting;
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GrpcRequest = {
|
export type GrpcRequest = {
|
||||||
@@ -69,6 +70,7 @@ export type GrpcRequest = {
|
|||||||
*/
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HttpRequest = {
|
export type HttpRequest = {
|
||||||
@@ -159,6 +161,7 @@ export type WebsocketRequest = {
|
|||||||
settingSendCookies: InheritedBoolSetting;
|
settingSendCookies: InheritedBoolSetting;
|
||||||
settingStoreCookies: InheritedBoolSetting;
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Workspace = {
|
export type Workspace = {
|
||||||
@@ -175,6 +178,7 @@ export type Workspace = {
|
|||||||
settingValidateCertificates: boolean;
|
settingValidateCertificates: boolean;
|
||||||
settingFollowRedirects: boolean;
|
settingFollowRedirects: boolean;
|
||||||
settingRequestTimeout: number;
|
settingRequestTimeout: number;
|
||||||
|
settingRequestMessageSize: number;
|
||||||
settingDnsOverrides: Array<DnsOverride>;
|
settingDnsOverrides: Array<DnsOverride>;
|
||||||
settingSendCookies: boolean;
|
settingSendCookies: boolean;
|
||||||
settingStoreCookies: boolean;
|
settingStoreCookies: boolean;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ pub async fn ws_connect(
|
|||||||
headers: HeaderMap<HeaderValue>,
|
headers: HeaderMap<HeaderValue>,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
request_message_size: i32,
|
||||||
) -> Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response)> {
|
) -> Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response)> {
|
||||||
info!("Connecting to WS {url}");
|
info!("Connecting to WS {url}");
|
||||||
let tls_config = get_tls_config(validate_certificates, WITH_ALPN, client_cert.clone())?;
|
let tls_config = get_tls_config(validate_certificates, WITH_ALPN, client_cert.clone())?;
|
||||||
@@ -34,7 +35,7 @@ pub async fn ws_connect(
|
|||||||
|
|
||||||
let (stream, response) = connect_async_tls_with_config(
|
let (stream, response) = connect_async_tls_with_config(
|
||||||
req,
|
req,
|
||||||
Some(WebSocketConfig::default()),
|
Some(websocket_config(request_message_size)),
|
||||||
false,
|
false,
|
||||||
Some(Connector::Rustls(Arc::new(tls_config))),
|
Some(Connector::Rustls(Arc::new(tls_config))),
|
||||||
)
|
)
|
||||||
@@ -48,3 +49,12 @@ pub async fn ws_connect(
|
|||||||
|
|
||||||
Ok((stream, response))
|
Ok((stream, response))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn websocket_config(request_message_size: i32) -> WebSocketConfig {
|
||||||
|
let max_message_size = message_size_limit(request_message_size);
|
||||||
|
WebSocketConfig::default().max_message_size(max_message_size).max_frame_size(max_message_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn message_size_limit(setting: i32) -> Option<usize> {
|
||||||
|
setting.try_into().ok().filter(|limit| *limit > 0)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::connect::ws_connect;
|
use crate::connect::{message_size_limit, ws_connect};
|
||||||
|
use crate::error::Error::GenericError;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use futures_util::stream::SplitSink;
|
use futures_util::stream::SplitSink;
|
||||||
use futures_util::{SinkExt, StreamExt};
|
use futures_util::{SinkExt, StreamExt};
|
||||||
@@ -15,10 +16,16 @@ use tokio_tungstenite::tungstenite::http::HeaderValue;
|
|||||||
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
|
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
|
||||||
use yaak_tls::ClientCertificateConfig;
|
use yaak_tls::ClientCertificateConfig;
|
||||||
|
|
||||||
|
type WebsocketSink = SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>;
|
||||||
|
|
||||||
|
struct WebsocketConnection {
|
||||||
|
max_message_size: Option<usize>,
|
||||||
|
sink: WebsocketSink,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WebsocketManager {
|
pub struct WebsocketManager {
|
||||||
connections:
|
connections: Arc<Mutex<HashMap<String, WebsocketConnection>>>,
|
||||||
Arc<Mutex<HashMap<String, SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>>>>,
|
|
||||||
read_tasks: Arc<Mutex<HashMap<String, tokio::task::JoinHandle<()>>>>,
|
read_tasks: Arc<Mutex<HashMap<String, tokio::task::JoinHandle<()>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,14 +42,20 @@ impl WebsocketManager {
|
|||||||
receive_tx: mpsc::Sender<Message>,
|
receive_tx: mpsc::Sender<Message>,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
client_cert: Option<ClientCertificateConfig>,
|
client_cert: Option<ClientCertificateConfig>,
|
||||||
|
request_message_size: i32,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
let tx = receive_tx.clone();
|
let tx = receive_tx.clone();
|
||||||
|
let max_message_size = message_size_limit(request_message_size);
|
||||||
|
|
||||||
let (stream, response) =
|
let (stream, response) =
|
||||||
ws_connect(url, headers, validate_certificates, client_cert).await?;
|
ws_connect(url, headers, validate_certificates, client_cert, request_message_size)
|
||||||
|
.await?;
|
||||||
let (write, mut read) = stream.split();
|
let (write, mut read) = stream.split();
|
||||||
|
|
||||||
self.connections.lock().await.insert(id.to_string(), write);
|
self.connections
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.insert(id.to_string(), WebsocketConnection { max_message_size, sink: write });
|
||||||
|
|
||||||
let handle = {
|
let handle = {
|
||||||
let connection_id = id.to_string();
|
let connection_id = id.to_string();
|
||||||
@@ -76,7 +89,15 @@ impl WebsocketManager {
|
|||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
};
|
};
|
||||||
connection.send(msg).await?;
|
if let Some(limit) = connection.max_message_size {
|
||||||
|
let message_size = msg.len();
|
||||||
|
if message_size > limit {
|
||||||
|
return Err(GenericError(format!(
|
||||||
|
"WebSocket message too large: found {message_size} bytes, the limit is {limit} bytes"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connection.sink.send(msg).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +105,7 @@ impl WebsocketManager {
|
|||||||
info!("Closing websocket");
|
info!("Closing websocket");
|
||||||
if let Some(mut connection) = self.connections.lock().await.remove(id) {
|
if let Some(mut connection) = self.connections.lock().await.remove(id) {
|
||||||
// Wait a maximum of 1 second for the connection to close
|
// Wait a maximum of 1 second for the connection to close
|
||||||
if let Err(e) = connection.close().await {
|
if let Err(e) = connection.sink.close().await {
|
||||||
warn!("Failed to close websocket connection {e:?}");
|
warn!("Failed to close websocket connection {e:?}");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ export type Folder = {
|
|||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
settingFollowRedirects: InheritedBoolSetting;
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
settingRequestTimeout: InheritedIntSetting;
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GraphQlIntrospection = {
|
export type GraphQlIntrospection = {
|
||||||
@@ -183,6 +184,7 @@ export type GrpcRequest = {
|
|||||||
*/
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HttpRequest = {
|
export type HttpRequest = {
|
||||||
@@ -450,6 +452,7 @@ export type WebsocketRequest = {
|
|||||||
settingSendCookies: InheritedBoolSetting;
|
settingSendCookies: InheritedBoolSetting;
|
||||||
settingStoreCookies: InheritedBoolSetting;
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
settingValidateCertificates: InheritedBoolSetting;
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingRequestMessageSize: InheritedIntSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Workspace = {
|
export type Workspace = {
|
||||||
@@ -466,6 +469,7 @@ export type Workspace = {
|
|||||||
settingValidateCertificates: boolean;
|
settingValidateCertificates: boolean;
|
||||||
settingFollowRedirects: boolean;
|
settingFollowRedirects: boolean;
|
||||||
settingRequestTimeout: number;
|
settingRequestTimeout: number;
|
||||||
|
settingRequestMessageSize: number;
|
||||||
settingDnsOverrides: Array<DnsOverride>;
|
settingDnsOverrides: Array<DnsOverride>;
|
||||||
settingSendCookies: boolean;
|
settingSendCookies: boolean;
|
||||||
settingStoreCookies: boolean;
|
settingStoreCookies: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user