summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-06-30 04:19:20 +0200
committerEugen Wissner <belka@caraus.de>2017-06-30 04:19:20 +0200
commite46e45ad5a43bfc281e3e058eb37676ba00a04dd (patch)
tree7f603b066953492e1e90303fe249940cc4417ff2 /source
parente79c75df81e6c7ae10669448a16adae4672aa282 (diff)
downloadtanya-e46e45ad5a43bfc281e3e058eb37676ba00a04dd.tar.gz
Remove previously deprecated modules
* tanya.network.uri * tanya.network.inet * tanya.memory.types
Diffstat (limited to 'source')
-rw-r--r--source/tanya/memory/smartref.d8
-rw-r--r--source/tanya/memory/types.d301
-rw-r--r--source/tanya/net/uri.d22
-rw-r--r--source/tanya/network/inet.d19
-rw-r--r--source/tanya/network/package.d2
-rw-r--r--source/tanya/network/url.d1192
6 files changed, 15 insertions, 1529 deletions
diff --git a/source/tanya/memory/smartref.d b/source/tanya/memory/smartref.d
index 4a00672..87aaa45 100644
--- a/source/tanya/memory/smartref.d
+++ b/source/tanya/memory/smartref.d
@@ -23,7 +23,7 @@ import std.range;
import std.traits;
import tanya.memory;
-package template Payload(T)
+private template Payload(T)
{
static if (is(T == class) || is(T == interface) || isArray!T)
{
@@ -35,7 +35,7 @@ package template Payload(T)
}
}
-package final class RefCountedStore(T)
+private final class RefCountedStore(T)
{
T payload;
size_t counter = 1;
@@ -68,14 +68,14 @@ package final class RefCountedStore(T)
}
}
-package void separateDeleter(T)(RefCountedStore!T storage,
+private void separateDeleter(T)(RefCountedStore!T storage,
shared Allocator allocator)
{
allocator.dispose(storage.payload);
allocator.dispose(storage);
}
-package void unifiedDeleter(T)(RefCountedStore!T storage,
+private void unifiedDeleter(T)(RefCountedStore!T storage,
shared Allocator allocator)
{
auto ptr1 = finalize(storage);
diff --git a/source/tanya/memory/types.d b/source/tanya/memory/types.d
deleted file mode 100644
index e255d5a..0000000
--- a/source/tanya/memory/types.d
+++ /dev/null
@@ -1,301 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Smart pointers.
- *
- * $(RED Deprecated. Use $(D_PSYMBOL tanya.memory.smartref) instead.
- * This module will be removed in 0.8.0.)
- *
- * Copyright: Eugene Wissner 2016-2017.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- */
-deprecated("Use tanya.memory.smartref instead")
-module tanya.memory.types;
-
-import core.exception;
-import std.algorithm.comparison;
-import std.algorithm.mutation;
-import std.conv;
-import std.range;
-import std.traits;
-import tanya.memory;
-public import tanya.memory.smartref : RefCounted, Payload;
-
-version (unittest)
-{
- private struct B
- {
- int prop;
- @disable this();
- this(int param1) @nogc
- {
- prop = param1;
- }
- }
-}
-
-/**
- * $(D_PSYMBOL Scoped) stores an object that gets destroyed at the end of its scope.
- *
- * Params:
- * T = Value type.
- */
-struct Scoped(T)
-{
- private Payload!T payload;
-
- invariant
- {
- assert(payload is null || allocator_ !is null);
- }
-
- /**
- * Takes ownership over $(D_PARAM value), setting the counter to 1.
- * $(D_PARAM value) may be a pointer, an object or a dynamic array.
- *
- * Params:
- * value = Value whose ownership is taken over.
- * allocator = Allocator used to destroy the $(D_PARAM value) and to
- * allocate/deallocate internal storage.
- *
- * Precondition: $(D_INLINECODE allocator !is null)
- */
- this()(auto ref Payload!T value,
- shared Allocator allocator = defaultAllocator)
- {
- this(allocator);
-
- move(value, this.payload);
- static if (__traits(isRef, value))
- {
- value = null;
- }
- }
-
- /// Ditto.
- this(shared Allocator allocator)
- in
- {
- assert(allocator !is null);
- }
- body
- {
- this.allocator_ = allocator;
- }
-
- /**
- * $(D_PSYMBOL Scoped) is noncopyable.
- */
- @disable this(this);
-
- /**
- * Destroys the owned object.
- */
- ~this()
- {
- if (this.payload !is null)
- {
- allocator.dispose(this.payload);
- }
- }
-
- /**
- * Initialized this $(D_PARAM Scoped) and takes ownership over
- * $(D_PARAM rhs).
- *
- * To reset $(D_PSYMBOL Scoped) assign $(D_KEYWORD null).
- *
- * If the allocator wasn't set before, $(D_PSYMBOL defaultAllocator) will
- * be used. If you need a different allocator, create a new
- * $(D_PSYMBOL Scoped) and assign it.
- *
- * Params:
- * rhs = New object.
- *
- * Returns: $(D_KEYWORD this).
- */
- ref typeof(this) opAssign()(auto ref Payload!T rhs)
- {
- allocator.dispose(this.payload);
- move(rhs, this.payload);
-
- return this;
- }
-
- /// Ditto.
- ref typeof(this) opAssign(typeof(null))
- {
- allocator.dispose(this.payload);
- return this;
- }
-
- /// Ditto.
- ref typeof(this) opAssign(typeof(this) rhs)
- {
- swap(this.allocator_, rhs.allocator_);
- swap(this.payload, rhs.payload);
-
- return this;
- }
-
- /**
- * Returns: Reference to the owned object.
- */
- Payload!T get() pure nothrow @safe @nogc
- {
- return payload;
- }
-
- version (D_Ddoc)
- {
- /**
- * Params:
- * op = Operation.
- *
- * Dereferences the pointer. It is defined only for pointers, not for
- * reference types like classes, that can be accessed directly.
- *
- * Returns: Reference to the pointed value.
- */
- ref T opUnary(string op)()
- if (op == "*");
- }
- else static if (isPointer!(Payload!T))
- {
- ref T opUnary(string op)()
- if (op == "*")
- {
- return *payload;
- }
- }
-
- mixin DefaultAllocator;
- alias get this;
-}
-
-///
-@nogc unittest
-{
- auto p = defaultAllocator.make!int(5);
- auto s = Scoped!int(p, defaultAllocator);
- assert(p is null);
- assert(*s == 5);
-}
-
-///
-@nogc unittest
-{
- static bool destroyed = false;
-
- struct F
- {
- ~this() @nogc
- {
- destroyed = true;
- }
- }
- {
- auto s = Scoped!F(defaultAllocator.make!F(), defaultAllocator);
- }
- assert(destroyed);
-}
-
-/**
- * Constructs a new object of type $(D_PARAM T) and wraps it in a
- * $(D_PSYMBOL Scoped) using $(D_PARAM args) as the parameter list for
- * the constructor of $(D_PARAM T).
- *
- * Params:
- * T = Type of the constructed object.
- * A = Types of the arguments to the constructor of $(D_PARAM T).
- * allocator = Allocator.
- * args = Constructor arguments of $(D_PARAM T).
- *
- * Returns: Newly created $(D_PSYMBOL Scoped!T).
- *
- * Precondition: $(D_INLINECODE allocator !is null)
- */
-Scoped!T scoped(T, A...)(shared Allocator allocator, auto ref A args)
- if (!is(T == interface) && !isAbstractClass!T
- && !isAssociativeArray!T && !isArray!T)
-in
-{
- assert(allocator !is null);
-}
-body
-{
- auto payload = allocator.make!(T, shared Allocator, A)(args);
- return Scoped!T(payload, allocator);
-}
-
-/**
- * Constructs a new array with $(D_PARAM size) elements and wraps it in a
- * $(D_PSYMBOL Scoped).
- *
- * Params:
- * T = Array type.
- * size = Array size.
- * allocator = Allocator.
- *
- * Returns: Newly created $(D_PSYMBOL Scoped!T).
- *
- * Precondition: $(D_INLINECODE allocator !is null
- * && size <= size_t.max / ElementType!T.sizeof)
- */
-Scoped!T scoped(T)(shared Allocator allocator, const size_t size)
-@trusted
- if (isArray!T)
-in
-{
- assert(allocator !is null);
- assert(size <= size_t.max / ElementType!T.sizeof);
-}
-body
-{
- auto payload = allocator.resize!(ElementType!T)(null, size);
- return Scoped!T(payload, allocator);
-}
-
-private unittest
-{
- static assert(is(typeof(defaultAllocator.scoped!B(5))));
- static assert(is(typeof(defaultAllocator.scoped!(int[])(5))));
-}
-
-private unittest
-{
- auto s = defaultAllocator.scoped!int(5);
- assert(*s == 5);
-
- s = null;
- assert(s is null);
-}
-
-private unittest
-{
- auto s = defaultAllocator.scoped!int(5);
- assert(*s == 5);
-
- s = defaultAllocator.scoped!int(4);
- assert(*s == 4);
-}
-
-private @nogc unittest
-{
- auto p1 = defaultAllocator.make!int(5);
- auto p2 = p1;
- auto rc = Scoped!int(p1, defaultAllocator);
-
- assert(p1 is null);
- assert(rc.get() is p2);
-}
-
-private @nogc unittest
-{
- auto rc = Scoped!int(defaultAllocator);
- assert(rc.allocator is defaultAllocator);
-}
diff --git a/source/tanya/net/uri.d b/source/tanya/net/uri.d
index eac2f7a..da90011 100644
--- a/source/tanya/net/uri.d
+++ b/source/tanya/net/uri.d
@@ -13,7 +13,6 @@
module tanya.net.uri;
import std.ascii : isAlphaNum, isDigit;
-import std.traits : isSomeString;
import std.uni : isAlpha, isNumber;
import tanya.memory;
@@ -151,9 +150,10 @@ struct URL
goto ParsePath;
}
}
- else // certain schemas like mailto: and zlib: may not have any / after them
+ else
{
-
+ // Schemas like mailto: and zlib: may not have any slash after
+ // them.
if (!parsePort(value[pos .. $]))
{
this.scheme = value[0 .. pos];
@@ -384,7 +384,7 @@ struct URL
assert(u.fragment == "fragment");
}
-private unittest
+private @nogc unittest
{
auto u = URL("127.0.0.1");
assert(u.path == "127.0.0.1");
@@ -540,17 +540,11 @@ private @nogc unittest
*
* Params:
* T = "scheme", "host", "port", "user", "pass", "path", "query",
- * "fragment" or $(D_KEYWORD null) for a struct with all components.
+ * "fragment".
* source = The string containing the URL.
*
* Returns: Requested URL component.
*/
-URL parseURL(const char[] source) @nogc
-{
- return URL(source);
-}
-
-/// Ditto.
auto parseURL(string T)(const char[] source)
if (T == "scheme"
|| T == "host"
@@ -565,6 +559,12 @@ if (T == "scheme"
return mixin("ret." ~ T);
}
+/// Ditto.
+URL parseURL(const char[] source) @nogc
+{
+ return URL(source);
+}
+
///
@nogc unittest
{
diff --git a/source/tanya/network/inet.d b/source/tanya/network/inet.d
deleted file mode 100644
index 964f58b..0000000
--- a/source/tanya/network/inet.d
+++ /dev/null
@@ -1,19 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Internet utilities.
- *
- * $(RED Deprecated. Use $(D_PSYMBOL tanya.net.inet) instead.
- * This module will be removed in 0.8.0.)
- *
- * Copyright: Eugene Wissner 2017.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- */
-deprecated("Use tanya.net.inet instead")
-module tanya.network.inet;
-
-public import tanya.net.inet;
diff --git a/source/tanya/network/package.d b/source/tanya/network/package.d
index 14a6752..c81604f 100644
--- a/source/tanya/network/package.d
+++ b/source/tanya/network/package.d
@@ -12,6 +12,4 @@
*/
module tanya.network;
-public import tanya.network.inet;
public import tanya.network.socket;
-public import tanya.network.url;
diff --git a/source/tanya/network/url.d b/source/tanya/network/url.d
deleted file mode 100644
index cd78eea..0000000
--- a/source/tanya/network/url.d
+++ /dev/null
@@ -1,1192 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * URL parser.
- *
- * Copyright: Eugene Wissner 2016-2017.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- */
-deprecated("Use tanya.net.uri instead")
-module tanya.network.url;
-
-import std.ascii : isAlphaNum, isDigit;
-import std.traits : isSomeString;
-import std.uni : isAlpha, isNumber;
-import std.uri;
-import tanya.memory;
-
-version (unittest) private
-{
- import std.typecons;
- static Tuple!(string, string[string], ushort)[] URLTests;
-}
-
-static this()
-{
- version (unittest)
- {
- URLTests = [
- tuple(`127.0.0.1`, [
- "path": "127.0.0.1",
- ], ushort(0)),
-
- tuple(`http://127.0.0.1`, [
- "scheme": "http",
- "host": "127.0.0.1",
- ], ushort(0)),
-
- tuple(`http://127.0.0.1/`, [
- "scheme": "http",
- "host": "127.0.0.1",
- "path": "/",
- ], ushort(0)),
-
- tuple(`127.0.0.1/`, [
- "path": "127.0.0.1/",
- ], ushort(0)),
-
- tuple(`127.0.0.1:60000/`, [
- "host": "127.0.0.1",
- "path": "/",
- ], ushort(60000)),
-
- tuple(`example.org`, [
- "path": "example.org",
- ], ushort(0)),
-
- tuple(`example.org/`, [
- "path": "example.org/",
- ], ushort(0)),
-
- tuple(`http://example.org`, [
- "scheme": "http",
- "host": "example.org",
- ], ushort(0)),
-
- tuple(`http://example.org/`, [
- "scheme": "http",
- "host": "example.org",
- "path": "/",
- ], ushort(0)),
-
- tuple(`www.example.org`, [
- "path": "www.example.org",
- ], ushort(0)),
-
- tuple(`www.example.org/`, [
- "path": "www.example.org/",
- ], ushort(0)),
-
- tuple(`http://www.example.org`, [
- "scheme": "http",
- "host": "www.example.org",
- ], ushort(0)),
-
- tuple(`http://www.example.org/`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- ], ushort(0)),
-
- tuple(`www.example.org:2`, [
- "host": "www.example.org",
- ], ushort(2)),
-
- tuple(`http://www.example.org:80`, [
- "scheme": "http",
- "host": "www.example.org",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- ], ushort(80)),
-
- tuple(`http://www.example.org/index.html`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- ], ushort(0)),
-
- tuple(`www.example.org/?`, [
- "path": "www.example.org/",
- "query": "",
- ], ushort(0)),
-
- tuple(`www.example.org:80/?`, [
- "host": "www.example.org",
- "path": "/",
- "query": "",
- ], ushort(80)),
-
- tuple(`http://www.example.org/?`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- "query": "",
- ], ushort(0)),
-
- tuple(`http://www.example.org:80/?`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- "query": "",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/index.html`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/foo/bar/index.html`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/foo/bar/index.html",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/this/is/a/very/deep/directory/structure/and/file.png`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/this/is/a/very/deep/directory/structure/and/file.png",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/deep/directory/structure/and/file.png?lots=1&of=2&parameters=3&too=4`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/deep/directory/structure/and/file.png",
- "query": "lots=1&of=2&parameters=3&too=4",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/this/is/a/very/deep/directory/structure/and/`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/this/is/a/very/deep/directory/structure/and/",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/this/is/a/very/deep/directory/structure/and/file.php`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/this/is/a/very/deep/directory/structure/and/file.php",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/this/../a/../deep/directory`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/this/../a/../deep/directory",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/this/../a/../deep/directory/`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/this/../a/../deep/directory/",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/this/is/a/very/deep/directory/../image.png`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/this/is/a/very/deep/directory/../image.png",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/index.html`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/index.html?`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- "query": "",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/#foo`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- "fragment": "foo",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/?#`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- "query": "",
- "fragment": "",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/?test=1`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- "query": "test=1",
- ], ushort(80)),
-
- tuple(`http://www.example.org/?test=1&`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- "query": "test=1&",
- ], ushort(0)),
-
- tuple(`http://www.example.org:80/?&`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/",
- "query": "&",
- ], ushort(80)),
-
- tuple(`http://www.example.org:80/index.html?test=1&`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- "query": "test=1&",
- ], ushort(80)),
-
- tuple(`http://www.example.org/index.html?&`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- "query": "&",
- ], ushort(0)),
-
- tuple(`http://www.example.org:80/index.html?foo&`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- "query": "foo&",
- ], ushort(80)),
-
- tuple(`http://www.example.org/index.html?&foo`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- "query": "&foo",
- ], ushort(0)),
-
- tuple(`http://www.example.org:80/index.html?test=1&test2=char`, [
- "scheme": "http",
- "host": "www.example.org",
- "path": "/index.html",
- "query": "test=1&test2=char",
- ], ushort(80)),
-
- tuple(`www.example.org:80/index.html?test=1&test2=char#some_ref123`, [
- "host": "www.example.org",
- "path": "/index.html",
- "query": "test=1&test2=char",
- "fragment": "some_ref123",
- ], ushort(80)),
-
- tuple(`http://secret@www.example.org:80/index.html?test=1&test2=char#some_ref123`, [
- "scheme": "http",
- "host": "www.example.org",
- "user": "secret",
- "path": "/index.html",
- "query": "test=1&test2=char",
- "fragment": "some_ref123",
- ], ushort(80)),
-
- tuple(`http://secret:@www.example.org/index.html?test=1&test2=char#some_ref123`, [
- "scheme": "http",
- "host": "www.example.org",
- "user": "secret",
- "pass": "",
- "path": "/index.html",
- "query": "test=1&test2=char",
- "fragment": "some_ref123",
- ], ushort(0)),
-
- tuple(`http://:hideout@www.example.org:80/index.html?test=1&test2=char#some_ref123`, [
- "scheme": "http",
- "host": "www.example.org",
- "user": "",
- "pass": "hideout",
- "path": "/index.html",
- "query": "test=1&test2=char",
- "fragment": "some_ref123",
- ], ushort(80)),
-
- tuple(`http://secret:hideout@www.example.org/index.html?test=1&test2=char#some_ref123`, [
- "scheme": "http",
- "host": "www.example.org",
- "user": "secret",
- "pass": "hideout",
- "path": "/index.html",
- "query": "test=1&test2=char",
- "fragment": "some_ref123",
- ], ushort(0)),
-
- tuple(`http://secret:hid:out@www.example.org:80/index.html?test=1&test2=int#some_ref123`, [
- "scheme": "http",
- "host": "www.example.org",
- "user": "secret",
- "pass": "hid:out",
- "path": "/index.html",
- "query": "test=1&test2=int",
- "fragment": "some_ref123",
- ], ushort(80)),
-
- tuple(`nntp://news.example.org`, [
- "scheme": "nntp",
- "host": "news.example.org",
- ], ushort(0)),
-
- tuple(`ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz`, [
- "scheme": "ftp",
- "host": "ftp.gnu.org",
- "path": "/gnu/glic/glibc.tar.gz",
- ], ushort(0)),
-
- tuple(`zlib:http://foo@bar`, [
- "scheme": "zlib",
- "path": "http://foo@bar",
- ], ushort(0)),
-
- tuple(`zlib:filename.txt`, [
- "scheme": "zlib",
- "path": "filename.txt",
- ], ushort(0)),
-
- tuple(`zlib:/path/to/my/file/file.txt`, [
- "scheme": "zlib",
- "path": "/path/to/my/file/file.txt",
- ], ushort(0)),
-
- tuple(`foo://foo@bar`, [
- "scheme": "foo",
- "host": "bar",
- "user": "foo",
- ], ushort(0)),
-
- tuple(`mailto:me@mydomain.com`, [
- "scheme": "mailto",
- "path": "me@mydomain.com",
- ], ushort(0)),
-
- tuple(`/foo.php?a=b&c=d`, [
- "path": "/foo.php",
- "query": "a=b&c=d",
- ], ushort(0)),
-
- tuple(`foo.php?a=b&c=d`, [
- "path": "foo.php",
- "query": "a=b&c=d",
- ], ushort(0)),
-
- tuple(`http://user:passwd@www.example.com:8080?bar=1&boom=0`, [
- "scheme": "http",
- "host": "www.example.com",
- "user": "user",
- "pass": "passwd",
- "query": "bar=1&boom=0",
- ], ushort(8080)),
-
- tuple(`file:///path/to/file`, [
- "scheme": "file",
- "path": "/path/to/file",
- ], ushort(0)),
-
- tuple(`file://path/to/file`, [
- "scheme": "file",
- "host": "path",
- "path": "/to/file",
- ], ushort(0)),
-
- tuple(`file:/path/to/file`, [
- "scheme": "file",
- "path": "/path/to/file",
- ], ushort(0)),
-
- tuple(`http://1.2.3.4:/abc.asp?a=1&b=2`, [
- "scheme": "http",
- "host": "1.2.3.4",
- "path": "/abc.asp",
- "query": "a=1&b=2",
- ], ushort(0)),
-
- tuple(`http://foo.com#bar`, [
- "scheme": "http",
- "host": "foo.com",
- "fragment": "bar",
- ], ushort(0)),
-
- tuple(`scheme:`, [
- "scheme": "scheme",
- ], ushort(0)),
-
- tuple(`foo+bar://baz@bang/bla`, [
- "scheme": "foo+bar",
- "host": "bang",
- "user": "baz",
- "path": "/bla",
- ], ushort(0)),
-
- tuple(`gg:9130731`, [
- "scheme": "gg",
- "path": "9130731",
- ], ushort(0)),
-
- tuple(`http://10.10.10.10/:80`, [
- "scheme": "http",
- "host": "10.10.10.10",
- "path": "/:80",
- ], ushort(0)),
-
- tuple(`http://x:?`, [
- "scheme": "http",
- "host": "x",
- "query": "",
- ], ushort(0)),
-
- tuple(`x:blah.com`, [
- "scheme": "x",
- "path": "blah.com",
- ], ushort(0)),
-
- tuple(`x:/blah.com`, [
- "scheme": "x",
- "path": "/blah.com",
- ], ushort(0)),
-
- tuple(`http://::?`, [
- "scheme": "http",
- "host": ":",
- "query": "",
- ], ushort(0)),
-
- tuple(`http://::#`, [
- "scheme": "http",
- "host": ":",
- "fragment": "",
- ], ushort(0)),
-
- tuple(`http://?:/`, [
- "scheme": "http",
- "host": "?",
- "path": "/",
- ], ushort(0)),
-
- tuple(`http://@?:/`, [
- "scheme": "http",
- "host": "?",
- "user": "",
- "path": "/",
- ], ushort(0)),
-
- tuple(`file:///:`, [
- "scheme": "file",
- "path": "/:",
- ], ushort(0)),
-
- tuple(`file:///a:/`, [
- "scheme": "file",
- "path": "a:/",
- ], ushort(0)),
-
- tuple(`file:///ab:/`, [
- "scheme": "file",
- "path": "/ab:/",
- ], ushort(0)),
-
- tuple(`file:///a:/`, [
- "scheme": "file",
- "path": "a:/",
- ], ushort(0)),
-
- tuple(`file:///@:/`, [
- "scheme": "file",
- "path": "@:/",
- ], ushort(0)),
-
- tuple(`file:///:80/`, [
- "scheme": "file",
- "path": "/:80/",
- ], ushort(0)),
-
- tuple(`[]`, [
- "path": "[]",
- ], ushort(0)),
-
- tuple(`http://[x:80]/`, [
- "scheme": "http",
- "host": "[x:80]",
- "path": "/",
- ], ushort(0)),
-
- tuple(``, [
- "path": "",
- ], ushort(0)),
-
- tuple(`/`, [
- "path": "/",
- ], ushort(0)),
-
- tuple(`/rest/Users?filter={"id":"789"}`, [
- "path": "/rest/Users",
- "query": `filter={"id":"789"}`,
- ], ushort(0)),
-
- tuple(`//example.org`, [
- "host": "example.org",
- ], ushort(0)),
-
- tuple(`/standard/?fq=B:20001`, [
- "path": "/standard/",
- "query": "fq=B:20001",
- ], ushort(0)),
-
- tuple(`/standard/?fq=B:200013`, [
- "path": "/standard/",
- "query": "fq=B:200013",
- ], ushort(0)),
-
- tuple(`/standard/?fq=home:012345`, [
- "path": "/standard/",
- "query": "fq=home:012345",
- ], ushort(0)),
-
- tuple(`/standard/?fq=home:01234`, [
- "path": "/standard/",
- "query": "fq=home:01234",
- ], ushort(0)),
-
- tuple(`http://user:pass@host`, [
- "scheme": "http",
- "host": "host",
- "user": "user",
- "pass": "pass",
- ], ushort(0)),
-
- tuple(`//user:pass@host`, [
- "host": "host",
- "user": "user",
- "pass": "pass",
- ], ushort(0)),
-
- tuple(`//user@host`, [
- "host": "host",
- "user": "user",
- ], ushort(0)),
-
- tuple(`//example.org:99/hey?a=b#c=d`, [
- "host": "example.org",
- "path": "/hey",
- "query": "a=b",
- "fragment": "c=d",
- ], ushort(99)),
-
- tuple(`//example.org/hey?a=b#c=d`, [
- "host": "example.org",
- "path": "/hey",
- "query": "a=b",
- "fragment": "c=d",
- ], ushort(0)),
-
- tuple(`http://example.org/some/path.cgi?t=1#fragment?data`, [
- "scheme": "http",
- "host": "example.org",
- "path": "/some/path.cgi",
- "query": "t=1",
- "fragment": "fragment?data",
- ], ushort(0)),
-
- tuple(`http://example.org/some/path.cgi#fragment?data`, [
- "scheme": "http",
- "host": "example.org",
- "path": "/some/path.cgi",
- "fragment": "fragment?data",
- ], ushort(0)),
-
- tuple(`x://::abc/?`, string[string].init, ushort(0)),
- tuple(`http:///blah.com`, string[string].init, ushort(0)),
- tuple(`http://:80`, string[string].init, ushort(0)),
- tuple(`http://user@:80`, string[string].init, ushort(0)),
- tuple(`http://user:pass@:80`, string[string].init, ushort(0)),
- tuple(`http://:`, string[string].init, ushort(0)),
- tuple(`http://@/`, string[string].init, ushort(0)),
- tuple(`http://@:/`, string[string].init, ushort(0)),
- tuple(`http://:/`, string[string].init, ushort(0)),
- tuple(`http://?`, string[string].init, ushort(0)),
- tuple(`http://#`, string[string].init, ushort(0)),
- tuple(`http://:?`, string[string].init, ushort(0)),
- tuple(`http://blah.com:123456`, string[string].init, ushort(0)),
- tuple(`http://blah.com:70000`, string[string].init, ushort(0)),
- tuple(`http://blah.com:abcdef`, string[string].init, ushort(0)),
- tuple(`http://secret@hideout@www.example.org:80/index.html?test=1&test2=char#some_ref123`,
- string[string].init,
- ushort(0)),
- tuple(`http://user:@pass@host/path?argument?value#etc`, string[string].init, ushort(0)),
- tuple(`http://foo.com\@bar.com`, string[string].init, ushort(0)),
- tuple(`http://email@address.com:pass@example.org`, string[string].init, ushort(0)),
- tuple(`:`, string[string].init, ushort(0)),
- ];
- }
-}
-
-/**
- * A Unique Resource Locator.
- */
-struct URL
-{
- /** The URL scheme. */
- const(char)[] scheme;
-
- /** The username. */
- const(char)[] user;
-
- /** The password. */
- const(char)[] pass;
-
- /** The hostname. */
- const(char)[] host;
-
- /** The port number. */
- ushort port;
-
- /** The path. */
- const(char)[] path;
-
- /** The query string. */
- const(char)[] query;
-
- /** The anchor. */
- const(char)[] fragment;
-
- /**
- * Attempts to parse an URL from a string.
- * Output string data (scheme, user, etc.) are just slices of input string (e.g., no memory allocation and copying).
- *
- * Params:
- * source = The string containing the URL.
- *
- * Throws: $(D_PSYMBOL URIException) if the URL is malformed.
- */
- this(in char[] source)
- {
- auto value = source;
- ptrdiff_t pos = -1, endPos = value.length, start;
-
- foreach (i, ref c; source)
- {
- if (pos == -1 && c == ':')
- {
- pos = i;
- }
- if (endPos == value.length && (c == '?' || c == '#'))
- {
- endPos = i;
- }
- }
-
- // Check if the colon is a part of the scheme or the port and parse
- // the appropriate part
- if (value.length > 1 && value[0] == '/' && value[1] == '/')
- {
- // Relative scheme
- start = 2;
- }
- else if (pos > 0)
- {
- // Validate scheme
- // [ toLower(alpha) | digit | "+" | "-" | "." ]
- foreach (ref c; value[0..pos])
- {
- if (!c.isAlphaNum && c != '+' && c != '-' && c != '.')
- {
- if (endPos > pos)
- {
- if (!parsePort(value[pos..$]))
- {
- throw defaultAllocator.make!URIException("Failed to parse port");
- }
- }
- goto ParsePath;
- }
- }
-
- if (value.length == pos + 1) // only scheme is available
- {
- scheme = value[0 .. $ - 1];
- return;
- }
- else if (value.length > pos + 1 && value[pos + 1] == '/')
- {
- scheme = value[0..pos];
-
- if (value.length > pos + 2 && value[pos + 2] == '/')
- {
- start = pos + 3;
- if (scheme == "file" && value.length > start && value[start] == '/')
- {
- // Windows drive letters
- if (value.length - start > 2 && value[start + 2] == ':')
- {
- ++start;
- }
- goto ParsePath;
- }
- }
- else
- {
- start = pos + 1;
- goto ParsePath;
- }
- }
- else // certain schemas like mailto: and zlib: may not have any / after them
- {
-
- if (!parsePort(value[pos..$]))
- {
- scheme = value[0..pos];
- start = pos + 1;
- goto ParsePath;
- }
- }
- }
- else if (pos == 0 && parsePort(value[pos..$]))
- {
- // An URL shouldn't begin with a port number
- throw defaultAllocator.make!URIException("URL begins with port");
- }
- else
- {
- goto ParsePath;
- }
-
- // Parse host
- pos = -1;
- for (ptrdiff_t i = start; i < value.length; ++i)
- {
- if (value[i] == '@')
- {
- pos = i;
- }
- else if (value[i] == '/')
- {
- endPos = i;
- break;
- }
- }
-
- // Check for login and password
- if (pos != -1)
- {
- // *( unreserved / pct-encoded / sub-delims / ":" )
- foreach (i, c; value[start..pos])
- {
- if (c == ':')
- {
- if (user is null)
- {
- user = value[start .. start + i];
- pass = value[start + i + 1 .. pos];
- }
- }
- else if (!c.isAlpha &&
- !c.isNumber &&
- c != '!' &&
- c != ';' &&
- c != '=' &&
- c != '_' &&
- c != '~' &&
- !(c >= '$' && c <= '.'))
- {
- if (scheme !is null)
- {
- scheme = null;
- }
- if (user !is null)
- {
- user = null;
- }
- if (pass !is null)
- {
- pass = null;
- }
- throw make!URIException(defaultAllocator,
- "Restricted characters in user information");
- }
- }
- if (user is null)
- {
- user = value[start..pos];
- }
-
- start = ++pos;
- }
-
- pos = endPos;
- if (endPos <= 1 || value[start] != '[' || value[endPos - 1] != ']')
- {
- // Short circuit portscan
- // IPv6 embedded address
- for (ptrdiff_t i = endPos - 1; i >= start; --i)
- {
- if (value[i] == ':')
- {
- pos = i;
- if (port == 0 && !parsePort(value[i..endPos]))
- {
- if (scheme !is null)
- {
- scheme = null;
- }
- if (user !is null)
- {
- user = null;
- }
- if (pass !is null)
- {
- pass = null;
- }
- throw defaultAllocator.make!URIException("Invalid port");
- }
- break;
- }
- }
- }
-
- // Check if we have a valid host, if we don't reject the string as url
- if (pos <= start)
- {
- if (scheme !is null)
- {
- scheme = null;
- }
- if (user !is null)
- {
- user = null;
- }
- if (pass !is null)
- {
- pass = null;
- }
- throw defaultAllocator.make!URIException("Invalid host");
- }
-
- host = value[start..pos];
-
- if (endPos == value.length)
- {
- return;
- }
-
- start = endPos;
-
- ParsePath:
- endPos = value.length;
- pos = -1;
- foreach (i, ref c; value[start..$])
- {
- if (c == '?' && pos == -1)
- {
- pos = start + i;
- }
- else if (c == '#')
- {
- endPos = start + i;
- break;
- }
- }
- if (pos == -1)
- {
- pos = endPos;
- }
-
- if (pos > start)
- {
- path = value[start..pos];
- }
- if (endPos >= ++pos)
- {
- query = value[pos..endPos];
- }
- if (++endPos <= value.length)
- {
- fragment = value[endPos..$];
- }
- }
-
- ~this()
- {
- if (scheme !is null)
- {
- scheme = null;
- }
- if (user !is null)
- {
- user = null;
- }
- if (pass !is null)
- {
- pass = null;
- }
- if (host !is null)
- {
- host = null;
- }
- if (path !is null)
- {
- path = null;
- }
- if (query !is null)
- {
- query = null;
- }
- if (fragment !is null)
- {
- fragment = null;
- }
- }
-
- /**
- * Attempts to parse and set the port.
- *
- * Params:
- * port = String beginning with a colon followed by the port number and
- * an optional path (query string and/or fragment), like:
- * `:12345/some_path` or `:12345`.
- *
- * Returns: Whether the port could be found.
- */
- private bool parsePort(in char[] port) pure nothrow @safe @nogc
- {
- ptrdiff_t i = 1;
- float lPort = 0;
-
- for (; i < port.length && port[i].isDigit() && i <= 6; ++i)
- {
- lPort += (port[i] - '0') / cast(float)(10 ^^ (i - 1));
- }
- if (i == 1 && (i == port.length || port[i] == '/'))
- {
- return true;
- }
- else if (i == port.length || port[i] == '/')
- {
- lPort *= 10 ^^ (i - 2);
- if (lPort > ushort.max)
- {
- return false;
- }
- this.port = cast(ushort)lPort;
- return true;
- }
- return false;
- }
-}
-
-///
-unittest
-{
- auto u = URL("example.org");
- assert(u.path == "example.org");
-
- u = URL("relative/path");
- assert(u.path == "relative/path");
-
- // Host and scheme
- u = URL("https://example.org");
- assert(u.scheme == "https");
- assert(u.host == "example.org");
- assert(u.path is null);
- assert(u.port == 0);
- assert(u.fragment is null);
-
- // With user and port and path
- u = URL("https://hilary:putnam@example.org:443/foo/bar");
- assert(u.scheme == "https");
- assert(u.host == "example.org");
- assert(u.path == "/foo/bar");
- assert(u.port == 443);
- assert(u.user == "hilary");
- assert(u.pass == "putnam");
- assert(u.fragment is null);
-
- // With query string
- u = URL("https://example.org/?login=true");
- assert(u.scheme == "https");
- assert(u.host == "example.org");
- assert(u.path == "/");
- assert(u.query == "login=true");
- assert(u.fragment is null);
-
- // With query string and fragment
- u = URL("https://example.org/?login=false#label");
- assert(u.scheme == "https");
- assert(u.host == "example.org");
- assert(u.path == "/");
- assert(u.query == "login=false");
- assert(u.fragment == "label");
-
- u = URL("redis://root:password@localhost:2201/path?query=value#fragment");
- assert(u.scheme == "redis");
- assert(u.user == "root");
- assert(u.pass == "password");
- assert(u.host == "localhost");
- assert(u.port == 2201);
- assert(u.path == "/path");
- assert(u.query == "query=value");
- assert(u.fragment == "fragment");
-}
-
-private unittest
-{
- foreach(t; URLTests)
- {
- if (t[1].length == 0 && t[2] == 0)
- {
- try
- {
- URL(t[0]);
- assert(0);
- }
- catch (URIException e)
- {
- assert(1);
- }
- }
- else
- {
- auto u = URL(t[0]);
- assert("scheme" in t[1] ? u.scheme == t[1]["scheme"] : u.scheme is null,
- t[0]);
- assert("user" in t[1] ? u.user == t[1]["user"] : u.user is null, t[0]);
- assert("pass" in t[1] ? u.pass == t[1]["pass"] : u.pass is null, t[0]);
- assert("host" in t[1] ? u.host == t[1]["host"] : u.host is null, t[0]);
- assert(u.port == t[2], t[0]);
- assert("path" in t[1] ? u.path == t[1]["path"] : u.path is null, t[0]);
- assert("query" in t[1] ? u.query == t[1]["query"] : u.query is null, t[0]);
- if ("fragment" in t[1])
- {
- assert(u.fragment == t[1]["fragment"], t[0]);
- }
- else
- {
- assert(u.fragment is null, t[0]);
- }
- }
- }
-}
-
-/**
- * Contains possible URL components that can be returned from
- * $(D_PSYMBOL parseURL).
- */
-enum Component : string
-{
- scheme = "scheme",
- host = "host",
- port = "port",
- user = "user",
- pass = "pass",
- path = "path",
- query = "query",
- fragment = "fragment",
-}
-
-/**
- * Attempts to parse an URL from a string.
- *
- * Params:
- * T = $(D_SYMBOL Component) member or $(D_KEYWORD null) for a
- * struct with all components.
- * source = The string containing the URL.
- *
- * Returns: Requested URL components.
- */
-URL parseURL(typeof(null) T)(in char[] source)
-{
- return URL(source);
-}
-
-/// Ditto.
-const(char)[] parseURL(immutable(char)[] T)(in char[] source)
- if (T == "scheme"
- || T == "host"
- || T == "user"
- || T == "pass"
- || T == "path"
- || T == "query"
- || T == "fragment")
-{
- auto ret = URL(source);
- return mixin("ret." ~ T);
-}
-
-/// Ditto.
-ushort parseURL(immutable(char)[] T)(in char[] source)
- if (T == "port")
-{
- auto ret = URL(source);
- return ret.port;
-}
-
-unittest
-{
- assert(parseURL!(Component.port)("http://example.org:5326") == 5326);
-}
-
-private unittest
-{
- foreach(t; URLTests)
- {
- if (t[1].length == 0 && t[2] == 0)
- {
- try
- {
- parseURL!(Component.port)(t[0]);
- parseURL!(Component.user)(t[0]);
- parseURL!(Component.pass)(t[0]);
- parseURL!(Component.host)(t[0]);
- parseURL!(Component.path)(t[0]);
- parseURL!(Component.query)(t[0]);
- parseURL!(Component.fragment)(t[0]);
- assert(0);
- }
- catch (URIException e)
- {
- assert(1);
- }
- }
- else
- {
- ushort port = parseURL!(Component.port)(t[0]);
- auto component = parseURL!(Component.scheme)(t[0]);
- assert("scheme" in t[1] ? component == t[1]["scheme"] : component is null,
- t[0]);
- component = parseURL!(Component.user)(t[0]);
- assert("user" in t[1] ? component == t[1]["user"] : component is null,
- t[0]);
- component = parseURL!(Component.pass)(t[0]);
- assert("pass" in t[1] ? component == t[1]["pass"] : component is null,
- t[0]);
- component = parseURL!(Component.host)(t[0]);
- assert("host" in t[1] ? component == t[1]["host"] : component is null,
- t[0]);
- assert(port == t[2], t[0]);
- component = parseURL!(Component.path)(t[0]);
- assert("path" in t[1] ? component == t[1]["path"] : component is null,
- t[0]);
- component = parseURL!(Component.query)(t[0]);
- assert("query" in t[1] ? component == t[1]["query"] : component is null,
- t[0]);
- component = parseURL!(Component.fragment)(t[0]);
- if ("fragment" in t[1])
- {
- assert(component == t[1]["fragment"], t[0]);
- }
- else
- {
- assert(component is null, t[0]);
- }
- }
- }
-}