mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-12 05:48:57 +00:00
Improve OpenAPI server URL validation (#3937)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/react-openapi": patch
|
||||
---
|
||||
|
||||
Improve OpenAPI server URL validation
|
||||
@@ -11,7 +11,7 @@ import { generateMediaTypeExamples, generateSchemaExample } from './generateSche
|
||||
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
||||
import type { OpenAPIOperationData } from './types';
|
||||
import { mergeHeaders } from './util/headers';
|
||||
import { getDefaultServerURL } from './util/server';
|
||||
import { getDefaultServerURL, hasValidServerHost } from './util/server';
|
||||
import {
|
||||
resolvePrefillCodePlaceholderFromSecurityScheme,
|
||||
resolveURLWithPrefillCodePlaceholdersFromServer,
|
||||
@@ -216,11 +216,14 @@ function OpenAPICodeSampleFooter(props: {
|
||||
const hasMultipleMediaTypes =
|
||||
renderers.length > 1 || renderers.some((renderer) => renderer.examples.length > 0);
|
||||
|
||||
// Check if any server has a host that can be used in an HTTP request
|
||||
const hasValidHost = hasValidServerHost(servers);
|
||||
|
||||
if (hideTryItPanel && !hasMultipleMediaTypes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!validateHttpMethod(method) || (!hasMultipleMediaTypes && servers.length === 0)) {
|
||||
if (!validateHttpMethod(method) || (!hasMultipleMediaTypes && !hasValidHost)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -237,7 +240,7 @@ function OpenAPICodeSampleFooter(props: {
|
||||
) : (
|
||||
<span />
|
||||
)}
|
||||
{!hideTryItPanel && servers.length > 0 && (
|
||||
{!hideTryItPanel && hasValidHost && (
|
||||
<ScalarApiButton
|
||||
context={getOpenAPIClientContext(context)}
|
||||
method={method}
|
||||
|
||||
@@ -18,6 +18,14 @@ export function OpenAPIMediaTypeExamplesSelector(props: {
|
||||
const state = useSelectState(stateKey, renderers[0].mediaType);
|
||||
const selected = renderers.find((r) => r.mediaType === state.key) || renderers[0];
|
||||
|
||||
const hasMultipleMediaTypes = renderers.length >= 2;
|
||||
const hasMultipleExamples = selected.examples.length >= 2;
|
||||
|
||||
// Only render the wrapper div if at least one selector will render
|
||||
if (!hasMultipleMediaTypes && !hasMultipleExamples) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="openapi-codesample-selectors">
|
||||
<MediaTypeSelector selectIcon={selectIcon} stateKey={stateKey} renderers={renderers} />
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from './contentTypeChecks';
|
||||
import { json2xml } from './json2xml';
|
||||
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
||||
import { isValidServerHost } from './util/server';
|
||||
|
||||
export interface CodeSampleInput {
|
||||
method: string;
|
||||
@@ -69,9 +70,12 @@ export const codeSampleGenerators: CodeSampleGenerator[] = [
|
||||
|
||||
const bodyString = body ? `\n${body}` : '';
|
||||
|
||||
// Only include Host header if origin is considered a valid server host
|
||||
const hasValidHost = isValidServerHost(origin);
|
||||
const hostLine = hasValidHost ? `Host: ${origin.replaceAll(/https?:\/\//g, '')}\n` : '';
|
||||
|
||||
const httpRequest = `${method.toUpperCase()} ${decodeURI(path)} HTTP/1.1
|
||||
Host: ${origin.replaceAll(/https*:\/\//g, '')}
|
||||
${headerString}${bodyString}`;
|
||||
${hostLine}${headerString}${bodyString}`;
|
||||
|
||||
return httpRequest;
|
||||
},
|
||||
|
||||
@@ -45,3 +45,31 @@ function parseServerURL(url: string) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any server has a host that can be used in an HTTP request.
|
||||
* This is used to determine if the "Try it" button should be shown.
|
||||
*/
|
||||
export function hasValidServerHost(servers: OpenAPIV3.ServerObject[]): boolean {
|
||||
if (servers.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return servers.some((server) => {
|
||||
const url = interpolateServerURL(server);
|
||||
return isValidServerHost(url);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the server host/URL is valid for making direct HTTP requests.
|
||||
* Accepts both full URLs (with protocol) and hostnames (without protocol).
|
||||
*/
|
||||
export function isValidServerHost(url: string): boolean {
|
||||
// Check if URL starts with http:// or https://
|
||||
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return /^(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/.test(url);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user