@@ -73,76 +73,6 @@ public extension HubApi {
73
73
struct SiblingsResponse : Codable {
74
74
let siblings : [ Sibling ]
75
75
}
76
-
77
- /// Throws error if the response code is not 20X
78
- func httpGet( for url: URL ) async throws -> ( Data , HTTPURLResponse ) {
79
- var request = URLRequest ( url: url)
80
- if let hfToken = hfToken {
81
- request. setValue ( " Bearer \( hfToken) " , forHTTPHeaderField: " Authorization " )
82
- }
83
- let ( data, response) = try await URLSession . shared. data ( for: request)
84
- guard let response = response as? HTTPURLResponse else { throw Hub . HubClientError. unexpectedError }
85
-
86
- switch response. statusCode {
87
- case 200 ..< 300 : break
88
- case 400 ..< 500 : throw Hub . HubClientError. authorizationRequired
89
- default : throw Hub . HubClientError. httpStatusCode ( response. statusCode)
90
- }
91
-
92
- return ( data, response)
93
- }
94
-
95
- /// Throws error if page does not exist or is not accessible.
96
- /// Allows relative redirects but ignores absolute ones for LFS files.
97
- func httpHead( for url: URL ) async throws -> ( Data , HTTPURLResponse ) {
98
- var request = URLRequest ( url: url)
99
- request. httpMethod = " HEAD "
100
- if let hfToken = hfToken {
101
- request. setValue ( " Bearer \( hfToken) " , forHTTPHeaderField: " Authorization " )
102
- }
103
- request. setValue ( " identity " , forHTTPHeaderField: " Accept-Encoding " )
104
-
105
- let redirectDelegate = RedirectDelegate ( )
106
- let session = URLSession ( configuration: . default, delegate: redirectDelegate, delegateQueue: nil )
107
-
108
- let ( data, response) = try await session. data ( for: request)
109
- guard let response = response as? HTTPURLResponse else { throw Hub . HubClientError. unexpectedError }
110
-
111
- switch response. statusCode {
112
- case 200 ..< 400 : break // Allow redirects to pass through to the redirect delegate
113
- case 400 ..< 500 : throw Hub . HubClientError. authorizationRequired
114
- default : throw Hub . HubClientError. httpStatusCode ( response. statusCode)
115
- }
116
-
117
- return ( data, response)
118
- }
119
-
120
- func getFilenames( from repo: Repo , matching globs: [ String ] = [ ] ) async throws -> [ String ] {
121
- // Read repo info and only parse "siblings"
122
- let url = URL ( string: " \( endpoint) /api/ \( repo. type) / \( repo. id) " ) !
123
- let ( data, _) = try await httpGet ( for: url)
124
- let response = try JSONDecoder ( ) . decode ( SiblingsResponse . self, from: data)
125
- let filenames = response. siblings. map { $0. rfilename }
126
- guard globs. count > 0 else { return filenames }
127
-
128
- var selected : Set < String > = [ ]
129
- for glob in globs {
130
- selected = selected. union ( filenames. matching ( glob: glob) )
131
- }
132
- return Array ( selected)
133
- }
134
-
135
- func getFilenames( from repoId: String , matching globs: [ String ] = [ ] ) async throws -> [ String ] {
136
- return try await getFilenames ( from: Repo ( id: repoId) , matching: globs)
137
- }
138
-
139
- func getFilenames( from repo: Repo , matching glob: String ) async throws -> [ String ] {
140
- return try await getFilenames ( from: repo, matching: [ glob] )
141
- }
142
-
143
- func getFilenames( from repoId: String , matching glob: String ) async throws -> [ String ] {
144
- return try await getFilenames ( from: Repo ( id: repoId) , matching: [ glob] )
145
- }
146
76
}
147
77
148
78
/// Additional Errors
@@ -178,20 +108,6 @@ public extension HubApi {
178
108
}
179
109
}
180
110
181
- /// Whoami
182
- public extension HubApi {
183
- func whoami( ) async throws -> Config {
184
- guard hfToken != nil else { throw Hub . HubClientError. authorizationRequired }
185
-
186
- let url = URL ( string: " \( endpoint) /api/whoami-v2 " ) !
187
- let ( data, _) = try await httpGet ( for: url)
188
-
189
- let parsed = try JSONSerialization . jsonObject ( with: data, options: [ ] )
190
- guard let dictionary = parsed as? [ NSString : Any ] else { throw Hub . HubClientError. parse }
191
- return Config ( dictionary)
192
- }
193
- }
194
-
195
111
/// Snaphsot download
196
112
public extension HubApi {
197
113
func localRepoLocation( _ repo: Repo ) -> URL {
@@ -236,130 +152,10 @@ public extension HubApi {
236
152
guard let etag = etag else { return nil }
237
153
return etag. trimmingPrefix ( " W/ " ) . trimmingCharacters ( in: CharacterSet ( charactersIn: " \" " ) )
238
154
}
239
-
240
- func getFileMetadata( url: URL ) async throws -> FileMetadata {
241
- let ( _, response) = try await httpHead ( for: url)
242
- let location = response. statusCode == 302 ? response. value ( forHTTPHeaderField: " Location " ) : response. url? . absoluteString
243
-
244
- return FileMetadata (
245
- commitHash: response. value ( forHTTPHeaderField: " X-Repo-Commit " ) ,
246
- etag: normalizeEtag (
247
- ( response. value ( forHTTPHeaderField: " X-Linked-Etag " ) ) ?? ( response. value ( forHTTPHeaderField: " Etag " ) )
248
- ) ,
249
- location: location ?? url. absoluteString,
250
- size: Int ( response. value ( forHTTPHeaderField: " X-Linked-Size " ) ?? response. value ( forHTTPHeaderField: " Content-Length " ) ?? " " )
251
- )
252
- }
253
-
254
- func getFileMetadata( from repo: Repo , matching globs: [ String ] = [ ] ) async throws -> [ FileMetadata ] {
255
- let files = try await getFilenames ( from: repo, matching: globs)
256
- let url = URL ( string: " \( endpoint) / \( repo. id) /resolve/main " ) ! // TODO: revisions
257
- var selectedMetadata : Array < FileMetadata > = [ ]
258
- for file in files {
259
- let fileURL = url. appending ( path: file)
260
- selectedMetadata. append ( try await getFileMetadata ( url: fileURL) )
261
- }
262
- return selectedMetadata
263
- }
264
-
265
- func getFileMetadata( from repoId: String , matching globs: [ String ] = [ ] ) async throws -> [ FileMetadata ] {
266
- return try await getFileMetadata ( from: Repo ( id: repoId) , matching: globs)
267
- }
268
-
269
- func getFileMetadata( from repo: Repo , matching glob: String ) async throws -> [ FileMetadata ] {
270
- return try await getFileMetadata ( from: repo, matching: [ glob] )
271
- }
272
-
273
- func getFileMetadata( from repoId: String , matching glob: String ) async throws -> [ FileMetadata ] {
274
- return try await getFileMetadata ( from: Repo ( id: repoId) , matching: [ glob] )
275
- }
276
- }
277
-
278
- /// Stateless wrappers that use `HubApi` instances
279
- public extension Hub {
280
- static func getFilenames( from repo: Hub . Repo , matching globs: [ String ] = [ ] ) async throws -> [ String ] {
281
- return try await HubApi . shared. getFilenames ( from: repo, matching: globs)
282
- }
283
-
284
- static func getFilenames( from repoId: String , matching globs: [ String ] = [ ] ) async throws -> [ String ] {
285
- return try await HubApi . shared. getFilenames ( from: Repo ( id: repoId) , matching: globs)
286
- }
287
-
288
- static func getFilenames( from repo: Repo , matching glob: String ) async throws -> [ String ] {
289
- return try await HubApi . shared. getFilenames ( from: repo, matching: glob)
290
- }
291
-
292
- static func getFilenames( from repoId: String , matching glob: String ) async throws -> [ String ] {
293
- return try await HubApi . shared. getFilenames ( from: Repo ( id: repoId) , matching: glob)
294
- }
295
-
296
- static func whoami( token: String ) async throws -> Config {
297
- return try await HubApi ( hfToken: token) . whoami ( )
298
- }
299
-
300
- static func getFileMetadata( fileURL: URL ) async throws -> HubApi . FileMetadata {
301
- return try await HubApi . shared. getFileMetadata ( url: fileURL)
302
- }
303
-
304
- static func getFileMetadata( from repo: Repo , matching globs: [ String ] = [ ] ) async throws -> [ HubApi . FileMetadata ] {
305
- return try await HubApi . shared. getFileMetadata ( from: repo, matching: globs)
306
- }
307
-
308
- static func getFileMetadata( from repoId: String , matching globs: [ String ] = [ ] ) async throws -> [ HubApi . FileMetadata ] {
309
- return try await HubApi . shared. getFileMetadata ( from: Repo ( id: repoId) , matching: globs)
310
- }
311
-
312
- static func getFileMetadata( from repo: Repo , matching glob: String ) async throws -> [ HubApi . FileMetadata ] {
313
- return try await HubApi . shared. getFileMetadata ( from: repo, matching: [ glob] )
314
- }
315
-
316
- static func getFileMetadata( from repoId: String , matching glob: String ) async throws -> [ HubApi . FileMetadata ] {
317
- return try await HubApi . shared. getFileMetadata ( from: Repo ( id: repoId) , matching: [ glob] )
318
- }
319
155
}
320
156
321
157
public extension [ String ] {
322
158
func matching( glob: String ) -> [ String ] {
323
159
filter { fnmatch ( glob, $0, 0 ) == 0 }
324
160
}
325
161
}
326
-
327
- /// Only allow relative redirects and reject others
328
- /// Reference: https://github.com/huggingface/huggingface_hub/blob/b2c9a148d465b43ab90fab6e4ebcbbf5a9df27d4/src/huggingface_hub/file_download.py#L258
329
- private class RedirectDelegate : NSObject , URLSessionTaskDelegate {
330
- func urlSession( _ session: URLSession , task: URLSessionTask , willPerformHTTPRedirection response: HTTPURLResponse , newRequest request: URLRequest , completionHandler: @escaping ( URLRequest ? ) -> Void ) {
331
- // Check if it's a redirect status code (300-399)
332
- if ( 300 ... 399 ) . contains ( response. statusCode) {
333
- // Get the Location header
334
- if let locationString = response. value ( forHTTPHeaderField: " Location " ) ,
335
- let locationUrl = URL ( string: locationString) {
336
-
337
- // Check if it's a relative redirect (no host component)
338
- if locationUrl. host == nil {
339
- // For relative redirects, construct the new URL using the original request's base
340
- if let originalUrl = task. originalRequest? . url,
341
- var components = URLComponents ( url: originalUrl, resolvingAgainstBaseURL: true ) {
342
- // Update the path component with the relative path
343
- components. path = locationUrl. path
344
- components. query = locationUrl. query
345
-
346
- // Create new request with the resolved URL
347
- if let resolvedUrl = components. url {
348
- var newRequest = URLRequest ( url: resolvedUrl)
349
- // Copy headers from original request
350
- task. originalRequest? . allHTTPHeaderFields? . forEach { key, value in
351
- newRequest. setValue ( value, forHTTPHeaderField: key)
352
- }
353
- newRequest. setValue ( resolvedUrl. absoluteString, forHTTPHeaderField: " Location " )
354
- completionHandler ( newRequest)
355
- return
356
- }
357
- }
358
- }
359
- }
360
- }
361
-
362
- // For all other cases (non-redirects or absolute redirects), prevent redirect
363
- completionHandler ( nil )
364
- }
365
- }
0 commit comments