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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
use std::io::Read;
use std::collections::VecDeque;

use crate::client::*;
use crate::header::*;
use crate::*;

pub(crate) struct ResponseData
{
	pub(crate) read_queue: VecDeque<u8>,
	pub(crate) headers_done: bool,
	pub(crate) transfer_done: bool,
	pub(crate) headers: HeaderMap,
	pub(crate) status_code: StatusCode,
}

impl ResponseData
{
	pub(crate) fn new() -> Self
	{
		Self
		{
			read_queue: VecDeque::new(),
			headers_done: false,
			transfer_done: false,
			headers: HeaderMap::new(),
			status_code: StatusCode::NOT_IMPLEMENTED,
		}
	}
}

/// Represents the result of an HTTP request
///
/// This object implements `Read`, which means
/// you can read it in a streaming fashion or
/// use the accessors to read it into memory.
pub struct Response
{
	pub(crate) client: Client,
	pub(crate) rd: Box<ResponseData>,
//	pub(crate) h: RefCell<curl::multi::Easy2Handle<Tranceiver>>,
//	pub(crate) tx: Rc<RefCell<TranceiverData>>,
//	pub(crate) multi: curl::multi::Multi,
}

impl Response
{
	/// Returns the HTTP status code.
	///
	/// `is_success()` is the most convenient way to
	/// make sure the message was received.
	pub fn status(&self) -> StatusCode
	{
		self.rd.status_code
	}

	/// Gets the Content-Length of the returned body.
	///
	/// If the server reported the length of the returned body,
	/// then this returns it, and None if the server didn't
	/// specify. This value is available before the body
	/// is read with [`data()`](#method.data) or [`text_as_utf8()`](#method.text_as_utf8)
	///
	/// It may also be a lie.
	pub fn content_length(&self) -> Option<u64>
	{
		self.header(CONTENT_LENGTH)
			.map(|v| v.to_str().ok()?.parse().ok())?
	}

	/// Read the entire document and interpret it as UTF-8.
	///
	/// Read the entire message body into memory.
	pub fn text_as_utf8(&mut self) -> std::io::Result<String>
	{
		String::from_utf8(self.data()?)
			.map_err(
				|e|
					std::io::Error::new(
						std::io::ErrorKind::InvalidData,
						Error::new(Kind::NotUtf8(e), None)
					)
			)
	}

	/// Copies this Read object into another Write object
	///
	/// Returns the number of bytes read or an Error
	/// if the request failed at some point.
	pub fn copy_to<W: std::io::Write+?Sized>(&mut self, w: &mut W)
		-> std::io::Result<u64>
	{
		std::io::copy(self, w)
	}

	/// Gets a specific HTTP header by name
	pub fn header<K: AsHeaderName>(&self, k: K) -> Option<&HeaderValue>
	{
		self.headers().get(k)
	}

	/// Reads all data into a vector, emptying this Response
	pub fn data(&mut self)
		-> std::io::Result<Vec<u8>>
	{
		let mut d = vec!();
		self.read_to_end(&mut d)?;
		Ok(d)
	}

	/// Gets a multimap of all HTTP headers received
	pub fn headers(&self) -> &HeaderMap
	{
		&self.rd.headers
	}

	/// The remote ip address for this connection
	pub fn remote_address(&self) -> Result<&str>
	{
		unsafe
		{
			let p = std::ptr::null_mut();

			crate::client::cr(sys::curl_easy_getinfo(
				self.client.easy,
				sys::CURLINFO_PRIMARY_IP,
				&p
			))?;
			std::str::from_utf8(std::ffi::CStr::from_ptr(p).to_bytes())
				.map_err(|e| Error::new(Kind::Curl(format!("utf-8 decoding: {}",e)), None))
		}
	}
}

impl std::fmt::Debug for Response
{
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
	{
		f.write_fmt(format_args!("Response {{code={}}}", self.status()))
	}
}


impl std::io::Read for Response
{
	fn read(&mut self, buf: &mut [u8])
		-> std::io::Result<usize>
	{
		let mut pos = 0;
		while pos != buf.len()
		{
			if self.rd.read_queue.len() == 0 && !self.rd.transfer_done
			{
				self.rd.transfer_done = self.client.wait_and_process()
					.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
			}
			if self.rd.read_queue.len() == 0 && self.rd.transfer_done
			{
				break;
			}

			let num1;
			let num2;
			let data = &mut self.rd;
			{
				let (a,b) = data.read_queue.as_slices();
				num1 = std::cmp::min(buf.len()-pos, a.len());
				buf[pos .. pos+num1].copy_from_slice(&a[0 .. num1]);
				pos += num1;
				num2 = std::cmp::min(buf.len()-pos, b.len());
				buf[pos .. pos+num2].copy_from_slice(&b[0 .. num2]);
				pos += num2;
			}
			data.read_queue.drain( 0 .. num1+num2 );
		}

		Ok(pos)
	}
}