/* Called by: zxid_soap_call_hdr_body, zxid_wsc_call */ struct zx_root_s* zxid_soap_call_raw(zxid_conf* cf, struct zx_str* url, struct zx_e_Envelope_s* env, char** ret_enve) { #ifdef USE_CURL struct zx_root_s* r; struct zx_str* ret; struct zx_str* ss; char soap_action_buf[1024]; char* soap_act; const char* env_start; ss = zx_easy_enc_elem_opt(cf, &env->gg); DD("ss(%.*s) len=%d", ss->len, ss->s, ss->len); if (cf->soap_action_hdr && strcmp(cf->soap_action_hdr,"#inhibit")) { if (!strcmp(cf->soap_action_hdr,"#same")) { if (env->Header && env->Header->Action && ZX_GET_CONTENT_S(env->Header->Action)) { snprintf(soap_action_buf,sizeof(soap_action_buf), "SOAPAction: \"%.*s\"", ZX_GET_CONTENT_LEN(env->Header->Action), ZX_GET_CONTENT_S(env->Header->Action)); soap_action_buf[sizeof(soap_action_buf)-1] = 0; soap_act = soap_action_buf; D("SOAPaction(%s)", soap_action_buf); } else { ERR("e:Envelope/e:Headers/a:Action SOAP header is malformed %p", env->Header); } } else { snprintf(soap_action_buf,sizeof(soap_action_buf), "SOAPAction: \"%s\"", cf->soap_action_hdr); soap_action_buf[sizeof(soap_action_buf)-1] = 0; soap_act = soap_action_buf; } } else soap_act = 0; ret = zxid_http_cli(cf, url->len, url->s, ss->len, ss->s, cf->wsc_soap_content_type, soap_act, 0); zx_str_free(cf->ctx, ss); if (ret_enve) *ret_enve = ret?ret->s:0; if (!ret) return 0; env_start = zxid_locate_soap_Envelope(ret->s); if (!env_start) { ERR("SOAP response does not have Envelope element url(%.*s)", url->len, url->s); D_XML_BLOB(cf, "NO ENVELOPE SOAP RESPONSE", ret->len, ret->s); ZX_FREE(cf->ctx, ret); return 0; } cf->ctx->top1 = 1; /* Stop parsing after first toplevel <e:Envelope> */ r = zx_dec_zx_root(cf->ctx, ret->len - (env_start - ret->s), env_start, "soap_call"); if (!r || !r->Envelope || !r->Envelope->Body) { ERR("Failed to parse SOAP response url(%.*s)", url->len, url->s); D_XML_BLOB(cf, "BAD SOAP RESPONSE", ret->len, ret->s); ZX_FREE(cf->ctx, ret); return 0; } return r; #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: */ size_t zxid_curl_write_data(void *buffer, size_t size, size_t nmemb, void *userp) { int len = size * nmemb; #if 1 struct zxid_curl_ctx* rc = (struct zxid_curl_ctx*)userp; int old_len, new_len, in_buf = rc->p - rc->buf; if (rc->p + len > rc->lim) { old_len = rc->lim-rc->buf; new_len = MIN(MAX(old_len + old_len, in_buf + len), ZXID_MAX_CURL_BUF); if (new_len == ZXID_MAX_CURL_BUF) { ERR("Too large HTTP response. Response length at least %d. Maximum allowed length (ZXID_MAX_CURL_BUF): %d", in_buf + len, ZXID_MAX_CURL_BUF); return -1; /* Signal error */ } D("Reallocating curl buffer from %d to %d in_buf=%d len=%d", old_len, new_len, in_buf, len); REALLOCN(rc->buf, new_len+1); rc->p = rc->buf + in_buf; rc->lim = rc->buf + new_len; } memcpy(rc->p, buffer, len); rc->p += len; if (errmac_debug & CURL_INOUT) { INFO("RECV(%.*s) %d chars", len, (char*)buffer, len); D_XML_BLOB(0, "RECV", len, (char*)buffer); } #else int fd = (int)userp; write_all_fd(fd, buffer, len); #endif return len; }
/* Called by: */ size_t zxid_curl_read_data(void *buffer, size_t size, size_t nmemb, void *userp) { int len = size*nmemb; struct zxid_curl_ctx* wc = (struct zxid_curl_ctx*)userp; if (len > (wc->lim - wc->p)) len = wc->lim - wc->p; memcpy(buffer, wc->p, len); wc->p += len; if (errmac_debug & CURL_INOUT) { INFO("SEND(%.*s) %d chars", len, (char*)buffer, len); D_XML_BLOB(0, "SEND", len, (char*)buffer); } return len; }
/* 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 }