Add headers to request
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")
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")
Set authenticator for http requests. v - Auth instance.
Set IO buffer size for http and ftp requests v - buffer size in bytes.
get contentLength of the responce
get length og actually received content. this value increase over time, while we receive data
Set Cookie for http requests. v - array of cookie.
Get Cookie for http requests. v - array of cookie.
Set http keepAlive value v - use keepalive requests - true, or not - false
Set maximum content lenth both for http and ftp requests v - maximum content length in bytes. When limit reached - throw RequestException
Set maximum length for HTTP headers v - maximum length of the HTTP response. When limit reached - throw RequestException
Set limit on HTTP redirects v - limit on redirect depth
Set timeout on IO operation. v - timeout value
set "streaming" property
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.
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 string httpbinUrl = httpTestServer(); 10 11 version(vibeD) { 12 } 13 else { 14 import httpbin; 15 auto server = httpbinApp(); 16 server.start(); 17 scope(exit) { 18 server.stop(); 19 } 20 } 21 22 globalLogLevel(LogLevel.info); 23 24 infof("testing Request"); 25 Request rq; 26 Response rs; 27 // 28 rs = rq.get(httpbinUrl); 29 assert(rs.code==200); 30 assert(rs.responseBody.length > 0); 31 rs = rq.get(httpbinUrl ~ "get", ["c":" d", "a":"b"]); 32 assert(rs.code == 200); 33 auto json = parseJSON(rs.responseBody.data).object["args"].object; 34 assert(json["c"].str == " d"); 35 assert(json["a"].str == "b"); 36 37 rq = Request(); 38 rq.keepAlive = true; 39 // handmade json 40 info("Check POST json"); 41 rs = rq.post(httpbinUrl ~ "post?b=x", `{"a":"b ", "c":[1,2,3]}`, "application/json"); 42 assert(rs.code==200); 43 json = parseJSON(rs.responseBody.data).object["args"].object; 44 assert(json["b"].str == "x"); 45 json = parseJSON(rs.responseBody.data).object["json"].object; 46 assert(json["a"].str == "b "); 47 assert(json["c"].array.map!(a=>a.integer).array == [1,2,3]); 48 { 49 import std.file; 50 import std.path; 51 auto tmpd = tempDir(); 52 auto tmpfname = tmpd ~ dirSeparator ~ "request_test.txt"; 53 auto f = File(tmpfname, "wb"); 54 f.rawWrite("abcdefgh\n12345678\n"); 55 f.close(); 56 // files 57 info("Check POST files"); 58 PostFile[] files = [ 59 {fileName: tmpfname, fieldName:"abc", contentType:"application/octet-stream"}, 60 {fileName: tmpfname} 61 ]; 62 rs = rq.post(httpbinUrl ~ "post", files); 63 assert(rs.code==200); 64 info("Check POST chunked from file.byChunk"); 65 f = File(tmpfname, "rb"); 66 rs = rq.post(httpbinUrl ~ "post", f.byChunk(3), "application/octet-stream"); 67 assert(rs.code==200); 68 auto data = fromJsonArrayToStr(parseJSON(rs.responseBody).object["data"]); 69 assert(data=="abcdefgh\n12345678\n"); 70 f.close(); 71 } 72 // ranges 73 { 74 info("Check POST chunked from lineSplitter"); 75 auto s = lineSplitter("one,\ntwo,\nthree."); 76 rs = rq.exec!"POST"(httpbinUrl ~ "post", s, "application/octet-stream"); 77 assert(rs.code==200); 78 auto data = fromJsonArrayToStr(parseJSON(rs.responseBody).object["data"]); 79 assert(data=="one,two,three."); 80 } 81 { 82 info("Check POST chunked from array"); 83 auto s = ["one,", "two,", "three."]; 84 rs = rq.post(httpbinUrl ~ "post", s, "application/octet-stream"); 85 assert(rs.code==200); 86 auto data = fromJsonArrayToStr(parseJSON(rs.responseBody).object["data"]); 87 assert(data=="one,two,three."); 88 } 89 { 90 info("Check POST chunked using std.range.chunks()"); 91 auto s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 92 rs = rq.post(httpbinUrl ~ "post", s.representation.chunks(10), "application/octet-stream"); 93 assert(rs.code==200); 94 auto data = fromJsonArrayToStr(parseJSON(rs.responseBody).object["data"]); 95 assert(data==s); 96 } 97 // associative array 98 rs = rq.post(httpbinUrl ~ "post", ["a":"b ", "c":"d"]); 99 assert(rs.code==200); 100 auto form = parseJSON(rs.responseBody.data).object["form"].object; 101 assert(form["a"].str == "b "); 102 assert(form["c"].str == "d"); 103 info("Check HEAD"); 104 rs = rq.exec!"HEAD"(httpbinUrl); 105 assert(rs.code==200); 106 info("Check DELETE"); 107 rs = rq.exec!"DELETE"(httpbinUrl ~ "delete"); 108 assert(rs.code==200); 109 info("Check PUT"); 110 rs = rq.exec!"PUT"(httpbinUrl ~ "put", `{"a":"b", "c":[1,2,3]}`, "application/json"); 111 assert(rs.code==200); 112 info("Check PATCH"); 113 rs = rq.exec!"PATCH"(httpbinUrl ~ "patch", "привiт, свiт!", "application/octet-stream"); 114 assert(rs.code==200); 115 116 info("Check compressed content"); 117 rq = Request(); 118 rq.keepAlive = true; 119 rq.addHeaders(["X-Header": "test"]); 120 rs = rq.get(httpbinUrl ~ "gzip"); 121 assert(rs.code==200); 122 info("gzip - ok"); 123 rs = rq.get(httpbinUrl ~ "deflate"); 124 assert(rs.code==200); 125 info("deflate - ok"); 126 127 info("Check redirects"); 128 rq = Request(); 129 rq.keepAlive = true; 130 rs = rq.get(httpbinUrl ~ "relative-redirect/2"); 131 assert((cast(HTTPResponse)rs).history.length == 2); 132 assert((cast(HTTPResponse)rs).code==200); 133 134 info("Check cookie"); 135 rq = Request(); 136 rs = rq.get(httpbinUrl ~ "cookies/set?A=abcd&b=cdef"); 137 assert(rs.code == 200); 138 json = parseJSON(rs.responseBody.data).object["cookies"].object; 139 assert(json["A"].str == "abcd"); 140 assert(json["b"].str == "cdef"); 141 auto cookie = rq.cookie(); 142 foreach(c; rq.cookie) { 143 final switch(c.attr) { 144 case "A": 145 assert(c.value == "abcd"); 146 break; 147 case "b": 148 assert(c.value == "cdef"); 149 break; 150 } 151 } 152 rs = rq.get(httpbinUrl ~ "absolute-redirect/2"); 153 assert((cast(HTTPResponse)rs).history.length == 2); 154 assert((cast(HTTPResponse)rs).code==200); 155 // rq = Request(); 156 rq.maxRedirects = 2; 157 rq.keepAlive = false; 158 assertThrown!MaxRedirectsException(rq.get(httpbinUrl ~ "absolute-redirect/3")); 159 160 info("Check chunked content"); 161 rq = Request(); 162 rq.keepAlive = true; 163 rq.bufferSize = 16*1024; 164 rs = rq.get(httpbinUrl ~ "range/1024"); 165 assert(rs.code==200); 166 assert(rs.responseBody.length==1024); 167 168 info("Check basic auth"); 169 rq = Request(); 170 rq.authenticator = new BasicAuthentication("user", "passwd"); 171 rs = rq.get(httpbinUrl ~ "basic-auth/user/passwd"); 172 assert(rs.code==200); 173 174 info("Check limits"); 175 rq = Request(); 176 rq.maxContentLength = 1; 177 assertThrown!RequestException(rq.get(httpbinUrl)); 178 rq = Request(); 179 rq.maxHeadersLength = 1; 180 assertThrown!RequestException(rq.get(httpbinUrl)); 181 182 info("Test getContent"); 183 auto r = getContent(httpbinUrl ~ "stream/20"); 184 assert(r.splitter('\n').filter!("a.length>0").count == 20); 185 r = getContent(httpbinUrl ~ "get", ["a":"b", "c":"d"]); 186 string name = "user", sex = "male"; 187 int age = 42; 188 r = getContent(httpbinUrl ~ "get", "name", name, "age", age, "sex", sex); 189 190 info("Test receiveAsRange with GET"); 191 rq = Request(); 192 rq.useStreaming = true; 193 rq.bufferSize = 16; 194 rs = rq.get(httpbinUrl ~ "stream/20"); 195 auto stream = rs.receiveAsRange(); 196 ubyte[] streamedContent; 197 while( !stream.empty() ) { 198 streamedContent ~= stream.front; 199 stream.popFront(); 200 } 201 rq = Request(); 202 rs = rq.get(httpbinUrl ~ "stream/20"); 203 assert(streamedContent == rs.responseBody.data); 204 info("Test postContent"); 205 r = postContent(httpbinUrl ~ "post", `{"a":"b", "c":1}`, "application/json"); 206 assert(parseJSON(r).object["json"].object["c"].integer == 1); 207 208 /// Posting to forms (for small data) 209 /// 210 /// posting query parameters using "application/x-www-form-urlencoded" 211 info("Test postContent using query params"); 212 postContent(httpbinUrl ~ "post", queryParams("first", "a", "second", 2)); 213 214 /// posting using multipart/form-data (large data and files). See docs fot HTTPRequest 215 info("Test postContent form"); 216 MultipartForm mpform; 217 mpform.add(formData(/* field name */ "greeting", /* content */ cast(ubyte[])"hello")); 218 postContent(httpbinUrl ~ "post", mpform); 219 220 /// you can do this using Request struct to access response details 221 info("Test postContent form via Request()"); 222 rq = Request(); 223 mpform = MultipartForm().add(formData(/* field name */ "greeting", /* content */ cast(ubyte[])"hello")); 224 rs = rq.post(httpbinUrl ~ "post", mpform); 225 assert(rs.code == 200); 226 227 info("Test receiveAsRange with POST"); 228 streamedContent.length = 0; 229 rq = Request(); 230 rq.useStreaming = true; 231 rq.bufferSize = 16; 232 string s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 233 rs = rq.post(httpbinUrl ~ "post", s.representation.chunks(10), "application/octet-stream"); 234 stream = rs.receiveAsRange(); 235 while( !stream.empty() ) { 236 streamedContent ~= stream.front; 237 stream.popFront(); 238 } 239 rq = Request(); 240 rs = rq.post(httpbinUrl ~ "post", s.representation.chunks(10), "application/octet-stream"); 241 assert(streamedContent == rs.responseBody.data); 242 info("Test get in parallel"); 243 { 244 import std.stdio; 245 import std.parallelism; 246 import std.algorithm; 247 import std.string; 248 import core.atomic; 249 250 immutable auto urls = [ 251 "stream/10", 252 "stream/20", 253 "stream/30", 254 "stream/40", 255 "stream/50", 256 "stream/60", 257 "stream/70", 258 ].map!(a => httpbinUrl ~ a).array.idup; 259 260 defaultPoolThreads(4); 261 262 shared short lines; 263 264 foreach(url; parallel(urls)) { 265 atomicOp!"+="(lines, getContent(url).splitter("\n").count); 266 } 267 assert(lines == 287); 268 269 }
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)