Merge pull request #151 from xixu-me/hf-api-support-4915912814412665047
Support Hugging Face API operations
This commit is contained in:
3 files changed
+87
-13
No files matched your search
+18
-9
@@ -11,6 +11,7 @@
|
||||
import { CONFIG, createConfig } from './config/index.js';
|
||||
import { SORTED_PLATFORMS, transformPath } from './config/platforms.js';
|
||||
import { configureAIHeaders, isAIInferenceRequest } from './protocols/ai.js';
|
||||
import { configureHuggingFaceHeaders, isHuggingFaceAPIRequest } from './protocols/huggingface.js';
|
||||
import {
|
||||
fetchToken,
|
||||
getScopeFromUrl,
|
||||
@@ -126,7 +127,10 @@ async function handleRequest(request, env, ctx) {
|
||||
// Check if this is an AI inference request
|
||||
const isAI = isAIInferenceRequest(request, url);
|
||||
|
||||
// Check cache first (skip cache for Git, Git LFS, Docker, and AI inference operations)
|
||||
// Check if this is a Hugging Face API request
|
||||
const isHF = isHuggingFaceAPIRequest(request, url);
|
||||
|
||||
// Check cache first (skip cache for Git, Git LFS, Docker, AI inference, and HF API operations)
|
||||
/** @type {Cache | null} */
|
||||
// @ts-ignore - Cloudflare Workers cache API
|
||||
const cache =
|
||||
@@ -134,7 +138,7 @@ async function handleRequest(request, env, ctx) {
|
||||
? /** @type {any} */ (caches).default // eslint-disable-line jsdoc/reject-any-type
|
||||
: null;
|
||||
|
||||
if (cache && !isGit && !isGitLFS && !isDocker && !isAI) {
|
||||
if (cache && !isGit && !isGitLFS && !isDocker && !isAI && !isHF) {
|
||||
try {
|
||||
// For Range requests, try cache match first
|
||||
const cacheKey = new Request(targetUrl, {
|
||||
@@ -177,10 +181,10 @@ async function handleRequest(request, env, ctx) {
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
// Add body for POST/PUT/PATCH requests (Git/Docker/AI inference operations)
|
||||
// Add body for POST/PUT/PATCH/DELETE requests (Git/Docker/AI/HF operations)
|
||||
if (
|
||||
['POST', 'PUT', 'PATCH'].includes(request.method) &&
|
||||
(isGit || isGitLFS || isDocker || isAI)
|
||||
['POST', 'PUT', 'PATCH', 'DELETE'].includes(request.method) &&
|
||||
(isGit || isGitLFS || isDocker || isAI || isHF)
|
||||
) {
|
||||
fetchOptions.body = request.body;
|
||||
}
|
||||
@@ -188,9 +192,9 @@ async function handleRequest(request, env, ctx) {
|
||||
// Cast headers to Headers for proper typing
|
||||
const requestHeaders = /** @type {Headers} */ (fetchOptions.headers);
|
||||
|
||||
// Set appropriate headers for Git/Docker/AI vs regular requests
|
||||
if (isGit || isGitLFS || isDocker || isAI) {
|
||||
// For Git/Docker/AI operations, copy all headers from the original request
|
||||
// Set appropriate headers for Git/Docker/AI/HF vs regular requests
|
||||
if (isGit || isGitLFS || isDocker || isAI || isHF) {
|
||||
// For Git/Docker/AI/HF operations, copy all headers from the original request
|
||||
// This ensures protocol compliance
|
||||
for (const [key, value] of request.headers.entries()) {
|
||||
// Skip headers that might cause issues with proxying
|
||||
@@ -209,6 +213,10 @@ async function handleRequest(request, env, ctx) {
|
||||
if (isAI) {
|
||||
configureAIHeaders(requestHeaders, request);
|
||||
}
|
||||
|
||||
if (isHF) {
|
||||
configureHuggingFaceHeaders(requestHeaders, request);
|
||||
}
|
||||
} else {
|
||||
// Regular file download headers
|
||||
Object.assign(fetchOptions, {
|
||||
@@ -617,8 +625,9 @@ async function handleRequest(request, env, ctx) {
|
||||
const isDocker = isDockerRequest(request, new URL(request.url));
|
||||
const isAI = isAIInferenceRequest(request, new URL(request.url));
|
||||
const isGitLFS = isGitLFSRequest(request, new URL(request.url));
|
||||
const isHF = isHuggingFaceAPIRequest(request, new URL(request.url));
|
||||
|
||||
return isGit || isGitLFS || isDocker || isAI
|
||||
return isGit || isGitLFS || isDocker || isAI || isHF
|
||||
? response
|
||||
: addPerformanceHeaders(response, monitor);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Xget - High-performance acceleration engine for developer resources
|
||||
* Copyright (C) 2025 Xi Xu
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Hugging Face protocol handler for Xget
|
||||
*/
|
||||
|
||||
/**
|
||||
* Detects if a request is a Hugging Face API operation.
|
||||
*
|
||||
* Identifies Hugging Face API requests by checking for:
|
||||
* - Hugging Face platform prefix (/hf/)
|
||||
* - API path segment (/api/)
|
||||
*
|
||||
* @param {Request} request - The incoming request object
|
||||
* @param {URL} url - Parsed URL object
|
||||
* @returns {boolean} True if this is a Hugging Face API operation
|
||||
*/
|
||||
export function isHuggingFaceAPIRequest(request, url) {
|
||||
// Check for Hugging Face API endpoints
|
||||
if (url.pathname.startsWith('/hf/api/')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Also check for token endpoint which is often used
|
||||
if (url.pathname.startsWith('/hf/token')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures headers for Hugging Face API requests.
|
||||
*
|
||||
* @param {Headers} headers - The headers object to modify
|
||||
* @param {Request} request - The original request
|
||||
*/
|
||||
export function configureHuggingFaceHeaders(headers, request) {
|
||||
// Pass through Authorization header if present
|
||||
if (request.headers.has('Authorization')) {
|
||||
headers.set('Authorization', request.headers.get('Authorization'));
|
||||
}
|
||||
|
||||
if (request.method === 'POST' && !headers.has('Content-Type')) {
|
||||
headers.set('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import { CONFIG } from '../config/index.js';
|
||||
// Imported protocol checks
|
||||
import { isAIInferenceRequest } from '../protocols/ai.js';
|
||||
import { isGitLFSRequest, isGitRequest } from '../protocols/git.js';
|
||||
import { isHuggingFaceAPIRequest } from '../protocols/huggingface.js';
|
||||
|
||||
/**
|
||||
* Detects if a request is a container registry operation (Docker/OCI).
|
||||
@@ -72,7 +73,7 @@ export function isDockerRequest(request, url) {
|
||||
}
|
||||
|
||||
// Re-export for standard usage
|
||||
export { isAIInferenceRequest, isGitLFSRequest, isGitRequest };
|
||||
export { isAIInferenceRequest, isGitLFSRequest, isGitRequest, isHuggingFaceAPIRequest };
|
||||
|
||||
/**
|
||||
* Validates incoming requests against security rules.
|
||||
@@ -90,15 +91,16 @@ export { isAIInferenceRequest, isGitLFSRequest, isGitRequest };
|
||||
* @returns {{valid: boolean, error?: string, status?: number}} Validation result object
|
||||
*/
|
||||
export function validateRequest(request, url, config = CONFIG) {
|
||||
// Allow POST method for Git, Git LFS, Docker, and AI inference operations
|
||||
// Allow POST method for Git, Git LFS, Docker, AI inference, and HF API operations
|
||||
const isGit = isGitRequest(request, url);
|
||||
const isGitLFS = isGitLFSRequest(request, url);
|
||||
const isDocker = isDockerRequest(request, url);
|
||||
const isAI = isAIInferenceRequest(request, url);
|
||||
const isHF = isHuggingFaceAPIRequest(request, url);
|
||||
|
||||
const allowedMethods =
|
||||
isGit || isGitLFS || isDocker || isAI
|
||||
? ['GET', 'HEAD', 'POST', 'PUT', 'PATCH']
|
||||
isGit || isGitLFS || isDocker || isAI || isHF
|
||||
? ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE']
|
||||
: config.SECURITY.ALLOWED_METHODS;
|
||||
|
||||
if (!allowedMethods.includes(request.method)) {
|
||||
|
||||
Reference in new issue
Block a user