1 module requests.utils; 2 3 import std.range; 4 5 __gshared immutable short[string] standard_ports; 6 shared static this() { 7 standard_ports["http"] = 80; 8 standard_ports["https"] = 443; 9 standard_ports["ftp"] = 21; 10 } 11 12 13 string Getter_Setter(T)(string name) { 14 return ` 15 @property final ` ~ T.stringof ~ ` ` ~ name ~ `() pure const @safe @nogc nothrow { 16 return _` ~ name ~ `; 17 } 18 @property final void ` ~ name ~ `(` ~ T.stringof ~ ` s) pure @nogc nothrow { 19 _` ~ name ~ `=s; 20 } 21 `; 22 } 23 24 string Setter(T)(string name) { 25 return ` 26 @property final void ` ~ name ~ `(` ~ T.stringof ~ ` s) pure @nogc nothrow { 27 _` ~ name ~ `=s; 28 } 29 `; 30 } 31 32 string Getter(T)(string name) { 33 return ` 34 @property final ` ~ T.stringof ~ ` ` ~ name ~ `() pure const @safe @nogc nothrow { 35 return _` ~ name ~ `; 36 } 37 `; 38 } 39 40 //auto getter(string name) { 41 // return ` 42 // @property final auto ` ~ name ~ `() const @safe @nogc { 43 // return __` ~ name ~ `; 44 // } 45 // `; 46 //} 47 //auto setter(string name) { 48 // string member = "__" ~ name; 49 // string t = "typeof(this."~member~")"; 50 // return ` 51 // @property final void ` ~ name ~`(` ~ t ~ ` s) pure @nogc nothrow {`~ 52 // member ~`=s; 53 // } 54 // `; 55 //} 56 57 unittest { 58 struct S { 59 private { 60 int _i; 61 string _s; 62 bool _b; 63 } 64 mixin(Getter!int("i")); 65 mixin(Setter!int("i")); 66 mixin(Getter!bool("b")); 67 } 68 S s; 69 assert(s.i == 0); 70 s.i = 1; 71 assert(s.i == 1); 72 assert(s.b == false); 73 } 74 75 template rank(R) { 76 static if ( isInputRange!R ) { 77 enum size_t rank = 1 + rank!(ElementType!R); 78 } else { 79 enum size_t rank = 0; 80 } 81 } 82 unittest { 83 assert(rank!(char) == 0); 84 assert(rank!(string) == 1); 85 assert(rank!(ubyte[][]) == 2); 86 } 87 // test if p1 is sub-path of p2 (used to find Cookie to send) 88 bool pathMatches(string p1, string p2) pure @safe @nogc { 89 import std.algorithm; 90 return p1.startsWith(p2); 91 } 92 93 package unittest { 94 assert("/abc/def".pathMatches("/")); 95 assert("/abc/def".pathMatches("/abc")); 96 assert("/abc/def".pathMatches("/abc/def")); 97 assert(!"/def".pathMatches("/abc")); 98 } 99 100 // test if d1 is subbomain of d2 (used to find Cookie to send) 101 // Host names can be specified either as an IP address or a HDN string. 102 // Sometimes we compare one host name with another. (Such comparisons 103 // SHALL be case-insensitive.) Host A's name domain-matches host B's if 104 // 105 // * their host name strings string-compare equal; or 106 // 107 // * A is a HDN string and has the form NB, where N is a non-empty 108 // name string, B has the form .B', and B' is a HDN string. (So, 109 // x.y.com domain-matches .Y.com but not Y.com.) 110 111 package bool domainMatches(string d1, string d2) pure @safe @nogc { 112 import std.algorithm; 113 return d1==d2 || 114 (d2[0] == '.' && d1.endsWith(d2)); 115 } 116 117 package unittest { 118 assert("x.example.com".domainMatches(".example.com")); 119 assert(!"x.example.com".domainMatches("example.com")); 120 assert("example.com".domainMatches("example.com")); 121 } 122 123 string[] dump(in ubyte[] data) { 124 import std.stdio; 125 import std.range; 126 import std.ascii; 127 import std.format; 128 import std.algorithm; 129 130 string[] res; 131 132 foreach(i,chunk; data.chunks(16).enumerate) { 133 string r; 134 r ~= format("%05X ", i*16); 135 ubyte[] left, right; 136 if ( chunk.length > 8 ) { 137 left = chunk[0..8].dup; 138 right= chunk[8..$].dup; 139 } else { 140 left = chunk.dup; 141 } 142 r ~= format("%-24.24s ", left.map!(c => format("%02X", c)).join(" ")); 143 r ~= format("%-24.24s ", right.map!(c => format("%02X", c)).join(" ")); 144 r ~= format("|%-16s|", chunk.map!(c => isPrintable(c)?cast(char)c:'.')); 145 res ~= r; 146 } 147 return res; 148 }