1 module requests.base; 2 3 import requests.streams; 4 import requests.utils; 5 import requests.uri; 6 7 import std.format; 8 import std.datetime; 9 import core.time; 10 11 public interface Auth { 12 string[string] authHeaders(string domain); 13 string userName(); 14 string password(); 15 } 16 17 public class RequestException: Exception { 18 this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @safe pure nothrow { 19 super(msg, file, line, next); 20 } 21 } 22 23 public struct ReceiveAsRange { 24 bool empty() { 25 return data.length == 0; 26 }; 27 ubyte[] front() { 28 return data; 29 }; 30 void popFront() { 31 if ( read ) { 32 // get new portion 33 data = read(); 34 } else { 35 // we can't read any new data 36 data.length = 0; 37 } 38 }; 39 package { 40 bool activated; 41 ubyte[] data; 42 ubyte[] delegate() read; 43 } 44 } 45 46 public class Response { 47 package { 48 ushort _code; 49 Buffer!ubyte _responseBody; 50 string[string] _responseHeaders; 51 /// Initial URI 52 URI _uri; 53 /// Final URI. Can differ from __URI if request go through redirections. 54 URI _finalURI; 55 ReceiveAsRange _receiveAsRange; 56 SysTime _startedAt, 57 _connectedAt, 58 _requestSentAt, 59 _finishedAt; 60 mixin(Setter!ushort("code")); 61 mixin(Setter!URI("uri")); 62 mixin(Setter!URI("finalURI")); 63 } 64 mixin(Getter!ushort("code")); 65 mixin(Getter!URI("uri")); 66 mixin(Getter!URI("finalURI")); 67 @property auto ref responseBody() @safe nothrow { 68 return _responseBody; 69 } 70 @property auto ref responseHeaders() pure @safe nothrow { 71 return _responseHeaders; 72 } 73 @property auto ref receiveAsRange() pure @safe nothrow { 74 return _receiveAsRange; 75 } 76 override string toString() const { 77 return "Response(%d, %s)".format(_code, _uri.uri()); 78 } 79 string format(string fmt) const { 80 import std.array; 81 auto a = appender!string(); 82 auto f = FormatSpec!char(fmt); 83 while (f.writeUpToNextSpec(a)) { 84 switch (f.spec) { 85 case 'h': 86 // Remote hostname. 87 a.put(_uri.host); 88 break; 89 case 'p': 90 // Remote port. 91 a.put("%d".format(_uri.port)); 92 break; 93 case 'P': 94 // Path. 95 a.put(_uri.path); 96 break; 97 case 'q': 98 // query parameters supplied with url. 99 a.put(_uri.query); 100 break; 101 case 's': 102 a.put("Response(%d, %s)".format(_code, _uri.uri())); 103 break; 104 case 'B': // received bytes 105 a.put("%d".format(_responseBody.length)); 106 break; 107 case 'T': // request total time, ms 108 a.put("%d".format((_finishedAt - _startedAt).total!"msecs")); 109 break; 110 case 'U': 111 a.put(_uri.uri()); 112 break; 113 case 'S': 114 a.put("%d".format(_code)); 115 break; 116 default: 117 throw new FormatException("Unknown Response format specifier: %" ~ f.spec); 118 } 119 } 120 return a.data(); 121 } 122 }