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