1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! An idiomatic synchronous Rust library for making HTTP requests.
//!
//! It's implemented in terms of curl.
//!
//! # Example
//!
//! ```rust
//! let mut output = vec!();
//! idcurl::get("http://example.com")
//!     .expect("error making request")
//!     .copy_to(&mut output)
//!     .unwrap();
//! ```
//!
//! ```rust
//! let body = r#"{ "hello": "world" }"#;
//!
//! let mut response = idcurl::Request::post(
//!     "http://example.com".to_string()
//! )
//!     .header("Content-Type", "application/json")
//!     .body(std::io::Cursor::new(body))
//!     .send()
//!     .expect("http request");
//! assert!(response.status().is_success());
//! std::io::copy(&mut response, &mut std::io::stdout())
//!     .expect("reading response");
//! ```

mod client;
mod request;
mod response;
mod method;
mod error;

pub mod header
{
	pub use http::header::*;
}

pub use error::*;
pub use request::*;
pub use response::*;
pub use method::*;

pub type Result<T> = std::result::Result<T, Error>;
use std::sync::{Once};

/// Make a basic http GET request to the given URL
///
/// Returns an error if the url couldn't be parsed
/// or the request couldn't be made.
///
/// The response is ready for reading as an `std::io::Read`,
/// which you may want to convert to a `std::io::BufRead`.
///
/// ```
/// let mut response = idcurl::get("http://example.com")
///     .expect("failed to make HTTP request");
/// assert!(response.status().is_success());
/// response.copy_to(&mut std::io::stdout()).unwrap();
/// ```
pub fn get(url: &str)
	-> Result<Response>
{
	Request::get(url.to_owned())
		.send()
}

/// Sends an http POST request to the given URL.
///
/// The payload to send is read from `r`, which can be easily made
/// with `std::io::Cursor` in case you're using a slice as a source.
///
/// ```
/// let data = b"something to send";
/// idcurl::post("http://example.com", std::io::Cursor::new(data))
///     .unwrap()
///     .copy_to(&mut std::io::stdout())
///     .unwrap();
/// ```
pub fn post<'b, R: std::io::Read+'b>(url: &str, r: R)
	-> Result<Response>
{
	Request::post(url.to_owned())
		.body(r)
		.send()
}

/// Sends an http PUT request to the given URL.
///
/// The payload to send is read from `r`, which can be easily made
/// with `std::io::Cursor` in case you're using a slice as a source.
///
/// ```
/// let data = b"something to send";
/// idcurl::put("http://example.com", std::io::Cursor::new(data))
///     .unwrap()
///     .copy_to(&mut std::io::stdout())
///     .unwrap();
/// ```
pub fn put<'b, R: std::io::Read+'b>(url: &str, r: R)
	-> Result<Response>
{
	Request::put(url.to_owned())
		.body(r)
		.send()
}

use curl_sys as sys;

pub use http::status::*;

/// Initializes the underlying libcurl library.
///
/// It's not required to call this before the library is used, but it's
/// recommended to do so as soon as the program starts.
pub fn init()
{
	static INIT: Once = Once::new();
	INIT.call_once(||
	{
		platform_init();
		unsafe
		{
			assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0);
		}

		// Note that we explicitly don't schedule a call to
		// `curl_global_cleanup`. The documentation for that function says
		//
		// > You must not call it when any other thread in the program (i.e. a
		// > thread sharing the same memory) is running. This doesn't just mean
		// > no other thread that is using libcurl.
		//
		// We can't ever be sure of that, so unfortunately we can't call the
		// function.
	});

	#[cfg(need_openssl_init)]
	fn platform_init()
	{
		openssl_sys::init();
	}

	#[cfg(not(need_openssl_init))]
	fn platform_init() {}
}