1 module hunt.http.codec.http.model.HostPort;
2 
3 import hunt.lang.exception;
4 import hunt.string;
5 
6 import std.array;
7 import std.string;
8 
9 /**
10  * Parse an authority string into Host and Port
11  * <p>
12  * Parse a string in the form "host:port", handling IPv4 an IPv6 hosts
13  * </p>
14  *
15  */
16 class HostPort {
17 	private string _host;
18 	private int _port;
19 
20 	this(string authority) {
21 		if (authority.empty)
22 			throw new IllegalArgumentException("No Authority");
23 		try {
24 			if (authority[0] == '[') {
25 				// ipv6reference
26 				int close = cast(int)authority.lastIndexOf(']');
27 				if (close < 0)
28 					throw new IllegalArgumentException("Bad IPv6 host");
29 				_host = authority[0..close + 1];
30 
31 				if (authority.length > close + 1) {
32 					if (authority[close + 1] != ':')
33 						throw new IllegalArgumentException("Bad IPv6 port");
34 					_port = StringUtils.toInt(authority, close + 2);
35 				} else
36 					_port = 0;
37 			} else {
38 				// ipv4address or hostname
39 				int c = cast(int)authority.lastIndexOf(':');
40 				if (c >= 0) {
41 					_host = authority[0..c];
42 					_port = StringUtils.toInt(authority, c + 1);
43 				} else {
44 					_host = authority;
45 					_port = 0;
46 				}
47 			}
48 		} catch (IllegalArgumentException iae) {
49 			throw iae;
50 		} catch (Exception ex) {
51 			throw new IllegalArgumentException("Bad HostPort");
52 		}
53 		if (_host.empty())
54 			throw new IllegalArgumentException("Bad host");
55 		if (_port < 0)
56 			throw new IllegalArgumentException("Bad port");
57 	}
58 
59 	/**
60 	 * Get the host.
61 	 * 
62 	 * @return the host
63 	 */
64 	string getHost() {
65 		return _host;
66 	}
67 
68 	/**
69 	 * Get the port.
70 	 * 
71 	 * @return the port
72 	 */
73 	int getPort() {
74 		return _port;
75 	}
76 
77 	/**
78 	 * Get the port.
79 	 * 
80 	 * @param defaultPort,
81 	 *            the default port to return if a port is not specified
82 	 * @return the port
83 	 */
84 	int getPort(int defaultPort) {
85 		return _port > 0 ? _port : defaultPort;
86 	}
87 
88 	/**
89 	 * Normalize IPv6 address as per https://www.ietf.org/rfc/rfc2732.txt
90 	 * 
91 	 * @param host
92 	 *            A host name
93 	 * @return Host name surrounded by '[' and ']' as needed.
94 	 */
95 	static string normalizeHost(string host) {
96 		// if it is normalized IPv6 or could not be IPv6, return
97 		if (host.empty() || host[0] == '[' || host.indexOf(':') < 0)
98 			return host;
99 
100 		// normalize with [ ]
101 		return "[" ~ host ~ "]";
102 	}
103 }