Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve URL handling in JS Client #8258

Merged
merged 23 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
43cb45e
amend endpoint logic
hannahblair May 10, 2024
3c138db
add changeset
gradio-pr-bot May 10, 2024
6edf585
improve url joining for local URLs
hannahblair May 10, 2024
e0f08f6
Merge branch 'root-url-client' of https://github.com/gradio-app/gradi…
hannahblair May 10, 2024
9dc4075
handle relative paths
hannahblair May 13, 2024
1108852
Merge branch 'main' into root-url-client
hannahblair May 13, 2024
63b49fe
Merge branch 'main' into root-url-client
hannahblair May 13, 2024
aa216d2
Merge branch 'main' into root-url-client
abidlabs May 13, 2024
13ee395
Merge branch 'main' into root-url-client
hannahblair May 14, 2024
a60c128
use join_urls in /info to ensure correct endpoints
hannahblair May 14, 2024
c58a506
add relative url logic and throw error for node
hannahblair May 14, 2024
85cf039
Merge branch 'main' into root-url-client
hannahblair May 14, 2024
5ae420f
tweaks
hannahblair May 14, 2024
7b8f611
Merge branch 'root-url-client' of https://github.com/gradio-app/gradi…
hannahblair May 14, 2024
2f4f709
remove relative paths support (wont work)
hannahblair May 14, 2024
e260ab4
tweak
hannahblair May 14, 2024
9b06305
tweak func to throw error and amend tests
hannahblair May 21, 2024
1cfa209
tweak
hannahblair May 22, 2024
34929f7
accomodate . in space names
hannahblair May 22, 2024
2c12f12
replace error with const msg
hannahblair May 22, 2024
1993fe7
tweak tests with error var
hannahblair May 22, 2024
662c94f
Merge branch 'main' into root-url-client
hannahblair May 22, 2024
f17855c
revert map() to reduce() due to misinterpreted base URL
hannahblair May 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/sad-feet-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@gradio/client": patch
"gradio": patch
---

fix:Improve URL handling in JS Client
16 changes: 12 additions & 4 deletions client/js/src/helpers/api_info.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Status } from "../types";
import { QUEUE_FULL_MSG } from "../constants";
import { HOST_URL, QUEUE_FULL_MSG } from "../constants";
import type { ApiData, ApiInfo, Config, JsApiData } from "../types";
import { determine_protocol } from "./init_helpers";

export const RE_SPACE_NAME = /^[^\/]*\/[^\/]*$/;
export const RE_SPACE_NAME = /^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-]+$/;
hannahblair marked this conversation as resolved.
Show resolved Hide resolved
export const RE_SPACE_DOMAIN = /.*hf\.space\/{0,1}$/;

export async function process_endpoint(
Expand All @@ -20,12 +20,13 @@ export async function process_endpoint(
headers.Authorization = `Bearer ${hf_token}`;
}

const _app_reference = app_reference.trim();
const _app_reference = app_reference.trim().replace(/\/$/, "");

if (RE_SPACE_NAME.test(_app_reference)) {
// app_reference is a HF space name
try {
const res = await fetch(
`https://huggingface.co/api/spaces/${_app_reference}/host`,
`https://huggingface.co/api/spaces/${_app_reference}/${HOST_URL}`,
{ headers }
);

Expand All @@ -43,6 +44,7 @@ export async function process_endpoint(
}

if (RE_SPACE_DOMAIN.test(_app_reference)) {
// app_reference is a direct HF space domain
const { ws_protocol, http_protocol, host } =
determine_protocol(_app_reference);

Expand All @@ -60,6 +62,12 @@ export async function process_endpoint(
};
}

export const join_urls = (...urls: string[]): string => {
return urls.reduce((base_url, part) => {
return `${base_url.replace(/\/+$/, "")}/${part.replace(/^\/+/, "")}`;
});
};

pngwn marked this conversation as resolved.
Show resolved Hide resolved
export function transform_api_info(
api_info: ApiInfo<ApiData>,
config: Config,
Expand Down
8 changes: 5 additions & 3 deletions client/js/src/helpers/init_helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Config } from "../types";
import { CONFIG_ERROR_MSG, CONFIG_URL } from "../constants";
import { Client } from "..";
import { join_urls } from "./api_info";

/**
* This function is used to resolve the URL for making requests when the app has a root path.
Expand Down Expand Up @@ -75,7 +76,8 @@ export async function resolve_config(
config.root = config_root;
return { ...config, path } as Config;
} else if (endpoint) {
const response = await this.fetch(`${endpoint}/${CONFIG_URL}`, {
const config_url = join_urls(endpoint, CONFIG_URL);
const response = await this.fetch(config_url, {
headers
});

Expand All @@ -97,7 +99,7 @@ export function determine_protocol(endpoint: string): {
host: string;
} {
if (endpoint.startsWith("http")) {
const { protocol, host } = new URL(endpoint);
const { protocol, host, pathname } = new URL(endpoint);

if (host.endsWith("hf.space")) {
return {
Expand All @@ -109,7 +111,7 @@ export function determine_protocol(endpoint: string): {
return {
ws_protocol: protocol === "https:" ? "wss" : "ws",
http_protocol: protocol as "http:" | "https:",
host
host: host + (pathname !== "/" ? pathname : "")
};
} else if (endpoint.startsWith("file:")) {
// This case is only expected to be used for the Wasm mode (Gradio-lite),
Expand Down
47 changes: 47 additions & 0 deletions client/js/src/test/api_info.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import {
get_description,
get_type,
process_endpoint,
join_urls,
map_data_to_params
} from "../helpers/api_info";
import { initialise_server } from "./server";
import { transformed_api_info } from "./test_data";

const server = initialise_server();
const IS_NODE = process.env.TEST_MODE === "node";

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
Expand Down Expand Up @@ -455,6 +457,51 @@ describe("process_endpoint", () => {
const result = await process_endpoint("hmb/hello_world");
expect(result).toEqual(expected);
});

it("processes local server URLs correctly", async () => {
if (!IS_NODE) {
const local_url = "http://localhost:7860/gradio";
const response_local_url = await process_endpoint(local_url);
expect(response_local_url.space_id).toBe(false);
expect(response_local_url.host).toBe("localhost:7860/gradio");

const local_url_2 = "http://localhost:7860/gradio/";
const response_local_url_2 = await process_endpoint(local_url_2);
expect(response_local_url_2.space_id).toBe(false);
expect(response_local_url_2.host).toBe("localhost:7860/gradio");
}
});

it("handles hugging face space references", async () => {
const space_id = "hmb/hello_world";

const response = await process_endpoint(space_id);
expect(response.space_id).toBe(space_id);
expect(response.host).toContain("hf.space");
});

it("handles hugging face domain URLs", async () => {
const app_reference = "https://hmb-hello-world.hf.space/";
const response = await process_endpoint(app_reference);
expect(response.space_id).toBe("hmb-hello-world");
expect(response.host).toBe("hmb-hello-world.hf.space");
});
});

describe("join_urls", () => {
it("joins URLs correctly", () => {
expect(join_urls("localhost:7860", "/gradio")).toBe(
"localhost:7860/gradio"
);

expect(join_urls("localhost:7860/", "/gradio")).toBe(
"localhost:7860/gradio"
);

expect(join_urls("localhost:7860/", "/app/", "/gradio/")).toBe(
"localhost:7860/app/gradio/"
);
});
});

describe("map_data_params", () => {
Expand Down
5 changes: 3 additions & 2 deletions client/js/src/utils/view_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import semiver from "semiver";
import { API_INFO_URL, BROKEN_CONNECTION_MSG } from "../constants";
import { Client } from "../client";
import { SPACE_FETCHER_URL } from "../constants";
import { transform_api_info } from "../helpers/api_info";
import { join_urls, transform_api_info } from "../helpers/api_info";

export async function view_api(this: Client): Promise<any> {
if (this.api_info) return this.api_info;
Expand Down Expand Up @@ -37,7 +37,8 @@ export async function view_api(this: Client): Promise<any> {
headers
});
} else {
response = await this.fetch(`${config?.root}/${API_INFO_URL}`, {
const url = join_urls(config.root, API_INFO_URL);
response = await this.fetch(url, {
headers
});
}
Expand Down