Merge pull request #800 from CyberShadow/std-net-curl-binary-post

std.net.curl: Do not assume POST data is null-terminated string
This commit is contained in:
Andrei Alexandrescu 2012-09-25 22:27:11 -07:00
commit 87eb83d3b8

View file

@ -171,8 +171,8 @@ version(unittest)
// Run unit test with the PHOBOS_TEST_ALLOW_NET=1 set in order to // Run unit test with the PHOBOS_TEST_ALLOW_NET=1 set in order to
// allow net traffic // allow net traffic
import std.stdio; import std.stdio;
import std.c.stdlib;
import std.range; import std.range;
import std.process : environment;
enum testUrl1 = "http://d-lang.appspot.com/testUrl1"; enum testUrl1 = "http://d-lang.appspot.com/testUrl1";
enum testUrl2 = "http://d-lang.appspot.com/testUrl2"; enum testUrl2 = "http://d-lang.appspot.com/testUrl2";
enum testUrl3 = "ftp://ftp.digitalmars.com/sieve.ds"; enum testUrl3 = "ftp://ftp.digitalmars.com/sieve.ds";
@ -266,8 +266,8 @@ void download(Conn = AutoProtocol)(const(char)[] url, string saveToPath, Conn co
unittest unittest
{ {
if (!netAllowed()) return; if (!netAllowed()) return;
download("ftp.digitalmars.com/sieve.ds", "/tmp/downloaded-ftp-file"); download("ftp.digitalmars.com/sieve.ds", getTempPath() ~ "downloaded-ftp-file");
download("d-lang.appspot.com/testUrl1", "/tmp/downloaded-http-file"); download("d-lang.appspot.com/testUrl1", getTempPath() ~ "downloaded-http-file");
} }
/** Upload file from local files system using the HTTP or FTP protocol. /** Upload file from local files system using the HTTP or FTP protocol.
@ -322,8 +322,8 @@ void upload(Conn = AutoProtocol)(string loadFromPath, const(char)[] url, Conn co
unittest unittest
{ {
if (!netAllowed()) return; if (!netAllowed()) return;
// upload("/tmp/downloaded-ftp-file", "ftp.digitalmars.com/sieve.ds"); // upload(getTempPath() ~ "downloaded-ftp-file", "ftp.digitalmars.com/sieve.ds");
upload("/tmp/downloaded-http-file", "d-lang.appspot.com/testUrl2"); upload(getTempPath() ~ "downloaded-http-file", "d-lang.appspot.com/testUrl2");
} }
/** HTTP/FTP get content. /** HTTP/FTP get content.
@ -418,11 +418,24 @@ if (is(T == char) || is(T == ubyte))
unittest unittest
{ {
if (!netAllowed()) return; if (!netAllowed()) return;
auto res = post(testUrl2, "Hello world");
assert(res == "Hello world", {
string data = "Hello world";
auto res = post(testUrl2, data);
assert(res == data,
"put!HTTP() returns unexpected content " ~ res); "put!HTTP() returns unexpected content " ~ res);
} }
{
ubyte[] data;
foreach (n; 0..256)
data ~= cast(ubyte)n;
auto res = post!ubyte(testUrl2, data);
assert(res == data,
"put!HTTP() with binary data returns unexpected content (" ~ text(res.length) ~ " bytes)");
}
}
/** HTTP/FTP put content. /** HTTP/FTP put content.
* *
@ -2398,7 +2411,7 @@ struct HTTP
*/ */
@property void postData(const(void)[] data) @property void postData(const(void)[] data)
{ {
_postData(cast(void*)data.ptr, "application/octet-stream"); _postData(data, "application/octet-stream");
} }
/** Specifying data to post when not using the onSend callback. /** Specifying data to post when not using the onSend callback.
@ -2417,21 +2430,36 @@ struct HTTP
*/ */
@property void postData(const(char)[] data) @property void postData(const(char)[] data)
{ {
_postData(cast(void*)data.ptr, "text/plain"); _postData(data, "text/plain");
} }
// Helper for postData property // Helper for postData property
private void _postData(void* data, string contentType) private void _postData(const(void)[] data, string contentType)
{ {
// cannot use callback when specifying data directly so it is disabled here. // cannot use callback when specifying data directly so it is disabled here.
// here.
p.curl.clear(CurlOption.readfunction); p.curl.clear(CurlOption.readfunction);
addRequestHeader("Content-Type", contentType); addRequestHeader("Content-Type", contentType);
p.curl.set(CurlOption.postfields, data); p.curl.set(CurlOption.postfields, cast(void*)data.ptr);
p.curl.set(CurlOption.postfieldsize, data.length);
if (method == Method.undefined) if (method == Method.undefined)
method = Method.post; method = Method.post;
} }
unittest
{
if (!netAllowed()) return;
ubyte[] data;
foreach (n; 0..256)
data ~= cast(ubyte)n;
auto http = HTTP(testUrl2);
http.postData = data;
ubyte[] result;
http.onReceive = (ubyte[] data) { result ~= data; return data.length; };
http.perform();
assert(data == result,
"HTTP POST with binary data returns unexpected content (" ~ text(result.length) ~ " bytes)");
}
/** /**
* Set the event handler that receives incoming headers. * Set the event handler that receives incoming headers.
* *
@ -2619,7 +2647,6 @@ struct HTTP
} // HTTP } // HTTP
/** /**
FTP client functionality. FTP client functionality.
@ -4101,7 +4128,17 @@ private static void _spawnAsync(Conn, Unit, Terminator = void)()
fromTid.send(thisTid(), curlMessage(true)); // signal done fromTid.send(thisTid(), curlMessage(true)); // signal done
} }
version (unittest) private auto netAllowed() version (unittest)
{ {
return getenv("PHOBOS_TEST_ALLOW_NET") != null; private auto netAllowed()
{
return environment.get("PHOBOS_TEST_ALLOW_NET") != null;
}
private string getTempPath()
{
version (Windows)
return environment["TEMP"] ~ `\`;
else
return "/tmp/";
}
} }