Added IPv6 toString implementation.
This commit is contained in:
parent
9a4c4a46f6
commit
79e6912b56
|
@ -14,3 +14,4 @@ handy-http-primitives-test-*
|
||||||
*.o
|
*.o
|
||||||
*.obj
|
*.obj
|
||||||
*.lst
|
*.lst
|
||||||
|
*.a
|
||||||
|
|
2
dub.json
2
dub.json
|
@ -7,6 +7,6 @@
|
||||||
"streams": "~>3.5.0"
|
"streams": "~>3.5.0"
|
||||||
},
|
},
|
||||||
"description": "Basic HTTP types that can be shared among various projects.",
|
"description": "Basic HTTP types that can be shared among various projects.",
|
||||||
"license": "MIT",
|
"license": "CC0",
|
||||||
"name": "handy-http-primitives"
|
"name": "handy-http-primitives"
|
||||||
}
|
}
|
|
@ -10,18 +10,6 @@ module handy_http_primitives.address;
|
||||||
struct IPv4InternetAddress {
|
struct IPv4InternetAddress {
|
||||||
const ubyte[4] bytes;
|
const ubyte[4] bytes;
|
||||||
const ushort port;
|
const ushort port;
|
||||||
|
|
||||||
string toString() const {
|
|
||||||
char[21] buffer;
|
|
||||||
size_t idx;
|
|
||||||
for (size_t i = 0; i < 4; i++) {
|
|
||||||
writeUIntToBuffer(bytes[i], buffer, idx);
|
|
||||||
if (i < 3) buffer[idx++] = '.';
|
|
||||||
}
|
|
||||||
buffer[idx++] = ':';
|
|
||||||
writeUIntToBuffer(port, buffer, idx);
|
|
||||||
return buffer[0 .. idx].idup;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,10 +19,6 @@ struct IPv4InternetAddress {
|
||||||
struct IPv6InternetAddress {
|
struct IPv6InternetAddress {
|
||||||
const ubyte[16] bytes;
|
const ubyte[16] bytes;
|
||||||
const ushort port;
|
const ushort port;
|
||||||
|
|
||||||
string toString() const {
|
|
||||||
return "Not implemented!";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,10 +27,6 @@ struct IPv6InternetAddress {
|
||||||
*/
|
*/
|
||||||
struct UnixSocketAddress {
|
struct UnixSocketAddress {
|
||||||
const string path;
|
const string path;
|
||||||
|
|
||||||
string toString() const {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines the different possible address types, used by `ClientAddress`.
|
/// Defines the different possible address types, used by `ClientAddress`.
|
||||||
|
@ -66,14 +46,33 @@ struct ClientAddress {
|
||||||
const IPv6InternetAddress ipv6InternetAddress;
|
const IPv6InternetAddress ipv6InternetAddress;
|
||||||
const UnixSocketAddress unixSocketAddress;
|
const UnixSocketAddress unixSocketAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes this address in a human-readable string representation.
|
||||||
|
* Returns: The string representation of this address.
|
||||||
|
*/
|
||||||
string toString() const {
|
string toString() const {
|
||||||
if (type == ClientAddressType.IPv4) {
|
if (type == ClientAddressType.UNIX) return unixSocketAddress.path;
|
||||||
return ipv4InternetAddress.toString();
|
version (Posix) { import core.sys.posix.arpa.inet : inet_ntop, AF_INET, AF_INET6; }
|
||||||
} else if (type == ClientAddressType.IPv6) {
|
version (Windows) { import core.sys.windows.winsock2 : inet_ntop, AF_INET, AF_INET6; }
|
||||||
return ipv6InternetAddress.toString();
|
const int addressFamily = type == ClientAddressType.IPv4
|
||||||
} else {
|
? AF_INET
|
||||||
return unixSocketAddress.toString();
|
:AF_INET6;
|
||||||
|
const scope void* inputBytes = type == ClientAddressType.IPv4
|
||||||
|
? ipv4InternetAddress.bytes.ptr
|
||||||
|
: ipv6InternetAddress.bytes.ptr;
|
||||||
|
const ushort port = type == ClientAddressType.IPv4
|
||||||
|
? ipv4InternetAddress.port
|
||||||
|
: ipv6InternetAddress.port;
|
||||||
|
char[45] buf; // Buffer is sized to maximum possible IPv6 length (39 chars), plus 6 chars for port string.
|
||||||
|
auto ret = inet_ntop(addressFamily, inputBytes, buf.ptr, buf.length);
|
||||||
|
if (ret is null) {
|
||||||
|
throw new Exception("Failed to serialize address.");
|
||||||
}
|
}
|
||||||
|
size_t strLength = 0;
|
||||||
|
while (buf[strLength] != '\0') strLength++;
|
||||||
|
buf[strLength++] = ':';
|
||||||
|
writeUIntToBuffer(port, buf, strLength);
|
||||||
|
return buf[0..strLength].idup;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClientAddress ofIPv4(IPv4InternetAddress addr) {
|
static ClientAddress ofIPv4(IPv4InternetAddress addr) {
|
||||||
|
@ -92,6 +91,12 @@ struct ClientAddress {
|
||||||
unittest {
|
unittest {
|
||||||
ClientAddress addr = ClientAddress.ofIPv4(IPv4InternetAddress([127, 0, 0, 1], 8000));
|
ClientAddress addr = ClientAddress.ofIPv4(IPv4InternetAddress([127, 0, 0, 1], 8000));
|
||||||
assert(addr.toString == "127.0.0.1:8000");
|
assert(addr.toString == "127.0.0.1:8000");
|
||||||
|
ClientAddress addr6 = ClientAddress.ofIPv6(IPv6InternetAddress(
|
||||||
|
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
8000
|
||||||
|
));
|
||||||
|
assert(addr6.toString == ":::8000");
|
||||||
|
// TODO: Add more comprehensive testing.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,7 +3,6 @@ module handy_http_primitives.request;
|
||||||
import streams : InputStream;
|
import streams : InputStream;
|
||||||
import std.traits : EnumMembers;
|
import std.traits : EnumMembers;
|
||||||
|
|
||||||
import handy_http_primitives.multivalue_map;
|
|
||||||
import handy_http_primitives.optional;
|
import handy_http_primitives.optional;
|
||||||
import handy_http_primitives.address;
|
import handy_http_primitives.address;
|
||||||
|
|
||||||
|
@ -21,7 +20,7 @@ struct ServerHttpRequest {
|
||||||
/// The URL that was requested.
|
/// The URL that was requested.
|
||||||
const string url = "";
|
const string url = "";
|
||||||
/// A case-insensitive map of all request headers.
|
/// A case-insensitive map of all request headers.
|
||||||
const(CaseInsensitiveStringMultiValueMap) headers;
|
const(string[][string]) headers;
|
||||||
/// The underlying stream used to read the body from the request.
|
/// The underlying stream used to read the body from the request.
|
||||||
InputStream!ubyte inputStream;
|
InputStream!ubyte inputStream;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ struct ServerHttpResponse {
|
||||||
* A struct containing basic information about a response status.
|
* A struct containing basic information about a response status.
|
||||||
*/
|
*/
|
||||||
struct StatusInfo {
|
struct StatusInfo {
|
||||||
const ushort code;
|
ushort code;
|
||||||
const string text;
|
string text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,3 +101,13 @@ enum HttpStatus : StatusInfo {
|
||||||
NOT_EXTENDED = StatusInfo(510, "Not Extended"),
|
NOT_EXTENDED = StatusInfo(510, "Not Extended"),
|
||||||
NETWORK_AUTHENTICATION_REQUIRED = StatusInfo(511, "Network Authentication Required")
|
NETWORK_AUTHENTICATION_REQUIRED = StatusInfo(511, "Network Authentication Required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Common "Content-Type" header values.
|
||||||
|
enum ContentTypes : string {
|
||||||
|
APPLICATION_JSON = "application/json",
|
||||||
|
APPLICATION_XML = "application/xml",
|
||||||
|
|
||||||
|
TEXT_PLAIN = "text/plain",
|
||||||
|
TEXT_HTML = "text/html",
|
||||||
|
TEXT_CSS = "text/css"
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue