mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-17 00:56:37 +01:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b84545b67 | ||
|
|
0e28079965 | ||
|
|
5d5f9cc943 | ||
|
|
b71bc2cc92 |
@@ -34,18 +34,18 @@ export async function convertToCurl(request: Partial<HttpRequest>) {
|
||||
let finalUrl = request.url || '';
|
||||
const urlParams = (request.urlParameters ?? []).filter(onlyEnabled);
|
||||
if (urlParams.length > 0) {
|
||||
// Build url
|
||||
// Build url
|
||||
const [base, hash] = finalUrl.split('#');
|
||||
const separator = base!.includes('?') ? '&' : '?';
|
||||
const queryString = urlParams
|
||||
.map(p => `${encodeURIComponent(p.name)}=${encodeURIComponent(p.value)}`)
|
||||
.map((p) => `${encodeURIComponent(p.name)}=${encodeURIComponent(p.value)}`)
|
||||
.join('&');
|
||||
finalUrl = base + separator + queryString + (hash ? `#${hash}` : '');
|
||||
}
|
||||
|
||||
|
||||
xs.push(quote(finalUrl));
|
||||
xs.push(NEWLINE);
|
||||
|
||||
|
||||
// Add headers
|
||||
for (const h of (request.headers ?? []).filter(onlyEnabled)) {
|
||||
xs.push('--header', quote(`${h.name}: ${h.value}`));
|
||||
@@ -53,7 +53,11 @@ export async function convertToCurl(request: Partial<HttpRequest>) {
|
||||
}
|
||||
|
||||
// Add form params
|
||||
if (Array.isArray(request.body?.form)) {
|
||||
const type = request.bodyType ?? 'none';
|
||||
if (
|
||||
(type === 'multipart/form-data' || type === 'application/x-www-form-urlencoded') &&
|
||||
Array.isArray(request.body?.form)
|
||||
) {
|
||||
const flag = request.bodyType === 'multipart/form-data' ? '--form' : '--data';
|
||||
for (const p of (request.body?.form ?? []).filter(onlyEnabled)) {
|
||||
if (p.file) {
|
||||
@@ -65,14 +69,14 @@ export async function convertToCurl(request: Partial<HttpRequest>) {
|
||||
}
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
} else if (typeof request.body?.query === 'string') {
|
||||
} else if (type === 'graphql' && typeof request.body?.query === 'string') {
|
||||
const body = {
|
||||
query: request.body.query || '',
|
||||
variables: maybeParseJSON(request.body.variables, undefined),
|
||||
};
|
||||
xs.push('--data', quote(JSON.stringify(body)));
|
||||
xs.push(NEWLINE);
|
||||
} else if (typeof request.body?.text === 'string') {
|
||||
} else if (type !== 'none' && typeof request.body?.text === 'string') {
|
||||
xs.push('--data', quote(request.body.text));
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
@@ -116,4 +120,4 @@ function maybeParseJSON<T>(v: string, fallback: T) {
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('exporter-curl', () => {
|
||||
],
|
||||
}),
|
||||
).toEqual(
|
||||
[`curl 'https://yaak.app/?a=aaa&b=bbb'`].join(` \\n `),
|
||||
[`curl 'https://yaak.app?a=aaa&b=bbb'`].join(` \\n `),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -218,4 +218,16 @@ describe('exporter-curl', () => {
|
||||
}),
|
||||
).toEqual([`curl 'https://yaak.app'`, `--header 'Authorization: Bearer '`].join(` \\\n `));
|
||||
});
|
||||
});
|
||||
|
||||
test('Stale body data', async () => {
|
||||
expect(
|
||||
await convertToCurl({
|
||||
url: 'https://yaak.app',
|
||||
bodyType: 'none',
|
||||
body: {
|
||||
text: 'ignore me',
|
||||
}
|
||||
}),
|
||||
).toEqual([`curl 'https://yaak.app'`].join(` \\\n `));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -111,7 +111,7 @@ pub async fn send_http_request<R: Runtime>(
|
||||
.referer(false)
|
||||
.tls_info(true);
|
||||
|
||||
let tls_config = yaak_http::tls::get_config(workspace.setting_validate_certificates);
|
||||
let tls_config = yaak_http::tls::get_config(workspace.setting_validate_certificates, true);
|
||||
client_builder = client_builder.use_preconfigured_tls(tls_config);
|
||||
|
||||
match settings.proxy {
|
||||
|
||||
@@ -4,8 +4,11 @@ use hyper_util::client::legacy::Client;
|
||||
use hyper_util::rt::TokioExecutor;
|
||||
use tonic::body::BoxBody;
|
||||
|
||||
// I think ALPN breaks this because we're specifying http2_only
|
||||
const WITH_ALPN: bool = false;
|
||||
|
||||
pub(crate) fn get_transport(validate_certificates: bool) -> Client<HttpsConnector<HttpConnector>, BoxBody> {
|
||||
let tls_config = yaak_http::tls::get_config(validate_certificates);
|
||||
let tls_config = yaak_http::tls::get_config(validate_certificates, WITH_ALPN);
|
||||
|
||||
let mut http = HttpConnector::new();
|
||||
http.enforce_http(false);
|
||||
|
||||
@@ -5,7 +5,7 @@ use rustls::{ClientConfig, DigitallySignedStruct, SignatureScheme};
|
||||
use rustls_platform_verifier::BuilderVerifierExt;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn get_config(validate_certificates: bool) -> ClientConfig {
|
||||
pub fn get_config(validate_certificates: bool, with_alpn: bool) -> ClientConfig {
|
||||
let arc_crypto_provider = Arc::new(ring::default_provider());
|
||||
let config_builder = ClientConfig::builder_with_provider(arc_crypto_provider)
|
||||
.with_safe_default_protocol_versions()
|
||||
@@ -19,8 +19,11 @@ pub fn get_config(validate_certificates: bool) -> ClientConfig {
|
||||
.with_custom_certificate_verifier(Arc::new(NoVerifier))
|
||||
.with_no_client_auth()
|
||||
};
|
||||
// Required for http/2 support
|
||||
client.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
||||
|
||||
if with_alpn {
|
||||
client.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
||||
}
|
||||
|
||||
client
|
||||
}
|
||||
|
||||
|
||||
@@ -7,16 +7,19 @@ use tokio_tungstenite::tungstenite::handshake::client::Response;
|
||||
use tokio_tungstenite::tungstenite::http::HeaderValue;
|
||||
use tokio_tungstenite::tungstenite::protocol::WebSocketConfig;
|
||||
use tokio_tungstenite::{
|
||||
connect_async_tls_with_config, Connector, MaybeTlsStream, WebSocketStream,
|
||||
Connector, MaybeTlsStream, WebSocketStream, connect_async_tls_with_config,
|
||||
};
|
||||
|
||||
// Enabling ALPN breaks websocket requests
|
||||
const WITH_ALPN: bool = false;
|
||||
|
||||
pub(crate) async fn ws_connect(
|
||||
url: &str,
|
||||
headers: HeaderMap<HeaderValue>,
|
||||
validate_certificates: bool,
|
||||
) -> crate::error::Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response)> {
|
||||
info!("Connecting to WS {url}");
|
||||
let tls_config = yaak_http::tls::get_config(validate_certificates);
|
||||
let tls_config = yaak_http::tls::get_config(validate_certificates, WITH_ALPN);
|
||||
|
||||
let mut req = url.into_client_request()?;
|
||||
let req_headers = req.headers_mut();
|
||||
@@ -34,4 +37,4 @@ pub(crate) async fn ws_connect(
|
||||
)
|
||||
.await?;
|
||||
Ok((stream, response))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ function GrpcProtoSelectionDialogWithRequest({ request }: Props & { request: Grp
|
||||
return (
|
||||
<VStack className="flex-col-reverse mb-3" space={3}>
|
||||
{/* Buttons on top so they get focus first */}
|
||||
<HStack space={2} justifyContent="start" className="flex-row-reverse">
|
||||
<HStack space={2} justifyContent="start" className="flex-row-reverse mt-3">
|
||||
<Button
|
||||
color="primary"
|
||||
variant="border"
|
||||
@@ -135,9 +135,7 @@ function GrpcProtoSelectionDialogWithRequest({ request }: Props & { request: Grp
|
||||
<table className="w-full divide-y divide-surface-highlight">
|
||||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
<th className="text-text-subtlest">Added File Paths</th>
|
||||
<th />
|
||||
<th className="text-text-subtlest" colSpan={3}>Added File Paths</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-surface-highlight">
|
||||
|
||||
@@ -21,9 +21,10 @@ export function WebPageViewer({ response }: Props) {
|
||||
<div className="h-full pb-3">
|
||||
<iframe
|
||||
key={body ? 'has-body' : 'no-body'}
|
||||
title="Response preview"
|
||||
title="Yaak response preview"
|
||||
srcDoc={contentForIframe}
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
sandbox="allow-scripts allow-forms"
|
||||
referrerPolicy="no-referrer"
|
||||
className="h-full w-full rounded border border-border-subtle"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -108,12 +108,11 @@ export function useIntrospectGraphQL(
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const schema = buildClientSchema(JSON.parse(introspection.data.content).data);
|
||||
setSchema(schema);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
setError('message' in e ? e.message : String(e));
|
||||
const parseResult = tryParseIntrospectionToSchema(introspection.data.content);
|
||||
if ('error' in parseResult) {
|
||||
setError(parseResult.error);
|
||||
} else {
|
||||
setSchema(parseResult.schema);
|
||||
}
|
||||
}, [introspection.data?.content]);
|
||||
|
||||
@@ -135,7 +134,26 @@ export function useCurrentGraphQLSchema(request: HttpRequest) {
|
||||
return useMemo(() => {
|
||||
if (result.data == null) return null;
|
||||
if (result.data.content == null || result.data.content === '') return null;
|
||||
const schema = buildClientSchema(JSON.parse(result.data.content).data);
|
||||
return schema;
|
||||
const r = tryParseIntrospectionToSchema(result.data.content);
|
||||
return 'error' in r ? null : r.schema;
|
||||
}, [result.data]);
|
||||
}
|
||||
|
||||
function tryParseIntrospectionToSchema(
|
||||
content: string,
|
||||
): { schema: GraphQLSchema } | { error: string } {
|
||||
let parsedResponse;
|
||||
try {
|
||||
parsedResponse = JSON.parse(content).data;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
return { error: String('message' in e ? e.message : e) };
|
||||
}
|
||||
|
||||
try {
|
||||
return { schema: buildClientSchema(parsedResponse, {}) };
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
return { error: String('message' in e ? e.message : e) };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user