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