1#![warn(missing_docs)]
2
3pub use auth::{AuthDecision, AuthHandler, AuthParam, AuthTarget, Challenge};
78pub use client::{
79 CacheMode, Client, ClientBuilder, ConnectionPolicy, ParserStrictness, ProxyConfig, Session,
80};
81pub use errors::NanoGetError;
82pub use request::{Header, Method, RedirectPolicy, Request};
83pub use response::{HttpVersion, Response};
84pub use url::{ToUrl, Url};
85
86mod auth;
87mod client;
88mod date;
89mod errors;
90mod http;
91#[cfg(feature = "https")]
92mod https;
93mod request;
94mod response;
95mod url;
96
97const DEFAULT_REDIRECT_LIMIT: usize = 10;
98
99pub fn get<U: ToUrl>(url: U) -> Result<String, NanoGetError> {
108 helper_client().get(url)
109}
110
111pub fn get_bytes<U: ToUrl>(url: U) -> Result<Vec<u8>, NanoGetError> {
117 let request =
118 Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(DEFAULT_REDIRECT_LIMIT));
119 helper_client()
120 .execute(request)
121 .map(|response| response.body)
122}
123
124pub fn head<U: ToUrl>(url: U) -> Result<Response, NanoGetError> {
129 let request =
130 Request::head(url)?.with_redirect_policy(RedirectPolicy::follow(DEFAULT_REDIRECT_LIMIT));
131 helper_client().execute(request)
132}
133
134pub fn get_http<U: ToUrl>(url: U) -> Result<String, NanoGetError> {
138 get_http_bytes(url)
139 .and_then(|body| String::from_utf8(body).map_err(|error| error.utf8_error().into()))
140}
141
142pub fn get_http_bytes<U: ToUrl>(url: U) -> Result<Vec<u8>, NanoGetError> {
146 let request =
147 Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(DEFAULT_REDIRECT_LIMIT));
148 if !request.url().is_http() {
149 return Err(NanoGetError::UnsupportedScheme(
150 request.url().scheme.clone(),
151 ));
152 }
153 helper_client()
154 .execute(request)
155 .map(|response| response.body)
156}
157
158pub fn head_http<U: ToUrl>(url: U) -> Result<Response, NanoGetError> {
162 let request =
163 Request::head(url)?.with_redirect_policy(RedirectPolicy::follow(DEFAULT_REDIRECT_LIMIT));
164 if !request.url().is_http() {
165 return Err(NanoGetError::UnsupportedScheme(
166 request.url().scheme.clone(),
167 ));
168 }
169 helper_client().execute(request)
170}
171
172#[cfg(feature = "https")]
178pub fn get_https<U: ToUrl>(url: U) -> Result<String, NanoGetError> {
179 get_https_bytes(url)
180 .and_then(|body| String::from_utf8(body).map_err(|error| error.utf8_error().into()))
181}
182
183#[cfg(feature = "https")]
189pub fn get_https_bytes<U: ToUrl>(url: U) -> Result<Vec<u8>, NanoGetError> {
190 let request =
191 Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(DEFAULT_REDIRECT_LIMIT));
192 if !request.url().is_https() {
193 return Err(NanoGetError::UnsupportedScheme(
194 request.url().scheme.clone(),
195 ));
196 }
197 helper_client()
198 .execute(request)
199 .map(|response| response.body)
200}
201
202#[cfg(feature = "https")]
208pub fn head_https<U: ToUrl>(url: U) -> Result<Response, NanoGetError> {
209 let request =
210 Request::head(url)?.with_redirect_policy(RedirectPolicy::follow(DEFAULT_REDIRECT_LIMIT));
211 if !request.url().is_https() {
212 return Err(NanoGetError::UnsupportedScheme(
213 request.url().scheme.clone(),
214 ));
215 }
216 helper_client().execute(request)
217}
218
219fn helper_client() -> Client {
220 Client::builder()
221 .redirect_policy(RedirectPolicy::follow(DEFAULT_REDIRECT_LIMIT))
222 .build()
223}
224
225#[cfg(test)]
226mod tests {
227 use crate::client::{CacheMode, Client, ConnectionPolicy, ParserStrictness};
228 use crate::{get_http_bytes, Method, RedirectPolicy, Request, Url};
229
230 #[test]
231 fn request_constructors_work() {
232 let request = Request::new(Method::Get, "http://example.com").unwrap();
233 assert_eq!(request.method(), Method::Get);
234 }
235
236 #[test]
237 fn default_url_scheme_is_http() {
238 let url = Url::parse("example.com").unwrap();
239 assert!(url.is_http());
240 }
241
242 #[test]
243 fn helper_requests_follow_redirects_by_default() {
244 let request = Request::get("http://example.com")
245 .unwrap()
246 .with_redirect_policy(RedirectPolicy::follow(10));
247 assert_eq!(request.redirect_policy(), RedirectPolicy::follow(10));
248 }
249
250 #[test]
251 fn http_only_helpers_reject_https_urls() {
252 let error = get_http_bytes("https://example.com").unwrap_err();
253 assert!(matches!(error, crate::NanoGetError::UnsupportedScheme(_)));
254 }
255
256 #[test]
257 fn http_only_text_and_head_helpers_reject_https_urls() {
258 let error = crate::get_http("https://example.com").unwrap_err();
259 assert!(matches!(error, crate::NanoGetError::UnsupportedScheme(_)));
260
261 let error = crate::head_http("https://example.com").unwrap_err();
262 assert!(matches!(error, crate::NanoGetError::UnsupportedScheme(_)));
263 }
264
265 #[test]
266 fn http_only_helpers_execute_http_paths() {
267 let error = get_http_bytes("http://127.0.0.1:9").unwrap_err();
268 assert!(matches!(
269 error,
270 crate::NanoGetError::Connect(_) | crate::NanoGetError::Io(_)
271 ));
272
273 let error = crate::head_http("http://127.0.0.1:9").unwrap_err();
274 assert!(matches!(
275 error,
276 crate::NanoGetError::Connect(_) | crate::NanoGetError::Io(_)
277 ));
278 }
279
280 #[cfg(feature = "https")]
281 #[test]
282 fn https_only_helpers_reject_http_urls() {
283 let error = crate::get_https("http://example.com").unwrap_err();
284 assert!(matches!(error, crate::NanoGetError::UnsupportedScheme(_)));
285
286 let error = crate::get_https_bytes("http://example.com").unwrap_err();
287 assert!(matches!(error, crate::NanoGetError::UnsupportedScheme(_)));
288
289 let error = crate::head_https("http://example.com").unwrap_err();
290 assert!(matches!(error, crate::NanoGetError::UnsupportedScheme(_)));
291 }
292
293 #[cfg(feature = "https")]
294 #[test]
295 fn https_only_helpers_execute_https_paths() {
296 let error = crate::get_https_bytes("https://127.0.0.1:9").unwrap_err();
297 assert!(matches!(
298 error,
299 crate::NanoGetError::Connect(_)
300 | crate::NanoGetError::Io(_)
301 | crate::NanoGetError::Tls(_)
302 ));
303 }
304
305 #[test]
306 fn client_builder_is_available() {
307 let _client = Client::builder()
308 .connection_policy(ConnectionPolicy::Reuse)
309 .cache_mode(CacheMode::Memory)
310 .parser_strictness(ParserStrictness::Lenient)
311 .build();
312 }
313}