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 	debug { http.verifyPeer = false; }
63 	http.onReceiveHeader =
64 		(in char[] key, in char[] value)
65 			{
66 				myLog( "Response Header : ", key, " = ", value);
67 				if (key.toLower == headerKey.toLower)
68 					headerVal = value.idup;
69 			};
70 	http.perform();
71 	return headerVal;
72 }
73 
74 /* ---------------------------------------------------------------------------- */
75 
76 /** Do some posting, filter for some headerkey
77  *
78  * Params:
79  *  url = url to pst to
80  *  postBody = data to post
81  *  status = storage for a HTTP.StatusLine
82  *  rheaders = responseheader to return
83  *  nonce = pointer to nonce string, so that we can update it.
84  *
85  * Returns:
86  *   the received payload of the POST operation
87  */
88 string doPost(string url, char[] postBody, HTTP.StatusLine* status,
89 	string[string]* rheaders,
90 	string* nonce)
91 {
92 	string response;
93 	//string headerVal;
94 
95 	auto http = HTTP(url);
96 	http.setUserAgent = "acme-lw-d/" ~ acmeClientVersion ~ " " ~ HTTP.defaultUserAgent();
97 	debug { http.verifyPeer = false; }
98 	http.verbose = curlBeVerbose;
99 	http.method = HTTP.Method.post;
100 	http.addRequestHeader("Content-Type", "application/jose+json");
101 
102 	http.onReceiveHeader =
103 		(in char[] key, in char[] value)
104 			{
105 				if (key.toLower == "replay-nonce") {
106 					*nonce = value.idup;
107 					myLog("Setting new NOnce: ", *nonce);
108 				}
109 			};
110 	http.onReceive =
111 		(ubyte[] data)
112 			{
113 				//writefln( "data: %s", to!string(data));
114 				response ~= data;
115 				return data.length;
116 			};
117 	http.postData = postBody;
118 
119 	http.perform();
120 
121 	if (status !is null) *status = http.statusLine;
122 
123 	if (rheaders !is null)
124 		*rheaders = http.responseHeaders;
125 
126 	return response;
127 }
128 
129 /* ---------------------------------------------------------------------------- */
130