Added address module, removed std.typecons usage, and prepped request module for removing remaining std lib imports.
This commit is contained in:
parent
144ac5c7b2
commit
a5a3774d69
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* Defines various address types for use with HTTP communication.
|
||||
*/
|
||||
module handy_http_primitives.address;
|
||||
|
||||
struct IPv4InternetAddress {
|
||||
const ubyte[4] bytes;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
struct IPv6InternetAddress {
|
||||
const ubyte[16] bytes;
|
||||
const ushort port;
|
||||
|
||||
string toString() const {
|
||||
return "Not implemented!";
|
||||
}
|
||||
}
|
||||
|
||||
struct UnixSocketAddress {
|
||||
const string path;
|
||||
|
||||
string toString() const {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
enum ClientAddressType {
|
||||
IPv4,
|
||||
IPv6,
|
||||
UNIX
|
||||
}
|
||||
|
||||
struct ClientAddress {
|
||||
const ClientAddressType type;
|
||||
const IPv4InternetAddress ipv4InternetAddress;
|
||||
const IPv6InternetAddress ipv6InternetAddress;
|
||||
const UnixSocketAddress unixSocketAddress;
|
||||
|
||||
string toString() const {
|
||||
if (type == ClientAddressType.IPv4) {
|
||||
return ipv4InternetAddress.toString();
|
||||
} else if (type == ClientAddressType.IPv6) {
|
||||
return ipv6InternetAddress.toString();
|
||||
} else {
|
||||
return unixSocketAddress.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static ClientAddress ofIPv4(IPv4InternetAddress addr) {
|
||||
return ClientAddress(ClientAddressType.IPv4, addr, IPv6InternetAddress.init, UnixSocketAddress.init);
|
||||
}
|
||||
|
||||
static ClientAddress ofIPv6(IPv6InternetAddress addr) {
|
||||
return ClientAddress(ClientAddressType.IPv6, IPv4InternetAddress.init, addr, UnixSocketAddress.init);
|
||||
}
|
||||
|
||||
static ClientAddress ofUnixSocket(UnixSocketAddress addr) {
|
||||
return ClientAddress(ClientAddressType.UNIX, IPv4InternetAddress.init, IPv6InternetAddress.init, addr);
|
||||
}
|
||||
}
|
||||
|
||||
unittest {
|
||||
ClientAddress addr = ClientAddress.ofIPv4(IPv4InternetAddress([127, 0, 0, 1], 8000));
|
||||
assert(addr.toString == "127.0.0.1:8000");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to append an unsigned integer value to a char buffer. It is
|
||||
* assumed that there's enough space to write value.
|
||||
* Params:
|
||||
* value = The value to append.
|
||||
* buffer = The buffer to append to.
|
||||
* idx = A reference to a variable tracking the next writable index in the buffer.
|
||||
*/
|
||||
private void writeUIntToBuffer(uint value, char[] buffer, ref size_t idx) {
|
||||
const size_t startIdx = idx;
|
||||
while (true) {
|
||||
ubyte remainder = value % 10;
|
||||
value /= 10;
|
||||
buffer[idx++] = cast(char) ('0' + remainder);
|
||||
if (value == 0) break;
|
||||
}
|
||||
// Swap the characters to proper order.
|
||||
for (size_t i = 0; i < (idx - startIdx) / 2; i++) {
|
||||
size_t p1 = i + startIdx;
|
||||
size_t p2 = idx - i - 1;
|
||||
char tmp = buffer[p1];
|
||||
buffer[p1] = buffer[p2];
|
||||
buffer[p2] = tmp;
|
||||
}
|
||||
}
|
|
@ -4,8 +4,6 @@
|
|||
*/
|
||||
module handy_http_primitives.optional;
|
||||
|
||||
import std.typecons : Nullable;
|
||||
|
||||
/**
|
||||
* A simple wrapper around a value to make it optionally present.
|
||||
*/
|
||||
|
@ -26,17 +24,6 @@ struct Optional(T) {
|
|||
return Optional!T(value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an optional value using a Phobos nullable.
|
||||
* Params:
|
||||
* nullableValue = The nullable value to use.
|
||||
* Returns: An optional that contains the given nullable value.
|
||||
*/
|
||||
static Optional!T of (Nullable!T nullableValue) {
|
||||
if (nullableValue.isNull) return Optional!T.empty();
|
||||
return Optional!T.of(nullableValue.get);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an optional that's empty.
|
||||
* Returns: An optional that is empty.
|
||||
|
@ -45,18 +32,6 @@ struct Optional(T) {
|
|||
return Optional!T(T.init, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this optional to a Phobos-style Nullable.
|
||||
* Returns: A `Nullable!T` representing this optional.
|
||||
*/
|
||||
Nullable!T asNullable() {
|
||||
Nullable!T n;
|
||||
if (!this.isNull) {
|
||||
n = this.value;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of this optional if it exists, otherwise uses a given
|
||||
* default value.
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
module handy_http_primitives.request;
|
||||
|
||||
import streams : InputStream;
|
||||
import std.traits : isSomeString, EnumMembers;
|
||||
import std.traits : EnumMembers;
|
||||
|
||||
import handy_http_primitives.multivalue_map;
|
||||
import handy_http_primitives.optional;
|
||||
import handy_http_primitives.address;
|
||||
|
||||
/**
|
||||
* The HTTP request struct which represents the content of an HTTP request as
|
||||
|
@ -14,7 +15,7 @@ struct ServerHttpRequest {
|
|||
/// The HTTP version of the request.
|
||||
const HttpVersion httpVersion = HttpVersion.V1;
|
||||
/// The remote address of the client that sent this request.
|
||||
const InternetAddress clientAddress;
|
||||
const ClientAddress clientAddress;
|
||||
/// The HTTP verb used in the request.
|
||||
const string method = HttpMethod.GET;
|
||||
/// The URL that was requested.
|
||||
|
@ -60,7 +61,8 @@ public enum HttpMethod : string {
|
|||
* s = The string to parse.
|
||||
* Returns: An optional which may contain an HttpMethod, if one was parsed.
|
||||
*/
|
||||
Optional!HttpMethod parseHttpMethod(S)(S s) if (isSomeString!S) {
|
||||
Optional!HttpMethod parseHttpMethod(string s) {
|
||||
// TODO: Remove this function now that we're using plain string HTTP methods.
|
||||
import std.uni : toUpper;
|
||||
import std.string : strip;
|
||||
static foreach (m; EnumMembers!HttpMethod) {
|
||||
|
@ -82,29 +84,6 @@ unittest {
|
|||
assert(parseHttpMethod("") == Optional!HttpMethod.empty);
|
||||
}
|
||||
|
||||
/// The data representing a remote IPv4 internet address, available as an int or bytes.
|
||||
union IPv4InternetAddress {
|
||||
const uint intValue;
|
||||
const ubyte[4] bytes;
|
||||
}
|
||||
|
||||
/// The data representing a remote IPv6 internet address.
|
||||
struct IPv6InternetAddress {
|
||||
const ubyte[16] bytes;
|
||||
}
|
||||
|
||||
/// A remote internet address, which is either IPv4 or IPv6. Check `isIPv6`.
|
||||
struct InternetAddress {
|
||||
/// True if this address is IPv6. False if this is an IPv4 address.
|
||||
const bool isIPv6;
|
||||
/// The port number assigned to the connecting client on this machine.
|
||||
const ushort port;
|
||||
union {
|
||||
IPv4InternetAddress ipv4Address;
|
||||
IPv6InternetAddress ipv6Address;
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a single query parameter's key and values.
|
||||
struct QueryParameter {
|
||||
string key;
|
||||
|
@ -149,7 +128,8 @@ QueryParameter[] parseQueryParameters(string url) {
|
|||
key = currentParamStr[0 .. currentParamEqualsIdx];
|
||||
val = currentParamStr[currentParamEqualsIdx + 1 .. $];
|
||||
}
|
||||
// Clean up URI-encoded characters. TODO: do this without using std lib GC methods?
|
||||
// Clean up URI-encoded characters.
|
||||
// TODO: Do this without using std lib GC methods?
|
||||
import std.uri : decodeComponent;
|
||||
import std.string : replace;
|
||||
key = key.replace("+", " ").decodeComponent();
|
||||
|
|
Loading…
Reference in New Issue