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 }