Skip to content

Commit

Permalink
Implement post overload in std.net.curl
Browse files Browse the repository at this point in the history
This overload provides the ability to send properly escaped
www-form-urlencoded data using an associative array. The data is built into
name value pairs using an Appender!string that reserves 128 bytes per name
value pair. An example was added to the documentation and the existing one
changed as this is the more common use case.

Several corrections to coding style were suggested and corrected.
  • Loading branch information
GilesBathgate committed May 6, 2016
1 parent 1e9fdc0 commit 9185ddd
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 16 deletions.
57 changes: 41 additions & 16 deletions std/net/curl.d
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ Example:
---
import std.net.curl, std.stdio;
// Return a char[] containing the content specified by an URL
// Return a char[] containing the content specified by a URL
auto content = get("dlang.org");
// Post data and return a char[] containing the content specified by an URL
auto content = post("mydomain.com/here.cgi", "post data");
// Post data and return a char[] containing the content specified by a URL
auto content = post("mydomain.com/here.cgi", ["name1" : "value1", "name2" : "value2"]);
// Get content of file from ftp server
auto content = get("ftp.digitalmars.com/sieve.ds");
Expand Down Expand Up @@ -566,22 +566,26 @@ unittest
/** HTTP post content.
*
* Params:
* url = resource to post to
* postData = data to send as the body of the request. An array
* of an arbitrary type is accepted and will be cast to ubyte[]
* before sending it.
* conn = HTTP connection to use
* url = resource to post to
* postDict = data to send as the body of the request. An associative array
* of $(D string) is accepted and will be encoded using
* www-form-urlencoding
* postData = data to send as the body of the request. An array
* of an arbitrary type is accepted and will be cast to ubyte[]
* before sending it.
* conn = HTTP connection to use
* T = The template parameter $(D T) specifies the type to return. Possible values
* are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). If asking
* for $(D char), content will be converted from the connection character set
* (specified in HTTP response headers or FTP connection properties, both ISO-8859-1
* by default) to UTF-8.
*
* The template parameter $(D T) specifies the type to return. Possible values
* are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). If asking
* for $(D char), content will be converted from the connection character set
* (specified in HTTP response headers or FTP connection properties, both ISO-8859-1
* by default) to UTF-8.
*
* Example:
* Examples:
* ----
* import std.net.curl;
* auto content = post("d-lang.appspot.com/testUrl2", [1,2,3,4]);
*
* auto content1 = post("d-lang.appspot.com/testUrl2", ["name1" : "value1", "name2" : "value2"]);
* auto content2 = post("d-lang.appspot.com/testUrl2", [1,2,3,4]);
* ----
*
* Returns:
Expand Down Expand Up @@ -627,6 +631,27 @@ unittest
assert(res == cast(ubyte[])[17, 27, 35, 41]);
}

/// ditto
T[] post(T = char)(const(char)[] url, string[string] postDict, HTTP conn = HTTP())
if (is(T == char) || is(T == ubyte))
{
import std.uri : urlEncode;

return post(url, urlEncode(postDict), conn);
}

unittest
{
foreach (host; [testServer.addr, "http://" ~ testServer.addr])
{
testServer.handle((s) {
auto req = s.recvReq!char;
s.send(httpOK(req.bdy));
});
auto res = post(host ~ "/path", ["name1" : "value1", "name2" : "value2"]);
assert(res == "name1=value1&name2=value2");
}
}

/** HTTP/FTP put content.
*
Expand Down
38 changes: 38 additions & 0 deletions std/uri.d
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,44 @@ string encodeComponent(Char)(in Char[] uriComponent) if (isSomeChar!Char)
return URI_Encode(s, URI_Alpha | URI_Digit | URI_Mark);
}

/* Encode associative array using www-form-urlencoding
*
* Params:
* values = an associative array containing the values to be encoded.
*
* Returns:
* A string encoded using www-form-urlencoding.
*/
package string urlEncode(in string[string] values)
{
if (values.length == 0)
return "";

import std.array : Appender;
import std.format : formattedWrite;

Appender!string enc;
enc.reserve(values.length * 128);

bool first = true;
foreach (k, v; values)
{
if (!first)
enc.put('&');
formattedWrite(enc, "%s=%s", encodeComponent(k), encodeComponent(v));
first = false;
}
return enc.data;
}

unittest
{
string[string] a;
assert(urlEncode(a) == "");
assert(urlEncode(["name1" : "value1"]) == "name1=value1");
assert(urlEncode(["name1" : "value1", "name2" : "value2"]) == "name1=value1&name2=value2");
}

/***************************
* Does string s[] start with a URL?
* Returns:
Expand Down

0 comments on commit 9185ddd

Please sign in to comment.