Request

This is simplest interface to both http and ftp protocols. Request has methods get, post and exec which routed to proper concrete handler (http or ftp, etc). To enable some protocol-specific featutes you have to use protocol interface directly (see docs for HTTPRequest or FTPRequest)

Members

Functions

exec
Response exec(A args)
Undocumented in source. Be warned that the author may not have intended to support it.
get
Response get(string uri, A args)

Execute GET for http and retrieve file for FTP. You have to provide at least uri. All other arguments should conform to HTTPRequest.get or FTPRequest.get depending on the URI scheme. 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) you will receive Exception("Operation not supported for ftp")

post
Response post(string uri, A args)

Execute POST for http and STOR file for FTP. You have to provide uri and data. Data should conform to HTTPRequest.post or FTPRequest.post depending on the URI scheme. When arguments do not conform scheme you will receive Exception("Operation not supported for ftp")

Properties

authenticator
Auth authenticator [@property setter]

Set authenticator for http requests. v - Auth instance.

bufferSize
size_t bufferSize [@property setter]

Set IO buffer size for http and ftp requests v - buffer size in bytes.

keepAlive
bool keepAlive [@property setter]

Set http keepAlive value v - use keepalive requests - true, or not - false

maxContentLength
size_t maxContentLength [@property setter]

Set maximum content lenth both for http and ftp requests v - maximum content length in bytes. When limit reached - throw RequestException

maxHeadersLength
size_t maxHeadersLength [@property setter]

Set maximum length for HTTP headers v - maximum length of the HTTP response. When limit reached - throw RequestException

maxRedirects
uint maxRedirects [@property setter]

Set limit on HTTP redirects v - limit on redirect depth

timeout
Duration timeout [@property setter]

Set timeout on IO operation. v - timeout value

verbosity
uint verbosity [@property setter]

Set verbosity for HTTP or FTP requests. v - verbosity level (0 - no output, 1 - headers to stdout, 2 - headers and body progress to stdout). default = 0.

Examples

1 import std.algorithm;
2 import std.range;
3 import std.array;
4 import std.json;
5 import std.stdio;
6 import std.string;
7 import std.exception;
8 
9 globalLogLevel(LogLevel.info);
10 
11 infof("testing Request");
12 Request rq;
13 Response rs;
14 //
15 rs = rq.get("https://httpbin.org/");
16 assert(rs.code==200);
17 assert(rs.responseBody.length > 0);
18 rs = rq.get("http://httpbin.org/get", ["c":" d", "a":"b"]);
19 assert(rs.code == 200);
20 auto json = parseJSON(rs.responseBody.data).object["args"].object;
21 assert(json["c"].str == " d");
22 assert(json["a"].str == "b");
23 
24 globalLogLevel(LogLevel.info);
25 rq = Request();
26 rq.keepAlive = true;
27 // handmade json
28 info("Check POST json");
29 rs = rq.post("http://httpbin.org/post?b=x", `{"a":"☺ ", "c":[1,2,3]}`, "application/json");
30 assert(rs.code==200);
31 json = parseJSON(rs.responseBody.data).object["args"].object;
32 assert(json["b"].str == "x");
33 json = parseJSON(rs.responseBody.data).object["json"].object;
34 assert(json["a"].str == "☺ ");
35 assert(json["c"].array.map!(a=>a.integer).array == [1,2,3]);
36 {
37     import std.file;
38     import std.path;
39     auto tmpd = tempDir();
40     auto tmpfname = tmpd ~ dirSeparator ~ "request_test.txt";
41     auto f = File(tmpfname, "wb");
42     f.rawWrite("abcdefgh\n12345678\n");
43     f.close();
44     // files
45     globalLogLevel(LogLevel.info);
46     info("Check POST files");
47     PostFile[] files = [
48     {fileName: tmpfname, fieldName:"abc", contentType:"application/octet-stream"}, 
49     {fileName: tmpfname}
50     ];
51     rs = rq.post("http://httpbin.org/post", files);
52     assert(rs.code==200);
53     info("Check POST chunked from file.byChunk");
54     f = File(tmpfname, "rb");
55     rs = rq.post("http://httpbin.org/post", f.byChunk(3), "application/octet-stream");
56     assert(rs.code==200);
57     auto data = parseJSON(rs.responseBody.data).object["data"].str;
58     assert(data=="abcdefgh\n12345678\n");
59     f.close();
60 }
61 {
62     // string
63     info("Check POST utf8 string");
64     rs = rq.post("http://httpbin.org/post", "привiт, свiт!", "application/octet-stream");
65     assert(rs.code==200);
66     auto data = parseJSON(rs.responseBody.data).object["data"].str;
67     assert(data=="привiт, свiт!");
68 }
69 // ranges
70 {
71     info("Check POST chunked from lineSplitter");
72     auto s = lineSplitter("one,\ntwo,\nthree.");
73     rs = rq.exec!"POST"("http://httpbin.org/post", s, "application/octet-stream");
74     assert(rs.code==200);
75     auto data = parseJSON(rs.responseBody.toString).object["data"].str;
76     assert(data=="one,two,three.");
77 }
78 {
79     info("Check POST chunked from array");
80     auto s = ["one,", "two,", "three."];
81     rs = rq.post("http://httpbin.org/post", s, "application/octet-stream");
82     assert(rs.code==200);
83     auto data = parseJSON(rs.responseBody.data).object["data"].str;
84     assert(data=="one,two,three.");
85 }
86 {
87     info("Check POST chunked using std.range.chunks()");
88     auto s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
89     rs = rq.post("http://httpbin.org/post", s.representation.chunks(10), "application/octet-stream");
90     assert(rs.code==200);
91     auto data = parseJSON(rs.responseBody.data).object["data"].str;
92     assert(data==s);
93 }
94 // associative array
95 rs = rq.post("http://httpbin.org/post", ["a":"b ", "c":"d"]);
96 assert(rs.code==200);
97 auto form = parseJSON(rs.responseBody.data).object["form"].object;
98 assert(form["a"].str == "b ");
99 assert(form["c"].str == "d");
100 info("Check HEAD");
101 rs = rq.exec!"HEAD"("http://httpbin.org/");
102 assert(rs.code==200);
103 info("Check DELETE");
104 rs = rq.exec!"DELETE"("http://httpbin.org/delete");
105 assert(rs.code==200);
106 info("Check PUT");
107 rs = rq.exec!"PUT"("http://httpbin.org/put",  `{"a":"b", "c":[1,2,3]}`, "application/json");
108 assert(rs.code==200);
109 info("Check PATCH");
110 rs = rq.exec!"PATCH"("http://httpbin.org/patch", "привiт, свiт!", "application/octet-stream");
111 assert(rs.code==200);
112 
113 info("Check compressed content");
114 globalLogLevel(LogLevel.info);
115 rq = Request();
116 rq.keepAlive = true;
117 rs = rq.get("http://httpbin.org/gzip");
118 assert(rs.code==200);
119 info("gzip - ok");
120 rs = rq.get("http://httpbin.org/deflate");
121 assert(rs.code==200);
122 info("deflate - ok");
123 
124 info("Check redirects");
125 globalLogLevel(LogLevel.info);
126 rq = Request();
127 rq.keepAlive = true;
128 rs = rq.get("http://httpbin.org/relative-redirect/2");
129 assert((cast(HTTPResponse)rs).history.length == 2);
130 assert((cast(HTTPResponse)rs).code==200);
131 //    rq = Request();
132 //    rq.keepAlive = true;
133 //    rq.proxy = "http://localhost:8888/";
134 rs = rq.get("http://httpbin.org/absolute-redirect/2");
135 assert((cast(HTTPResponse)rs).history.length == 2);
136 assert((cast(HTTPResponse)rs).code==200);
137 //    rq = Request();
138 rq.maxRedirects = 2;
139 rq.keepAlive = false;
140 rs = rq.get("https://httpbin.org/absolute-redirect/3");
141 assert((cast(HTTPResponse)rs).history.length == 2);
142 assert((cast(HTTPResponse)rs).code==302);
143 
144 info("Check utf8 content");
145 globalLogLevel(LogLevel.info);
146 rq = Request();
147 rs = rq.get("http://httpbin.org/encoding/utf8");
148 assert(rs.code==200);
149 
150 info("Check chunked content");
151 globalLogLevel(LogLevel.info);
152 rq = Request();
153 rq.keepAlive = true;
154 rq.bufferSize = 16*1024;
155 rs = rq.get("http://httpbin.org/range/1024");
156 assert(rs.code==200);
157 assert(rs.responseBody.length==1024);
158 
159 info("Check basic auth");
160 globalLogLevel(LogLevel.info);
161 rq = Request();
162 rq.authenticator = new BasicAuthentication("user", "passwd");
163 rs = rq.get("http://httpbin.org/basic-auth/user/passwd");
164 assert(rs.code==200);
165 
166 globalLogLevel(LogLevel.info);
167 info("Check exception handling, error messages are OK");
168 rq = Request();
169 rq.timeout = 1.seconds;
170 assertThrown!TimeoutException(rq.get("http://httpbin.org/delay/3"));
171 assertThrown!ConnectError(rq.get("http://0.0.0.0:65000/"));
172 assertThrown!ConnectError(rq.get("http://1.1.1.1/"));
173 //assertThrown!ConnectError(rq.get("http://gkhgkhgkjhgjhgfjhgfjhgf/"));
174 
175 globalLogLevel(LogLevel.info);
176 info("Check limits");
177 rq = Request();
178 rq.maxContentLength = 1;
179 assertThrown!RequestException(rq.get("http://httpbin.org/"));
180 rq = Request();
181 rq.maxHeadersLength = 1;
182 assertThrown!RequestException(rq.get("http://httpbin.org/"));
183 //
184 info("ftp post ", "ftp://speedtest.tele2.net/upload/TEST.TXT");
185 rs = rq.post("ftp://speedtest.tele2.net/upload/TEST.TXT", "test, ignore please\n".representation);
186 assert(rs.code == 226);
187 info("ftp get  ", "ftp://speedtest.tele2.net/nonexistent", ", in same session.");
188 rs = rq.get("ftp://speedtest.tele2.net/nonexistent");
189 assert(rs.code != 226);
190 info("ftp get  ", "ftp://speedtest.tele2.net/1KB.zip", ", in same session.");
191 rs = rq.get("ftp://speedtest.tele2.net/1KB.zip");
192 assert(rs.code == 226);
193 assert(rs.responseBody.length == 1024);
194 info("ftp get  ", "ftp://ftp.uni-bayreuth.de/README");
195 rs = rq.get("ftp://ftp.uni-bayreuth.de/README");
196 assert(rs.code == 226);
197 info("ftp post ", "ftp://speedtest.tele2.net/upload/TEST.TXT");
198 rs = rq.post("ftp://speedtest.tele2.net/upload/TEST.TXT", "another test, ignore please\n".representation);
199 assert(rs.code == 226);
200 info("ftp get  ", "ftp://ftp.iij.ad.jp/pub/FreeBSD/README.TXT");
201 rs = rq.get("ftp://ftp.iij.ad.jp/pub/FreeBSD/README.TXT");
202 assert(rs.code == 226);
203 info("testing ftp - done.");

Meta