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