changelog shortlog graph tags branches changeset files file revisions raw help

Mercurial > core / annotate rust/lib/dl/src/lib.rs

changeset 698: 96958d3eb5b0
parent: 966f92770ddf
author: Richard Westhaver <ellis@rwest.io>
date: Fri, 04 Oct 2024 22:04:59 -0400
permissions: -rw-r--r--
description: fixes
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
1
 //! Easy file downloading
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
2
 #![deny(rust_2018_idioms)]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
3
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
4
 use anyhow::{Context, Result};
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
5
 use std::path::Path;
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
6
 use url::Url;
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
7
 mod errors;
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
8
 pub use crate::errors::*;
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
9
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
10
 /// User agent header value for HTTP request.
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
11
 const USER_AGENT: &str = concat!("cc-install/", env!("CARGO_PKG_VERSION"));
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
12
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
13
 #[derive(Debug, Copy, Clone)]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
14
 pub enum Backend {
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
15
   Curl,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
16
   Reqwest(TlsBackend),
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
17
 }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
18
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
19
 #[derive(Debug, Copy, Clone)]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
20
 pub enum TlsBackend {
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
21
   Rustls,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
22
   Default,
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
23
 }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
24
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
25
 #[derive(Debug, Copy, Clone)]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
26
 pub enum Event<'a> {
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
27
   ResumingPartialDownload,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
28
   /// Received the Content-Length of the to-be downloaded data.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
29
   DownloadContentLengthReceived(u64),
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
30
   /// Received some data.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
31
   DownloadDataReceived(&'a [u8]),
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
32
 }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
33
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
34
 fn download_with_backend(
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
35
   backend: Backend,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
36
   url: &Url,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
37
   resume_from: u64,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
38
   callback: &dyn Fn(Event<'_>) -> Result<()>,
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
39
 ) -> Result<()> {
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
40
   match backend {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
41
     Backend::Curl => curl::download(url, resume_from, callback),
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
42
     Backend::Reqwest(tls) => {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
43
       reqwest_be::download(url, resume_from, callback, tls)
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
44
     }
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
45
   }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
46
 }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
47
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
48
 type DownloadCallback<'a> = &'a dyn Fn(Event<'_>) -> Result<()>;
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
49
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
50
 pub fn download_to_path_with_backend(
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
51
   backend: Backend,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
52
   url: &Url,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
53
   path: &Path,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
54
   resume_from_partial: bool,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
55
   callback: Option<DownloadCallback<'_>>,
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
56
 ) -> Result<()> {
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
57
   use std::{
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
58
     cell::RefCell,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
59
     fs::{remove_file, OpenOptions},
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
60
     io::{Read, Seek, SeekFrom, Write},
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
61
   };
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
62
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
63
   || -> Result<()> {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
64
     let (file, resume_from) = if resume_from_partial {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
65
       let possible_partial = OpenOptions::new().read(true).open(path);
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
66
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
67
       let downloaded_so_far = if let Ok(mut partial) = possible_partial {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
68
         if let Some(cb) = callback {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
69
           cb(Event::ResumingPartialDownload)?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
70
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
71
           let mut buf = vec![0; 32768];
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
72
           let mut downloaded_so_far = 0;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
73
           loop {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
74
             let n = partial.read(&mut buf)?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
75
             downloaded_so_far += n as u64;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
76
             if n == 0 {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
77
               break;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
78
             }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
79
             cb(Event::DownloadDataReceived(&buf[..n]))?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
80
           }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
81
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
82
           downloaded_so_far
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
83
         } else {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
84
           let file_info = partial.metadata()?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
85
           file_info.len()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
86
         }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
87
       } else {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
88
         0
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
89
       };
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
90
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
91
       let mut possible_partial = OpenOptions::new()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
92
         .write(true)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
93
         .create(true)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
94
         .open(path)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
95
         .context("error opening file for download")?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
96
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
97
       possible_partial.seek(SeekFrom::End(0))?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
98
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
99
       (possible_partial, downloaded_so_far)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
100
     } else {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
101
       (
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
102
         OpenOptions::new()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
103
           .write(true)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
104
           .create(true)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
105
           .open(path)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
106
           .context("error creating file for download")?,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
107
         0,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
108
       )
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
109
     };
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
110
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
111
     let file = RefCell::new(file);
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
112
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
113
     download_with_backend(backend, url, resume_from, &|event| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
114
       if let Event::DownloadDataReceived(data) = event {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
115
         file
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
116
           .borrow_mut()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
117
           .write_all(data)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
118
           .context("unable to write download to disk")?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
119
       }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
120
       match callback {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
121
         Some(cb) => cb(event),
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
122
         None => Ok(()),
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
123
       }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
124
     })?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
125
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
126
     file
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
127
       .borrow_mut()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
128
       .sync_data()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
129
       .context("unable to sync download to disk")?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
130
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
131
     Ok(())
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
132
   }()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
133
   .map_err(|e| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
134
     // TODO: We currently clear up the cached download on any error, should we
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
135
     // restrict it to a subset?
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
136
     if let Err(file_err) =
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
137
       remove_file(path).context("cleaning up cached downloads")
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
138
     {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
139
       file_err.context(e)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
140
     } else {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
141
       e
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
142
     }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
143
   })
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
144
 }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
145
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
146
 #[cfg(all(not(feature = "reqwest-backend"), not(feature = "curl-backend")))]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
147
 compile_error!("Must enable at least one backend");
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
148
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
149
 /// Download via libcurl; encrypt with the native (or OpenSSl) TLS
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
150
 /// stack via libcurl
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
151
 #[cfg(feature = "curl-backend")]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
152
 pub mod curl {
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
153
   use std::{cell::RefCell, str, time::Duration};
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
154
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
155
   use anyhow::{Context, Result};
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
156
   use curl::easy::Easy;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
157
   use url::Url;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
158
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
159
   use super::Event;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
160
   use crate::errors::*;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
161
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
162
   pub fn download(
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
163
     url: &Url,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
164
     resume_from: u64,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
165
     callback: &dyn Fn(Event<'_>) -> Result<()>,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
166
   ) -> Result<()> {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
167
     // Fetch either a cached libcurl handle (which will preserve open
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
168
     // connections) or create a new one if it isn't listed.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
169
     //
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
170
     // Once we've acquired it, reset the lifetime from 'static to our local
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
171
     // scope.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
172
     thread_local!(static EASY: RefCell<Easy> = RefCell::new(Easy::new()));
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
173
     EASY.with(|handle| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
174
       let mut handle = handle.borrow_mut();
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
175
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
176
       handle.url(url.as_ref())?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
177
       handle.follow_location(true)?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
178
       handle.useragent(super::USER_AGENT)?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
179
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
180
       if resume_from > 0 {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
181
         handle.resume_from(resume_from)?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
182
       } else {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
183
         // an error here indicates that the range header isn't supported by
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
184
         // underlying curl, so there's nothing to "clear" - safe to
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
185
         // ignore this error.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
186
         let _ = handle.resume_from(0);
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
187
       }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
188
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
189
       // Take at most 30s to connect
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
190
       handle.connect_timeout(Duration::new(30, 0))?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
191
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
192
       {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
193
         let cberr = RefCell::new(None);
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
194
         let mut transfer = handle.transfer();
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
195
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
196
         // Data callback for libcurl which is called with data that's
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
197
         // downloaded. We just feed it into our hasher and also write it out
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
198
         // to disk.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
199
         transfer.write_function(|data| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
200
           match callback(Event::DownloadDataReceived(data)) {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
201
             Ok(()) => Ok(data.len()),
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
202
             Err(e) => {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
203
               *cberr.borrow_mut() = Some(e);
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
204
               Ok(0)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
205
             }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
206
           }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
207
         })?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
208
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
209
         // Listen for headers and parse out a `Content-Length`
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
210
         // (case-insensitive) if it comes so we know how much we're
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
211
         // downloading.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
212
         transfer.header_function(|header| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
213
           if let Ok(data) = str::from_utf8(header) {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
214
             let prefix = "content-length: ";
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
215
             if data.to_ascii_lowercase().starts_with(prefix) {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
216
               if let Ok(s) = data[prefix.len()..].trim().parse::<u64>() {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
217
                 let msg = Event::DownloadContentLengthReceived(s + resume_from);
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
218
                 match callback(msg) {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
219
                   Ok(()) => (),
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
220
                   Err(e) => {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
221
                     *cberr.borrow_mut() = Some(e);
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
222
                     return false;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
223
                   }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
224
                 }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
225
               }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
226
             }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
227
           }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
228
           true
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
229
         })?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
230
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
231
         // If an error happens check to see if we had a filesystem error up
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
232
         // in `cberr`, but we always want to punt it up.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
233
         transfer.perform().or_else(|e| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
234
           // If the original error was generated by one of our
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
235
           // callbacks, return it.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
236
           match cberr.borrow_mut().take() {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
237
             Some(cberr) => Err(cberr),
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
238
             None => {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
239
               // Otherwise, return the error from curl
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
240
               if e.is_file_couldnt_read_file() {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
241
                 Err(e).context(DownloadError::FileNotFound)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
242
               } else {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
243
                 Err(e).context("error during download")?
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
244
               }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
245
             }
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
246
           }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
247
         })?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
248
       }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
249
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
250
       // If we didn't get a 20x or 0 ("OK" for files) then return an error
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
251
       let code = handle.response_code()?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
252
       match code {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
253
         0 | 200..=299 => {}
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
254
         _ => {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
255
           return Err(DownloadError::HttpStatus(code).into());
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
256
         }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
257
       };
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
258
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
259
       Ok(())
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
260
     })
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
261
   }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
262
 }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
263
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
264
 #[cfg(feature = "reqwest-backend")]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
265
 pub mod reqwest_be {
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
266
   #[cfg(all(
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
267
     not(feature = "reqwest-rustls-tls"),
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
268
     not(feature = "reqwest-default-tls")
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
269
   ))]
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
270
   compile_error!("Must select a reqwest TLS backend");
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
271
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
272
   use std::{io, time::Duration};
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
273
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
274
   use anyhow::{anyhow, Context, Result};
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
275
   #[cfg(any(
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
276
     feature = "reqwest-rustls-tls",
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
277
     feature = "reqwest-default-tls"
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
278
   ))]
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
279
   use once_cell::sync::Lazy;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
280
   use reqwest::{
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
281
     blocking::{Client, ClientBuilder, Response},
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
282
     header, Proxy,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
283
   };
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
284
   use url::Url;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
285
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
286
   use super::{Event, TlsBackend};
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
287
   use crate::errors::*;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
288
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
289
   pub fn download(
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
290
     url: &Url,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
291
     resume_from: u64,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
292
     callback: &dyn Fn(Event<'_>) -> Result<()>,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
293
     tls: TlsBackend,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
294
   ) -> Result<()> {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
295
     // Short-circuit reqwest for the "file:" URL scheme
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
296
     if download_from_file_url(url, resume_from, callback)? {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
297
       return Ok(());
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
298
     }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
299
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
300
     let mut res = request(url, resume_from, tls)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
301
       .context("failed to make network request")?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
302
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
303
     if !res.status().is_success() {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
304
       let code: u16 = res.status().into();
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
305
       return Err(anyhow!(DownloadError::HttpStatus(u32::from(code))));
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
306
     }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
307
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
308
     let buffer_size = 0x10000;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
309
     let mut buffer = vec![0u8; buffer_size];
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
310
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
311
     if let Some(len) = res.headers().get(header::CONTENT_LENGTH) {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
312
       // TODO possible issues during unwrap?
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
313
       let len = len.to_str().unwrap().parse::<u64>().unwrap() + resume_from;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
314
       callback(Event::DownloadContentLengthReceived(len))?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
315
     }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
316
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
317
     loop {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
318
       let bytes_read = io::Read::read(&mut res, &mut buffer)?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
319
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
320
       if bytes_read != 0 {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
321
         callback(Event::DownloadDataReceived(&buffer[0..bytes_read]))?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
322
       } else {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
323
         return Ok(());
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
324
       }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
325
     }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
326
   }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
327
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
328
   fn client_generic() -> ClientBuilder {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
329
     Client::builder()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
330
       .gzip(false)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
331
       .user_agent(super::USER_AGENT)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
332
       .proxy(Proxy::custom(env_proxy))
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
333
       .timeout(Duration::from_secs(30))
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
334
   }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
335
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
336
   #[cfg(feature = "reqwest-rustls-tls")]
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
337
   static CLIENT_RUSTLS_TLS: Lazy<Client> = Lazy::new(|| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
338
     let catcher = || client_generic().use_rustls_tls().build();
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
339
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
340
     // woah, an unwrap?!
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
341
     // It's OK. This is the same as what is happening in curl.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
342
     //
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
343
     // The curl::Easy::new() internally assert!s that the initialized
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
344
     // Easy is not null. Inside reqwest, the errors here would be from
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
345
     // the TLS library returning a null pointer as well.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
346
     catcher().unwrap()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
347
   });
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
348
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
349
   #[cfg(feature = "reqwest-default-tls")]
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
350
   static CLIENT_DEFAULT_TLS: Lazy<Client> = Lazy::new(|| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
351
     let catcher = || client_generic().build();
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
352
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
353
     // woah, an unwrap?!
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
354
     // It's OK. This is the same as what is happening in curl.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
355
     //
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
356
     // The curl::Easy::new() internally assert!s that the initialized
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
357
     // Easy is not null. Inside reqwest, the errors here would be from
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
358
     // the TLS library returning a null pointer as well.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
359
     catcher().unwrap()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
360
   });
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
361
 
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
362
   fn env_proxy(url: &Url) -> Option<Url> {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
363
     env_proxy::for_url(url).to_url()
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
364
   }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
365
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
366
   fn request(
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
367
     url: &Url,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
368
     resume_from: u64,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
369
     backend: TlsBackend,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
370
   ) -> Result<Response, DownloadError> {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
371
     let client: &Client = match backend {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
372
       #[cfg(feature = "reqwest-rustls-tls")]
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
373
       TlsBackend::Rustls => &CLIENT_RUSTLS_TLS,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
374
       #[cfg(not(feature = "reqwest-rustls-tls"))]
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
375
       TlsBackend::Rustls => {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
376
         return Err(DownloadError::BackendUnavailable("reqwest rustls"));
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
377
       }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
378
       #[cfg(feature = "reqwest-default-tls")]
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
379
       TlsBackend::Default => &CLIENT_DEFAULT_TLS,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
380
       #[cfg(not(feature = "reqwest-default-tls"))]
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
381
       TlsBackend::Default => {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
382
         return Err(DownloadError::BackendUnavailable("reqwest default TLS"));
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
383
       }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
384
     };
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
385
     let mut req = client.get(url.as_str());
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
386
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
387
     if resume_from != 0 {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
388
       req = req.header(header::RANGE, format!("bytes={resume_from}-"));
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
389
     }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
390
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
391
     Ok(req.send()?)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
392
   }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
393
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
394
   fn download_from_file_url(
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
395
     url: &Url,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
396
     resume_from: u64,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
397
     callback: &dyn Fn(Event<'_>) -> Result<()>,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
398
   ) -> Result<bool> {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
399
     use std::fs;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
400
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
401
     // The file scheme is mostly for use by tests to mock the dist server
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
402
     if url.scheme() == "file" {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
403
       let src = url.to_file_path().map_err(|_| {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
404
         DownloadError::Message(format!("bogus file url: '{url}'"))
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
405
       })?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
406
       if !src.is_file() {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
407
         // Because some of rustup's logic depends on checking
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
408
         // the error when a downloaded file doesn't exist, make
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
409
         // the file case return the same error value as the
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
410
         // network case.
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
411
         return Err(anyhow!(DownloadError::FileNotFound));
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
412
       }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
413
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
414
       let mut f =
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
415
         fs::File::open(src).context("unable to open downloaded file")?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
416
       io::Seek::seek(&mut f, io::SeekFrom::Start(resume_from))?;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
417
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
418
       let mut buffer = vec![0u8; 0x10000];
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
419
       loop {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
420
         let bytes_read = io::Read::read(&mut f, &mut buffer)?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
421
         if bytes_read == 0 {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
422
           break;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
423
         }
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
424
         callback(Event::DownloadDataReceived(&buffer[0..bytes_read]))?;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
425
       }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
426
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
427
       Ok(true)
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
428
     } else {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
429
       Ok(false)
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
430
     }
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
431
   }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
432
 }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
433
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
434
 #[cfg(not(feature = "curl-backend"))]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
435
 pub mod curl {
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
436
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
437
   use anyhow::{anyhow, Result};
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
438
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
439
   use super::Event;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
440
   use crate::errors::*;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
441
   use url::Url;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
442
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
443
   pub fn download(
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
444
     _url: &Url,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
445
     _resume_from: u64,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
446
     _callback: &dyn Fn(Event<'_>) -> Result<()>,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
447
   ) -> Result<()> {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
448
     Err(anyhow!(DownloadError::BackendUnavailable("curl")))
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
449
   }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
450
 }
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
451
 
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
452
 #[cfg(not(feature = "reqwest-backend"))]
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
453
 pub mod reqwest_be {
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
454
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
455
   use anyhow::{anyhow, Result};
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
456
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
457
   use super::{Event, TlsBackend};
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
458
   use crate::errors::*;
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
459
   use url::Url;
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
460
 
78
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
461
   pub fn download(
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
462
     _url: &Url,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
463
     _resume_from: u64,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
464
     _callback: &dyn Fn(Event<'_>) -> Result<()>,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
465
     _tls: TlsBackend,
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
466
   ) -> Result<()> {
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
467
     Err(anyhow!(DownloadError::BackendUnavailable("reqwest")))
966f92770ddf lisp groveling and rust fmt
ellis <ellis@rwest.io>
parents: 71
diff changeset
468
   }
71
97c99e44a22f rustup tomfoolery - installer and lib/dl
ellis <ellis@rwest.io>
parents:
diff changeset
469
 }