images.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. package server
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/sha256"
  6. "encoding/hex"
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "log"
  12. "log/slog"
  13. "net"
  14. "net/http"
  15. "net/url"
  16. "os"
  17. "path/filepath"
  18. "runtime"
  19. "slices"
  20. "strconv"
  21. "strings"
  22. "github.com/ollama/ollama/api"
  23. "github.com/ollama/ollama/envconfig"
  24. "github.com/ollama/ollama/fs/ggml"
  25. "github.com/ollama/ollama/parser"
  26. "github.com/ollama/ollama/template"
  27. "github.com/ollama/ollama/types/model"
  28. "github.com/ollama/ollama/version"
  29. )
  30. var (
  31. errCapabilities = errors.New("does not support")
  32. errCapabilityCompletion = errors.New("completion")
  33. errCapabilityTools = errors.New("tools")
  34. errCapabilityInsert = errors.New("insert")
  35. )
  36. type Capability string
  37. const (
  38. CapabilityCompletion = Capability("completion")
  39. CapabilityTools = Capability("tools")
  40. CapabilityInsert = Capability("insert")
  41. )
  42. type registryOptions struct {
  43. Insecure bool
  44. Username string
  45. Password string
  46. Token string
  47. CheckRedirect func(req *http.Request, via []*http.Request) error
  48. }
  49. type Model struct {
  50. Name string `json:"name"`
  51. Config ConfigV2
  52. ShortName string
  53. ModelPath string
  54. ParentModel string
  55. AdapterPaths []string
  56. ProjectorPaths []string
  57. System string
  58. License []string
  59. Digest string
  60. Options map[string]interface{}
  61. Messages []api.Message
  62. Template *template.Template
  63. }
  64. // CheckCapabilities checks if the model has the specified capabilities returning an error describing
  65. // any missing or unknown capabilities
  66. func (m *Model) CheckCapabilities(caps ...Capability) error {
  67. var errs []error
  68. for _, cap := range caps {
  69. switch cap {
  70. case CapabilityCompletion:
  71. r, err := os.Open(m.ModelPath)
  72. if err != nil {
  73. slog.Error("couldn't open model file", "error", err)
  74. continue
  75. }
  76. defer r.Close()
  77. // TODO(mxyng): decode the GGML into model to avoid doing this multiple times
  78. f, _, err := ggml.Decode(r, 0)
  79. if err != nil {
  80. slog.Error("couldn't decode ggml", "error", err)
  81. continue
  82. }
  83. if _, ok := f.KV()[fmt.Sprintf("%s.pooling_type", f.KV().Architecture())]; ok {
  84. errs = append(errs, errCapabilityCompletion)
  85. }
  86. case CapabilityTools:
  87. if !slices.Contains(m.Template.Vars(), "tools") {
  88. errs = append(errs, errCapabilityTools)
  89. }
  90. case CapabilityInsert:
  91. vars := m.Template.Vars()
  92. if !slices.Contains(vars, "suffix") {
  93. errs = append(errs, errCapabilityInsert)
  94. }
  95. default:
  96. slog.Error("unknown capability", "capability", cap)
  97. return fmt.Errorf("unknown capability: %s", cap)
  98. }
  99. }
  100. if err := errors.Join(errs...); err != nil {
  101. return fmt.Errorf("%w %w", errCapabilities, errors.Join(errs...))
  102. }
  103. return nil
  104. }
  105. func (m *Model) String() string {
  106. var modelfile parser.Modelfile
  107. modelfile.Commands = append(modelfile.Commands, parser.Command{
  108. Name: "model",
  109. Args: m.ModelPath,
  110. })
  111. for _, adapter := range m.AdapterPaths {
  112. modelfile.Commands = append(modelfile.Commands, parser.Command{
  113. Name: "adapter",
  114. Args: adapter,
  115. })
  116. }
  117. for _, projector := range m.ProjectorPaths {
  118. modelfile.Commands = append(modelfile.Commands, parser.Command{
  119. Name: "model",
  120. Args: projector,
  121. })
  122. }
  123. if m.Template != nil {
  124. modelfile.Commands = append(modelfile.Commands, parser.Command{
  125. Name: "template",
  126. Args: m.Template.String(),
  127. })
  128. }
  129. if m.System != "" {
  130. modelfile.Commands = append(modelfile.Commands, parser.Command{
  131. Name: "system",
  132. Args: m.System,
  133. })
  134. }
  135. for k, v := range m.Options {
  136. switch v := v.(type) {
  137. case []any:
  138. for _, s := range v {
  139. modelfile.Commands = append(modelfile.Commands, parser.Command{
  140. Name: k,
  141. Args: fmt.Sprintf("%v", s),
  142. })
  143. }
  144. default:
  145. modelfile.Commands = append(modelfile.Commands, parser.Command{
  146. Name: k,
  147. Args: fmt.Sprintf("%v", v),
  148. })
  149. }
  150. }
  151. for _, license := range m.License {
  152. modelfile.Commands = append(modelfile.Commands, parser.Command{
  153. Name: "license",
  154. Args: license,
  155. })
  156. }
  157. for _, msg := range m.Messages {
  158. modelfile.Commands = append(modelfile.Commands, parser.Command{
  159. Name: "message",
  160. Args: fmt.Sprintf("%s: %s", msg.Role, msg.Content),
  161. })
  162. }
  163. return modelfile.String()
  164. }
  165. type ConfigV2 struct {
  166. ModelFormat string `json:"model_format"`
  167. ModelFamily string `json:"model_family"`
  168. ModelFamilies []string `json:"model_families"`
  169. ModelType string `json:"model_type"`
  170. FileType string `json:"file_type"`
  171. // required by spec
  172. Architecture string `json:"architecture"`
  173. OS string `json:"os"`
  174. RootFS RootFS `json:"rootfs"`
  175. }
  176. type RootFS struct {
  177. Type string `json:"type"`
  178. DiffIDs []string `json:"diff_ids"`
  179. }
  180. func GetManifest(mp ModelPath) (*Manifest, string, error) {
  181. fp, err := mp.GetManifestPath()
  182. if err != nil {
  183. return nil, "", err
  184. }
  185. f, err := os.Open(fp)
  186. if err != nil {
  187. return nil, "", err
  188. }
  189. defer f.Close()
  190. sha256sum := sha256.New()
  191. var manifest Manifest
  192. if err := json.NewDecoder(io.TeeReader(f, sha256sum)).Decode(&manifest); err != nil {
  193. return nil, "", err
  194. }
  195. return &manifest, hex.EncodeToString(sha256sum.Sum(nil)), nil
  196. }
  197. func GetModel(name string) (*Model, error) {
  198. mp := ParseModelPath(name)
  199. manifest, digest, err := GetManifest(mp)
  200. if err != nil {
  201. return nil, err
  202. }
  203. model := &Model{
  204. Name: mp.GetFullTagname(),
  205. ShortName: mp.GetShortTagname(),
  206. Digest: digest,
  207. Template: template.DefaultTemplate,
  208. }
  209. if manifest.Config.Digest != "" {
  210. filename, err := GetBlobsPath(manifest.Config.Digest)
  211. if err != nil {
  212. return nil, err
  213. }
  214. configFile, err := os.Open(filename)
  215. if err != nil {
  216. return nil, err
  217. }
  218. defer configFile.Close()
  219. if err := json.NewDecoder(configFile).Decode(&model.Config); err != nil {
  220. return nil, err
  221. }
  222. }
  223. for _, layer := range manifest.Layers {
  224. filename, err := GetBlobsPath(layer.Digest)
  225. if err != nil {
  226. return nil, err
  227. }
  228. switch layer.MediaType {
  229. case "application/vnd.ollama.image.model":
  230. model.ModelPath = filename
  231. model.ParentModel = layer.From
  232. case "application/vnd.ollama.image.embed":
  233. // Deprecated in versions > 0.1.2
  234. // TODO: remove this warning in a future version
  235. slog.Info("WARNING: model contains embeddings, but embeddings in modelfiles have been deprecated and will be ignored.")
  236. case "application/vnd.ollama.image.adapter":
  237. model.AdapterPaths = append(model.AdapterPaths, filename)
  238. case "application/vnd.ollama.image.projector":
  239. model.ProjectorPaths = append(model.ProjectorPaths, filename)
  240. case "application/vnd.ollama.image.prompt",
  241. "application/vnd.ollama.image.template":
  242. bts, err := os.ReadFile(filename)
  243. if err != nil {
  244. return nil, err
  245. }
  246. model.Template, err = template.Parse(string(bts))
  247. if err != nil {
  248. return nil, err
  249. }
  250. case "application/vnd.ollama.image.system":
  251. bts, err := os.ReadFile(filename)
  252. if err != nil {
  253. return nil, err
  254. }
  255. model.System = string(bts)
  256. case "application/vnd.ollama.image.params":
  257. params, err := os.Open(filename)
  258. if err != nil {
  259. return nil, err
  260. }
  261. defer params.Close()
  262. // parse model options parameters into a map so that we can see which fields have been specified explicitly
  263. if err = json.NewDecoder(params).Decode(&model.Options); err != nil {
  264. return nil, err
  265. }
  266. case "application/vnd.ollama.image.messages":
  267. msgs, err := os.Open(filename)
  268. if err != nil {
  269. return nil, err
  270. }
  271. defer msgs.Close()
  272. if err = json.NewDecoder(msgs).Decode(&model.Messages); err != nil {
  273. return nil, err
  274. }
  275. case "application/vnd.ollama.image.license":
  276. bts, err := os.ReadFile(filename)
  277. if err != nil {
  278. return nil, err
  279. }
  280. model.License = append(model.License, string(bts))
  281. }
  282. }
  283. return model, nil
  284. }
  285. func CopyModel(src, dst model.Name) error {
  286. if !dst.IsFullyQualified() {
  287. return model.Unqualified(dst)
  288. }
  289. if !src.IsFullyQualified() {
  290. return model.Unqualified(src)
  291. }
  292. if src.Filepath() == dst.Filepath() {
  293. return nil
  294. }
  295. manifests, err := GetManifestPath()
  296. if err != nil {
  297. return err
  298. }
  299. dstpath := filepath.Join(manifests, dst.Filepath())
  300. if err := os.MkdirAll(filepath.Dir(dstpath), 0o755); err != nil {
  301. return err
  302. }
  303. srcpath := filepath.Join(manifests, src.Filepath())
  304. srcfile, err := os.Open(srcpath)
  305. if err != nil {
  306. return err
  307. }
  308. defer srcfile.Close()
  309. dstfile, err := os.Create(dstpath)
  310. if err != nil {
  311. return err
  312. }
  313. defer dstfile.Close()
  314. _, err = io.Copy(dstfile, srcfile)
  315. return err
  316. }
  317. func deleteUnusedLayers(deleteMap map[string]struct{}) error {
  318. // Ignore corrupt manifests to avoid blocking deletion of layers that are freshly orphaned
  319. manifests, err := Manifests(true)
  320. if err != nil {
  321. return err
  322. }
  323. for _, manifest := range manifests {
  324. for _, layer := range manifest.Layers {
  325. delete(deleteMap, layer.Digest)
  326. }
  327. delete(deleteMap, manifest.Config.Digest)
  328. }
  329. // only delete the files which are still in the deleteMap
  330. for k := range deleteMap {
  331. fp, err := GetBlobsPath(k)
  332. if err != nil {
  333. slog.Info(fmt.Sprintf("couldn't get file path for '%s': %v", k, err))
  334. continue
  335. }
  336. if err := os.Remove(fp); err != nil {
  337. slog.Info(fmt.Sprintf("couldn't remove file '%s': %v", fp, err))
  338. continue
  339. }
  340. }
  341. return nil
  342. }
  343. func PruneLayers() error {
  344. deleteMap := make(map[string]struct{})
  345. p, err := GetBlobsPath("")
  346. if err != nil {
  347. return err
  348. }
  349. blobs, err := os.ReadDir(p)
  350. if err != nil {
  351. slog.Info(fmt.Sprintf("couldn't read dir '%s': %v", p, err))
  352. return err
  353. }
  354. for _, blob := range blobs {
  355. name := blob.Name()
  356. name = strings.ReplaceAll(name, "-", ":")
  357. _, err := GetBlobsPath(name)
  358. if err != nil {
  359. if errors.Is(err, ErrInvalidDigestFormat) {
  360. // remove invalid blobs (e.g. partial downloads)
  361. if err := os.Remove(filepath.Join(p, blob.Name())); err != nil {
  362. slog.Error("couldn't remove blob", "blob", blob.Name(), "error", err)
  363. }
  364. }
  365. continue
  366. }
  367. deleteMap[name] = struct{}{}
  368. }
  369. slog.Info(fmt.Sprintf("total blobs: %d", len(deleteMap)))
  370. if err := deleteUnusedLayers(deleteMap); err != nil {
  371. slog.Error(fmt.Sprintf("couldn't remove unused layers: %v", err))
  372. return nil
  373. }
  374. slog.Info(fmt.Sprintf("total unused blobs removed: %d", len(deleteMap)))
  375. return nil
  376. }
  377. func PruneDirectory(path string) error {
  378. info, err := os.Lstat(path)
  379. if err != nil {
  380. return err
  381. }
  382. if info.IsDir() && info.Mode()&os.ModeSymlink == 0 {
  383. entries, err := os.ReadDir(path)
  384. if err != nil {
  385. return err
  386. }
  387. for _, entry := range entries {
  388. if err := PruneDirectory(filepath.Join(path, entry.Name())); err != nil {
  389. return err
  390. }
  391. }
  392. entries, err = os.ReadDir(path)
  393. if err != nil {
  394. return err
  395. }
  396. if len(entries) > 0 {
  397. return nil
  398. }
  399. return os.Remove(path)
  400. }
  401. return nil
  402. }
  403. func PushModel(ctx context.Context, name string, regOpts *registryOptions, fn func(api.ProgressResponse)) error {
  404. mp := ParseModelPath(name)
  405. fn(api.ProgressResponse{Status: "retrieving manifest"})
  406. if mp.ProtocolScheme == "http" && !regOpts.Insecure {
  407. return errors.New("insecure protocol http")
  408. }
  409. manifest, _, err := GetManifest(mp)
  410. if err != nil {
  411. fn(api.ProgressResponse{Status: "couldn't retrieve manifest"})
  412. return err
  413. }
  414. var layers []Layer
  415. layers = append(layers, manifest.Layers...)
  416. if manifest.Config.Digest != "" {
  417. layers = append(layers, manifest.Config)
  418. }
  419. for _, layer := range layers {
  420. if err := uploadBlob(ctx, mp, layer, regOpts, fn); err != nil {
  421. slog.Info(fmt.Sprintf("error uploading blob: %v", err))
  422. return err
  423. }
  424. }
  425. fn(api.ProgressResponse{Status: "pushing manifest"})
  426. requestURL := mp.BaseURL()
  427. requestURL = requestURL.JoinPath("v2", mp.GetNamespaceRepository(), "manifests", mp.Tag)
  428. manifestJSON, err := json.Marshal(manifest)
  429. if err != nil {
  430. return err
  431. }
  432. headers := make(http.Header)
  433. headers.Set("Content-Type", "application/vnd.docker.distribution.manifest.v2+json")
  434. resp, err := makeRequestWithRetry(ctx, http.MethodPut, requestURL, headers, bytes.NewReader(manifestJSON), regOpts)
  435. if err != nil {
  436. return err
  437. }
  438. defer resp.Body.Close()
  439. fn(api.ProgressResponse{Status: "success"})
  440. return nil
  441. }
  442. func PullModel(ctx context.Context, name string, regOpts *registryOptions, fn func(api.ProgressResponse)) error {
  443. mp := ParseModelPath(name)
  444. // build deleteMap to prune unused layers
  445. deleteMap := make(map[string]struct{})
  446. manifest, _, err := GetManifest(mp)
  447. if errors.Is(err, os.ErrNotExist) {
  448. // noop
  449. } else if err != nil {
  450. slog.Warn("pulling model with bad existing manifest", "name", name, "error", err)
  451. } else {
  452. for _, l := range manifest.Layers {
  453. deleteMap[l.Digest] = struct{}{}
  454. }
  455. if manifest.Config.Digest != "" {
  456. deleteMap[manifest.Config.Digest] = struct{}{}
  457. }
  458. }
  459. if mp.ProtocolScheme == "http" && !regOpts.Insecure {
  460. return errors.New("insecure protocol http")
  461. }
  462. fn(api.ProgressResponse{Status: "pulling manifest"})
  463. manifest, err = pullModelManifest(ctx, mp, regOpts)
  464. if err != nil {
  465. return fmt.Errorf("pull model manifest: %s", err)
  466. }
  467. var layers []Layer
  468. layers = append(layers, manifest.Layers...)
  469. if manifest.Config.Digest != "" {
  470. layers = append(layers, manifest.Config)
  471. }
  472. skipVerify := make(map[string]bool)
  473. for _, layer := range layers {
  474. cacheHit, err := downloadBlob(ctx, downloadOpts{
  475. mp: mp,
  476. digest: layer.Digest,
  477. regOpts: regOpts,
  478. fn: fn,
  479. })
  480. if err != nil {
  481. return err
  482. }
  483. skipVerify[layer.Digest] = cacheHit
  484. delete(deleteMap, layer.Digest)
  485. }
  486. delete(deleteMap, manifest.Config.Digest)
  487. fn(api.ProgressResponse{Status: "verifying sha256 digest"})
  488. for _, layer := range layers {
  489. if skipVerify[layer.Digest] {
  490. continue
  491. }
  492. if err := verifyBlob(layer.Digest); err != nil {
  493. if errors.Is(err, errDigestMismatch) {
  494. // something went wrong, delete the blob
  495. fp, err := GetBlobsPath(layer.Digest)
  496. if err != nil {
  497. return err
  498. }
  499. if err := os.Remove(fp); err != nil {
  500. // log this, but return the original error
  501. slog.Info(fmt.Sprintf("couldn't remove file with digest mismatch '%s': %v", fp, err))
  502. }
  503. }
  504. return err
  505. }
  506. }
  507. fn(api.ProgressResponse{Status: "writing manifest"})
  508. manifestJSON, err := json.Marshal(manifest)
  509. if err != nil {
  510. return err
  511. }
  512. fp, err := mp.GetManifestPath()
  513. if err != nil {
  514. return err
  515. }
  516. if err := os.MkdirAll(filepath.Dir(fp), 0o755); err != nil {
  517. return err
  518. }
  519. err = os.WriteFile(fp, manifestJSON, 0o644)
  520. if err != nil {
  521. slog.Info(fmt.Sprintf("couldn't write to %s", fp))
  522. return err
  523. }
  524. if !envconfig.NoPrune() && len(deleteMap) > 0 {
  525. fn(api.ProgressResponse{Status: "removing unused layers"})
  526. if err := deleteUnusedLayers(deleteMap); err != nil {
  527. fn(api.ProgressResponse{Status: fmt.Sprintf("couldn't remove unused layers: %v", err)})
  528. }
  529. }
  530. fn(api.ProgressResponse{Status: "success"})
  531. return nil
  532. }
  533. func pullModelManifest(ctx context.Context, mp ModelPath, regOpts *registryOptions) (*Manifest, error) {
  534. requestURL := mp.BaseURL().JoinPath("v2", mp.GetNamespaceRepository(), "manifests", mp.Tag)
  535. headers := make(http.Header)
  536. headers.Set("Accept", "application/vnd.docker.distribution.manifest.v2+json")
  537. resp, err := makeRequestWithRetry(ctx, http.MethodGet, requestURL, headers, nil, regOpts)
  538. if err != nil {
  539. return nil, err
  540. }
  541. defer resp.Body.Close()
  542. var m Manifest
  543. if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
  544. return nil, err
  545. }
  546. return &m, err
  547. }
  548. // GetSHA256Digest returns the SHA256 hash of a given buffer and returns it, and the size of buffer
  549. func GetSHA256Digest(r io.Reader) (string, int64) {
  550. h := sha256.New()
  551. n, err := io.Copy(h, r)
  552. if err != nil {
  553. log.Fatal(err)
  554. }
  555. return fmt.Sprintf("sha256:%x", h.Sum(nil)), n
  556. }
  557. var errUnauthorized = errors.New("unauthorized: access denied")
  558. func makeRequestWithRetry(ctx context.Context, method string, requestURL *url.URL, headers http.Header, body io.ReadSeeker, regOpts *registryOptions) (*http.Response, error) {
  559. for range 2 {
  560. resp, err := makeRequest(ctx, method, requestURL, headers, body, regOpts)
  561. if err != nil {
  562. if !errors.Is(err, context.Canceled) {
  563. slog.Info(fmt.Sprintf("request failed: %v", err))
  564. }
  565. return nil, err
  566. }
  567. switch {
  568. case resp.StatusCode == http.StatusUnauthorized:
  569. resp.Body.Close()
  570. // Handle authentication error with one retry
  571. challenge := parseRegistryChallenge(resp.Header.Get("www-authenticate"))
  572. token, err := getAuthorizationToken(ctx, challenge)
  573. if err != nil {
  574. return nil, err
  575. }
  576. regOpts.Token = token
  577. if body != nil {
  578. _, err = body.Seek(0, io.SeekStart)
  579. if err != nil {
  580. return nil, err
  581. }
  582. }
  583. case resp.StatusCode == http.StatusNotFound:
  584. resp.Body.Close()
  585. return nil, os.ErrNotExist
  586. case resp.StatusCode >= http.StatusBadRequest:
  587. defer resp.Body.Close()
  588. responseBody, err := io.ReadAll(resp.Body)
  589. if err != nil {
  590. return nil, fmt.Errorf("%d: %s", resp.StatusCode, err)
  591. }
  592. return nil, fmt.Errorf("%d: %s", resp.StatusCode, responseBody)
  593. default:
  594. return resp, nil
  595. }
  596. }
  597. return nil, errUnauthorized
  598. }
  599. // testMakeRequestDialContext specifies the dial function for the http client in
  600. // makeRequest. It can be used to resolve hosts in model names to local
  601. // addresses for testing. For example, the model name ("example.com/my/model")
  602. // can be directed to push/pull from "127.0.0.1:1234".
  603. //
  604. // This is not safe to set across goroutines. It should be set in
  605. // the main test goroutine, and not by tests marked to run in parallel with
  606. // t.Parallel().
  607. //
  608. // It should be cleared after use, otherwise it will affect other tests.
  609. //
  610. // Ideally we would have some set this up the stack, but the code is not
  611. // structured in a way that makes this easy, so this will have to do for now.
  612. var testMakeRequestDialContext func(ctx context.Context, network, addr string) (net.Conn, error)
  613. func makeRequest(ctx context.Context, method string, requestURL *url.URL, headers http.Header, body io.Reader, regOpts *registryOptions) (*http.Response, error) {
  614. if requestURL.Scheme != "http" && regOpts != nil && regOpts.Insecure {
  615. requestURL.Scheme = "http"
  616. }
  617. req, err := http.NewRequestWithContext(ctx, method, requestURL.String(), body)
  618. if err != nil {
  619. return nil, err
  620. }
  621. if headers != nil {
  622. req.Header = headers
  623. }
  624. if regOpts != nil {
  625. if regOpts.Token != "" {
  626. req.Header.Set("Authorization", "Bearer "+regOpts.Token)
  627. } else if regOpts.Username != "" && regOpts.Password != "" {
  628. req.SetBasicAuth(regOpts.Username, regOpts.Password)
  629. }
  630. }
  631. req.Header.Set("User-Agent", fmt.Sprintf("ollama/%s (%s %s) Go/%s", version.Version, runtime.GOARCH, runtime.GOOS, runtime.Version()))
  632. if s := req.Header.Get("Content-Length"); s != "" {
  633. contentLength, err := strconv.ParseInt(s, 10, 64)
  634. if err != nil {
  635. return nil, err
  636. }
  637. req.ContentLength = contentLength
  638. }
  639. c := &http.Client{
  640. CheckRedirect: regOpts.CheckRedirect,
  641. }
  642. if testMakeRequestDialContext != nil {
  643. tr := http.DefaultTransport.(*http.Transport).Clone()
  644. tr.DialContext = testMakeRequestDialContext
  645. c.Transport = tr
  646. }
  647. return c.Do(req)
  648. }
  649. func getValue(header, key string) string {
  650. startIdx := strings.Index(header, key+"=")
  651. if startIdx == -1 {
  652. return ""
  653. }
  654. // Move the index to the starting quote after the key.
  655. startIdx += len(key) + 2
  656. endIdx := startIdx
  657. for endIdx < len(header) {
  658. if header[endIdx] == '"' {
  659. if endIdx+1 < len(header) && header[endIdx+1] != ',' { // If the next character isn't a comma, continue
  660. endIdx++
  661. continue
  662. }
  663. break
  664. }
  665. endIdx++
  666. }
  667. return header[startIdx:endIdx]
  668. }
  669. func parseRegistryChallenge(authStr string) registryChallenge {
  670. authStr = strings.TrimPrefix(authStr, "Bearer ")
  671. return registryChallenge{
  672. Realm: getValue(authStr, "realm"),
  673. Service: getValue(authStr, "service"),
  674. Scope: getValue(authStr, "scope"),
  675. }
  676. }
  677. var errDigestMismatch = errors.New("digest mismatch, file must be downloaded again")
  678. func verifyBlob(digest string) error {
  679. fp, err := GetBlobsPath(digest)
  680. if err != nil {
  681. return err
  682. }
  683. f, err := os.Open(fp)
  684. if err != nil {
  685. return err
  686. }
  687. defer f.Close()
  688. fileDigest, _ := GetSHA256Digest(f)
  689. if digest != fileDigest {
  690. return fmt.Errorf("%w: want %s, got %s", errDigestMismatch, digest, fileDigest)
  691. }
  692. return nil
  693. }