/* Called by: zxid_soap_call_raw */ struct zx_str* zxid_http_cli(zxid_conf* cf, int url_len, const char* url, int len, const char* data, const char* content_type, const char* headers, int flags) { #ifdef USE_CURL struct zx_str* ret; CURLcode res; struct zxid_curl_ctx rc; struct zxid_curl_ctx wc; struct curl_slist content_type_curl; struct curl_slist headers_curl; char* urli; rc.buf = rc.p = ZX_ALLOC(cf->ctx, ZXID_INIT_SOAP_BUF+1); rc.lim = rc.buf + ZXID_INIT_SOAP_BUF; /* The underlying HTTP client is libcurl. While libcurl is documented to * be "entirely thread safe", one limitation is that curl handle can not * be shared between threads. Since we keep the curl handle as a part * of the configuration object, which may be shared between threads, * we need to take a lock for duration of the curl operation. Thus any * given configuration object can have only one HTTP request active * at a time. If you need more parallelism, you need more configuration * objects. */ #if 0 cf->curl = curl_easy_init(); curl_easy_reset(cf->curl); LOCK_INIT(cf->curl_mx); LOCK(cf->curl_mx, "curl-cli"); #else LOCK(cf->curl_mx, "curl-cli"); curl_easy_reset(cf->curl); #endif curl_easy_setopt(cf->curl, CURLOPT_WRITEDATA, &rc); curl_easy_setopt(cf->curl, CURLOPT_WRITEFUNCTION, zxid_curl_write_data); curl_easy_setopt(cf->curl, CURLOPT_NOPROGRESS, 1); curl_easy_setopt(cf->curl, CURLOPT_SSL_VERIFYPEER, 0); /* *** arrange verification */ curl_easy_setopt(cf->curl, CURLOPT_SSL_VERIFYHOST, 0); /* *** arrange verification */ //curl_easy_setopt(cf->curl, CURLOPT_CERTINFO, 1); if (!(flags & 0x02)) { curl_easy_setopt(cf->curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(cf->curl, CURLOPT_MAXREDIRS, 110); } if (flags & 0x01) curl_easy_setopt(cf->curl, CURLOPT_HEADER, 1); /* response shall have Heacers CRLF CRLF Body */ if (url_len == -1) url_len = strlen(url); urli = ZX_ALLOC(cf->ctx, url_len+1); memcpy(urli, url, url_len); urli[url_len] = 0; DD("urli(%s) len=%d", urli, len); curl_easy_setopt(cf->curl, CURLOPT_URL, urli); if (data) { if (len == -1) len = strlen(data); wc.buf = wc.p = (char*)data; wc.lim = (char*)data + len; curl_easy_setopt(cf->curl, CURLOPT_POST, 1); curl_easy_setopt(cf->curl, CURLOPT_POSTFIELDSIZE, len); curl_easy_setopt(cf->curl, CURLOPT_READDATA, &wc); curl_easy_setopt(cf->curl, CURLOPT_READFUNCTION, zxid_curl_read_data); ZERO(&content_type_curl, sizeof(content_type_curl)); content_type_curl.data = (char*)content_type; if (headers) { ZERO(&headers_curl, sizeof(headers_curl)); headers_curl.data = (char*)headers; headers_curl.next = &content_type_curl; //curl_slist_append(3) curl_easy_setopt(cf->curl, CURLOPT_HTTPHEADER, &headers_curl); } else { curl_easy_setopt(cf->curl, CURLOPT_HTTPHEADER, &content_type_curl); } } else { if (headers) { ZERO(&headers_curl, sizeof(headers_curl)); headers_curl.data = (char*)headers; curl_easy_setopt(cf->curl, CURLOPT_HTTPHEADER, &headers_curl); } } INFO("----------- call(%s) -----------", urli); DD("HTTP_CLI post(%.*s) len=%d\n", len, STRNULLCHK(data), len); D_XML_BLOB(cf, "HTTP_CLI POST", len, STRNULLCHK(data)); res = curl_easy_perform(cf->curl); /* <========= Actual call, blocks. */ switch (res) { case 0: break; case CURLE_SSL_CONNECT_ERROR: ERR("Is the URL(%s) really an https url? Check that certificate of the server is valid and that certification authority is known to the client. CURLcode(%d) CURLerr(%s)", urli, res, CURL_EASY_STRERR(res)); DD("buf(%.*s)", rc.lim-rc.buf, rc.buf); #if 0 struct curl_certinfo* ci; res = curl_easy_getinfo(cf->curl, CURLINFO_CERTINFO, &ci); /* CURLINFO_SSL_VERIFYRESULT */ if (!res && ci) { int i; struct curl_slist *slist; D("%d certs", ci->num_of_certs); for (i = 0; i < ci->num_of_certs; ++i) for (slist = ci->certinfo[i]; slist; slist = slist->next) D("%d: %s", i, slist->data); } #endif break; default: ERR("Failed post to url(%s) CURLcode(%d) CURLerr(%s)", urli, res, CURL_EASY_STRERR(res)); DD("buf(%.*s)", rc.lim-rc.buf, rc.buf); } /*curl_easy_getinfo(cf->curl, CURLINFO_CONTENT_TYPE, char*);*/ UNLOCK(cf->curl_mx, "curl-cli"); ZX_FREE(cf->ctx, urli); rc.lim = rc.p; rc.p[0] = 0; DD("HTTP_CLI got(%s)", rc.buf); DD_XML_BLOB(cf, "HTTP_CLI GOT", rc.lim - rc.buf, rc.buf); ret = zx_ref_len_str(cf->ctx, rc.lim - rc.buf, rc.buf); return ret; #else ERR("This copy of zxid was compiled to NOT use libcurl. SOAP calls (such as Artifact profile and WSC) are not supported. Add -DUSE_CURL (make ENA_CURL=1) and recompile. %d", 0); return 0; #endif }
/* Called by: zxid_soap_call_raw */ struct zx_str* zxid_http_post_raw(zxid_conf* cf, int url_len, const char* url, int len, const char* data, const char* SOAPaction) { #ifdef USE_CURL struct zx_str* ret; CURLcode res; struct zxid_curl_ctx rc; struct zxid_curl_ctx wc; struct curl_slist content_type; struct curl_slist SOAPaction_curl; char* urli; rc.buf = rc.p = ZX_ALLOC(cf->ctx, ZXID_INIT_SOAP_BUF+1); rc.lim = rc.buf + ZXID_INIT_SOAP_BUF; #if 0 cf->curl = curl_easy_init(); curl_easy_reset(cf->curl); LOCK_INIT(cf->curl_mx); LOCK(cf->curl_mx, "curl-soap"); #else LOCK(cf->curl_mx, "curl-soap"); curl_easy_reset(cf->curl); #endif curl_easy_setopt(cf->curl, CURLOPT_WRITEDATA, &rc); curl_easy_setopt(cf->curl, CURLOPT_WRITEFUNCTION, zxid_curl_write_data); curl_easy_setopt(cf->curl, CURLOPT_NOPROGRESS, 1); curl_easy_setopt(cf->curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(cf->curl, CURLOPT_MAXREDIRS, 110); curl_easy_setopt(cf->curl, CURLOPT_SSL_VERIFYPEER, 0); /* *** arrange verification */ curl_easy_setopt(cf->curl, CURLOPT_SSL_VERIFYHOST, 0); /* *** arrange verification */ //curl_easy_setopt(cf->curl, CURLOPT_CERTINFO, 1); if (url_len == -1) url_len = strlen(url); urli = ZX_ALLOC(cf->ctx, url_len+1); memcpy(urli, url, url_len); urli[url_len] = 0; DD("urli(%s) len=%d", urli, len); curl_easy_setopt(cf->curl, CURLOPT_URL, urli); if (len == -1) len = strlen(data); wc.buf = wc.p = (char*)data; wc.lim = (char*)data + len; curl_easy_setopt(cf->curl, CURLOPT_POST, 1); curl_easy_setopt(cf->curl, CURLOPT_POSTFIELDSIZE, len); curl_easy_setopt(cf->curl, CURLOPT_READDATA, &wc); curl_easy_setopt(cf->curl, CURLOPT_READFUNCTION, zxid_curl_read_data); ZERO(&content_type, sizeof(content_type)); content_type.data = cf->wsc_soap_content_type; /* SOAP11: "Content-Type: text/xml" */ if (SOAPaction) { ZERO(&SOAPaction_curl, sizeof(SOAPaction_curl)); SOAPaction_curl.data = (char*)SOAPaction; SOAPaction_curl.next = &content_type; //curl_slist_append(3) curl_easy_setopt(cf->curl, CURLOPT_HTTPHEADER, &SOAPaction_curl); } else { curl_easy_setopt(cf->curl, CURLOPT_HTTPHEADER, &content_type); } INFO("----------- call(%s) -----------", urli); DD("SOAP_CALL post(%.*s) len=%d\n", len, data, len); D_XML_BLOB(cf, "SOAPCALL POST", len, data); res = curl_easy_perform(cf->curl); /* <========= Actual call, blocks. */ switch (res) { case 0: break; case CURLE_SSL_CONNECT_ERROR: ERR("Is the URL(%s) really an https url? Check that certificate of the server is valid and that certification authority is known to the client. CURLcode(%d) CURLerr(%s)", urli, res, CURL_EASY_STRERR(res)); DD("buf(%.*s)", rc.lim-rc.buf, rc.buf); #if 0 struct curl_certinfo* ci; res = curl_easy_getinfo(cf->curl, CURLINFO_CERTINFO, &ci); /* CURLINFO_SSL_VERIFYRESULT */ if (!res && ci) { int i; struct curl_slist *slist; D("%d certs", ci->num_of_certs); for (i = 0; i < ci->num_of_certs; ++i) for (slist = ci->certinfo[i]; slist; slist = slist->next) D("%d: %s", i, slist->data); } #endif break; default: ERR("Failed post to url(%s) CURLcode(%d) CURLerr(%s)", urli, res, CURL_EASY_STRERR(res)); DD("buf(%.*s)", rc.lim-rc.buf, rc.buf); } /*curl_easy_getinfo(cf->curl, CURLINFO_CONTENT_TYPE, char*);*/ UNLOCK(cf->curl_mx, "curl-soap"); ZX_FREE(cf->ctx, urli); rc.lim = rc.p; rc.p[0] = 0; DD("SOAP_CALL got(%s)", rc.buf); D_XML_BLOB(cf, "SOAPCALL GOT", rc.lim - rc.buf, rc.buf); ret = zx_ref_len_str(cf->ctx, rc.lim - rc.buf, rc.buf); return ret; #else ERR("This copy of zxid was compiled to NOT use libcurl. SOAP calls (such as Artifact profile and WSC) are not supported. Add -DUSE_CURL (make ENA_CURL=1) and recompile. %d", 0); return 0; #endif }