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
extern crate curl;

use std::net::{IpAddr,AddrParseError};
use std::str;
use curl::easy::{Easy2, Handler, WriteError};

/// Any kind of error which may occur during retrieving the IP.
#[derive(Debug)]
pub enum MyIpError {
	/// This error occurs if we cannot parse the IP we got.
	AddressParseError(AddrParseError),

	/// This error occurs if a curl request failed.
	CurlError(curl::Error),

	/// This error occurs if the remote server returned an error.
	HttpError { code: u32 },

	/// This error occurs if the remote server returned invalid UTF-8 data.
	Utf8Error(str::Utf8Error)
}

struct Collector(Vec<u8>);

impl Handler for Collector {
	fn write(&mut self, data: &[u8]) -> Result<usize, WriteError> {
		self.0.extend_from_slice(data);
		Ok(data.len())
	}
}

/// Try to retrieve the public IP of the device
/// this code is executed on.
///
/// # Example
/// ```
/// let ip: ::std::net::IpAddr = match my_internet_ip::get() {
///     Ok(ip) => ip,
///     Err(e) => panic!("Could not get IP: {:?}", e)
/// };
///
/// // Do something with the IP, e.g. print it
/// ```
pub fn get() -> Result<IpAddr,MyIpError> {
	let mut easy = Easy2::new(Collector(Vec::new()));
	easy.get(true).map_err(|e| MyIpError::CurlError(e))?;
	easy.url("http://www.myip.ch").map_err(|e| MyIpError::CurlError(e))?;
	easy.perform().map_err(|e| MyIpError::CurlError(e))?;

	let response_code = easy.response_code().map_err(|e| MyIpError::CurlError(e))?;
	if response_code != 200 {
		return Err(MyIpError::HttpError{code: response_code});
	}

	let data = &easy.get_ref().0;
	let data_string: &str = str::from_utf8(&data).map_err(|e| MyIpError::Utf8Error(e))?;

	let mut ip = String::new();
	for line in data_string.split("\n") {
		if line.contains("Current IP Address") {
			ip = String::from(line.replace("<br/>","").replace("Current IP Address: ", "").trim());
		}
	}

	ip.parse().map_err(|e| MyIpError::AddressParseError(e))
}

#[cfg(test)]
mod tests{
	use super::*;

	#[test]
	fn simple() {
		println!("My IP: {}", get().unwrap());
	}
}