1 module requests.request;
2 import requests.http;
3 import requests.ftp;
4 import requests.streams;
5 import requests.base;
6 import requests.uri;
7 
8 import std.datetime;
9 import std.conv;
10 import std.experimental.logger;
11 import std.format;
12 import requests.utils;
13 
14 
15 /**
16    This is simplest interface to both http and ftp protocols.
17    Request has methods get, post and exec which routed to proper concrete handler (http or ftp, etc).
18    To enable some protocol-specific featutes you have to use protocol interface directly (see docs for HTTPRequest or FTPRequest)
19 */
20 public struct Request {
21     private {
22         URI         _uri;
23         HTTPRequest _http;  // route all http/https requests here
24         FTPRequest  _ftp;   // route all ftp requests here
25         string      _method;
26     }
27     /// Set timeout on IO operation.
28     /// $(B v) - timeout value
29     /// 
30     @property void timeout(Duration v) pure @nogc nothrow {
31         _http.timeout = v;
32         _ftp.timeout = v;
33     }
34     /// Set http keepAlive value
35     /// $(B v) - use keepalive requests - $(B true), or not - $(B false)
36     @property void keepAlive(bool v) pure @nogc nothrow {
37         _http.keepAlive = v;
38     }
39     /// Set limit on HTTP redirects
40     /// $(B v) - limit on redirect depth
41     @property void maxRedirects(uint v) pure @nogc nothrow {
42         _http.maxRedirects = v;
43     }
44     /// Set maximum content lenth both for http and ftp requests
45     /// $(B v) - maximum content length in bytes. When limit reached - throw RequestException
46     @property void maxContentLength(size_t v) pure @nogc nothrow {
47         _http.maxContentLength = v;
48         _ftp.maxContentLength = v;
49     }
50     /// Set maximum length for HTTP headers
51     /// $(B v) - maximum length of the HTTP response. When limit reached - throw RequestException
52     @property void maxHeadersLength(size_t v) pure @nogc nothrow {
53         _http.maxHeadersLength = v;
54     }
55     /// Set IO buffer size for http and ftp requests
56     /// $(B v) - buffer size in bytes.
57     @property void bufferSize(size_t v) {
58         _http.bufferSize = v;
59         _ftp.bufferSize = v;
60     }
61     /// Set verbosity for HTTP or FTP requests.
62     /// $(B v) - verbosity level (0 - no output, 1 - headers to stdout, 2 - headers and body progress to stdout). default = 0.
63     @property void verbosity(uint v) {
64         _http.verbosity = v;
65         _ftp.verbosity = v;
66     }
67     /// Set authenticator for http requests.
68     /// $(B v) - Auth instance.
69     @property void authenticator(Auth v) {
70         _http.authenticator = v;
71         _ftp.authenticator = v;
72     }
73     /// set proxy property.
74     /// $(B v) - full url to proxy.
75     @property void proxy(string v) {
76         _http.proxy = v;
77         _ftp.proxy = v;
78     }
79     /// Set Cookie for http requests.
80     /// $(B v) - array of cookie.
81     @property void cookie(Cookie[] v) pure @nogc nothrow {
82         _http.cookie = v;
83     }
84     /// Get Cookie for http requests.
85     /// $(B v) - array of cookie.
86     @property Cookie[] cookie()  pure @nogc nothrow {
87         return _http.cookie;
88     }
89     ///
90     /// set "streaming" property
91     /// Params:
92     /// v = value to set (true - use streaming)
93     /// 
94     @property void useStreaming(bool v) pure @nogc nothrow {
95         _http.useStreaming = v;
96         _ftp.useStreaming = v;
97     }
98     ///
99     /// get length og actually received content.
100     /// this value increase over time, while we receive data
101     /// 
102     @property long contentReceived() pure @nogc nothrow {
103         final switch ( _uri.scheme ) {
104             case "http", "https":
105                 return _http.contentReceived;
106             case "ftp":
107                 return _ftp.contentReceived;
108         }
109     }
110     /// get contentLength of the responce
111     @property long contentLength() pure @nogc nothrow {
112         final switch ( _uri.scheme ) {
113             case "http", "https":
114                 return _http.contentLength;
115             case "ftp":
116                 return _ftp.contentLength;
117         }
118     }
119     @property void sslSetVerifyPeer(bool v) {
120         _http.sslSetVerifyPeer(v);
121     }
122     @property void sslSetKeyFile(string path, SSLOptions.filetype type = SSLOptions.filetype.pem) pure @safe nothrow @nogc {
123         _http.sslSetKeyFile(path, type);
124     }
125     @property void sslSetCertFile(string path, SSLOptions.filetype type = SSLOptions.filetype.pem) pure @safe nothrow @nogc {
126         _http.sslSetCertFile(path, type);
127     }
128     @property void sslSetCaCert(string path) pure @safe nothrow @nogc {
129         _http.sslSetCaCert(path);
130     }
131     @property auto sslOptions() {
132         return _http.sslOptions();
133     }
134     @property auto bind(string v) {
135         _http.bind(v);
136         _ftp.bind(v);
137     }
138     /// Add headers to request
139     /// Params:
140     /// headers = headers to send.
141     void addHeaders(in string[string] headers) {
142         _http.addHeaders(headers);
143     }
144     void clearHeaders() {
145         _http.clearHeaders();
146     }
147     /// Execute GET for http and retrieve file for FTP.
148     /// You have to provide at least $(B uri). All other arguments should conform to HTTPRequest.get or FTPRequest.get depending on the URI scheme.
149     /// When arguments do not conform scheme (for example you try to call get("ftp://somehost.net/pub/README", {"a":"b"}) which doesn't make sense)
150     /// you will receive Exception("Operation not supported for ftp")
151     ///
152     Response get(A...)(string uri, A args) {
153         if ( uri ) {
154             _uri = URI(uri);
155         }
156         _method = "GET";
157         final switch ( _uri.scheme ) {
158             case "http", "https":
159                 _http.uri = _uri;
160                 static if (__traits(compiles, _http.get(null, args))) {
161                     return _http.get(null, args);
162                 } else {
163                     throw new Exception("Operation not supported for http");
164                 }
165             case "ftp":
166                 static if (args.length == 0) {
167                     return _ftp.get(uri);
168                 } else {
169                     throw new Exception("Operation not supported for ftp");
170                 }
171         }
172     }
173     /// Execute POST for http and STOR file for FTP.
174     /// You have to provide  $(B uri) and data. Data should conform to HTTPRequest.post or FTPRequest.post depending on the URI scheme.
175     /// When arguments do not conform scheme you will receive Exception("Operation not supported for ftp")
176     ///
177     Response post(A...)(string uri, A args) {
178         if ( uri ) {
179             _uri = URI(uri);
180         }
181         _method = "POST";
182         final switch ( _uri.scheme ) {
183             case "http", "https":
184                 _http.uri = _uri;
185                 static if (__traits(compiles, _http.post(null, args))) {
186                     return _http.post(null, args);
187                 } else {
188                     throw new Exception("Operation not supported for http");
189                 }
190             case "ftp":
191                 static if (__traits(compiles, _ftp.post(uri, args))) {
192                     return _ftp.post(uri, args);
193                 } else {
194                     throw new Exception("Operation not supported for ftp");
195                 }
196         }
197     }
198     Response exec(string method="GET", A...)(string uri, A args) {
199         _method = method;
200         _uri = URI(uri);
201         _http.uri = _uri;
202         return _http.exec!(method)(null, args);
203     }
204 
205     string toString() const {
206         return "Request(%s, %s)".format(_method, _uri.uri());
207     }
208     string format(string fmt) const {
209         final switch(_uri.scheme) {
210             case "http", "https":
211                 return _http.format(fmt);
212             case "ftp":
213                 return _ftp.format(fmt);
214         }
215     }
216 }