1 
2 /** Small helpers for libCURL
3  *
4  * This module contains all the CURL related helpers.
5  */
6 module acme.curl_helpers;
7 
8 import etc.c.curl;
9 
10 import std.conv;
11 import std.net.curl;
12 import std.stdio;
13 import std.string;
14 import std.typecons;
15 
16 private:
17 
18 void myLog(alias fun = writeln, T...)(T args)
19 {
20 	if (curlBeVerbose)
21 		fun(args);
22 }
23 
24 /** Current release number - FIXME Derive this from Git Tag. How in D? */
25 
26 public:
27 	enum acmeClientVersion = "0.1.8"; /// Client Version FIXME How to set this from cmdline?
28 	bool curlBeVerbose = false; /// Use verbose outputs?
29 
30 
31 /** Compose an error msg from custom and CURL error
32  *
33  * Params:
34  *  s = custom message
35  *  c = CURLcode
36  */
37 string getCurlError(string s, CURLcode c)
38 {
39 	import std.format : format;
40 	auto errorstring = curl_easy_strerror(c).to!string;
41 	auto resultstring = format( "%s\nErrorcode: %d (%s)", s, c, errorstring);
42     return resultstring;
43 }
44 
45 /* ---------------------------------------------------------------------------- */
46 
47 /** Get just the http receive headers with a given name from an URL
48 
49 	Params:
50 	  url = Url to query
51 	  headerKey = headerline to query
52 	Returns:
53 	  the value of a given header or null
54  */
55 string getResponseHeader(string url, string headerKey)
56 {
57 	string headerVal;
58 
59 	auto http = HTTP(url);
60 	http.setUserAgent = "acme-lw-d/" ~ acmeClientVersion ~ " " ~ HTTP.defaultUserAgent();
61 	http.method = HTTP.Method.head;
62 	http.onReceiveHeader =
63 		(in char[] key, in char[] value)
64 			{
65 				myLog( "Response Header : ", key, " = ", value);
66 				if (key.toLower == headerKey.toLower)
67 					headerVal = value.idup;
68 			};
69 	http.perform();
70 	return headerVal;
71 }
72 
73 /* ---------------------------------------------------------------------------- */
74 
75 /** Do some posting, filter for some headerkey
76  *
77  * Params:
78  *  url = url to pst to
79  *  postBody = data to post
80  *  status = storage for a HTTP.StatusLine
81  *  rheaders = responseheader to return
82  *  nonce = pointer to nonce string, so that we can update it.
83  *
84  * Returns:
85  *   the received payload of the POST operation
86  */
87 string doPost(string url, char[] postBody, HTTP.StatusLine* status,
88 	string[string]* rheaders,
89 	string* nonce)
90 {
91 	string response;
92 	//string headerVal;
93 
94 	auto http = HTTP(url);
95 	http.setUserAgent = "acme-lw-d/" ~ acmeClientVersion ~ " " ~ HTTP.defaultUserAgent();
96 	http.verbose = curlBeVerbose;
97 	http.method = HTTP.Method.post;
98 	http.addRequestHeader("Content-Type", "application/jose+json");
99 
100 	http.onReceiveHeader =
101 		(in char[] key, in char[] value)
102 			{
103 				if (key.toLower == "replay-nonce") {
104 					*nonce = value.idup;
105 					myLog("Setting new NOnce: ", *nonce);
106 				}
107 			};
108 	http.onReceive =
109 		(ubyte[] data)
110 			{
111 				//writefln( "data: %s", to!string(data));
112 				response ~= data;
113 				return data.length;
114 			};
115 	http.postData = postBody;
116 
117 	http.perform();
118 
119 	if (status !is null) *status = http.statusLine;
120 
121 	if (rheaders !is null)
122 		*rheaders = http.responseHeaders;
123 
124 	return response;
125 }
126 
127 /* ---------------------------------------------------------------------------- */
128