479
481
*-----------------------------------------------------------------------------
483
* cdk::BaseXml::InvokeAbortOnConnectError --
485
* Helper method to invoke onAbort handler when there is an HTTP error
486
* connecting to server. This method is 'protected' therefore subclasses
487
* may invoke it from ResponseDispatch, if alwaysDispatchResponse is set on
496
*-----------------------------------------------------------------------------
500
BaseXml::InvokeAbortOnConnectError(BasicHttpErrorCode errorCode, // IN
501
BasicHttpResponseCode responseCode, // IN
502
RequestState *state) // IN
507
#define ERR_CASE(c, d) case c: code = #c; detail = d; break
510
* Treat unsuccessful HTTP responses (e.g. "503 Service unavailable")
511
* as an HTTP errors. This can also be done in basicHttp by using
512
* CURLOPT_FAILONERROR.
514
if (errorCode == BASICHTTP_ERROR_NONE && !HTTP_IS_SUCCESS(responseCode)) {
515
errorCode = BASICHTTP_ERROR_HTTP_RETURNED_ERROR;
519
case BASICHTTP_ERROR_NONE:
522
ERR_CASE(BASICHTTP_ERROR_UNSUPPORTED_PROTOCOL,
523
_("Unsupported protocol"));
524
ERR_CASE(BASICHTTP_ERROR_URL_MALFORMAT,
526
ERR_CASE(BASICHTTP_ERROR_COULDNT_RESOLVE_PROXY,
527
_("The proxy could not be resolved"));
528
ERR_CASE(BASICHTTP_ERROR_COULDNT_RESOLVE_HOST,
529
_("The host could not be resolved"));
530
ERR_CASE(BASICHTTP_ERROR_COULDNT_CONNECT,
531
_("Could not connect to server"));
532
ERR_CASE(BASICHTTP_ERROR_HTTP_RETURNED_ERROR,
533
Util::Format(_("HTTP error %d"), responseCode));
534
ERR_CASE(BASICHTTP_ERROR_OPERATION_TIMEDOUT,
535
_("Connection timed out"));
536
ERR_CASE(BASICHTTP_ERROR_SSL_CONNECT_ERROR,
537
_("SSL connection error"));
538
ERR_CASE(BASICHTTP_ERROR_TOO_MANY_REDIRECTS,
539
_("Too many redirects"));
541
/* n:1 mapped curl errors. */
542
ERR_CASE(BASICHTTP_ERROR_TRANSFER,
543
_("Transfer error"));
544
ERR_CASE(BASICHTTP_ERROR_SSL_SECURITY,
545
_("SSL security error"));
549
ERR_CASE(BASICHTTP_ERROR_GENERIC,
558
_("The View Connection Server connection failed."), code.c_str(),
559
Util::Format(_("%s.\n\n"
560
"Verify that the view connection server address, "
561
"port, network settings, and SSL settings are "
562
"correct and try again."), detail.c_str())));
567
*-----------------------------------------------------------------------------
481
569
* cdk::BaseXml::OnResponse --
483
* Parse an XML API response based on the response operation. Invokes the
484
* onAbort/onDone handler passed to the initial request.
571
* Find the request's state, and set its response. Add an idle
572
* callback to process the response after curl has processed its
573
* headers and freed this connection up in case we need to issue
490
* Frees the BasicHttpRequest.
492
582
*-----------------------------------------------------------------------------
497
587
BasicHttpResponse *response, // IN
498
588
void *data) // IN
500
BaseXml *that = reinterpret_cast<BaseXml*>(data);
590
BaseXml *that = reinterpret_cast<BaseXml *>(data);
593
for (std::list<RequestState *>::iterator i = that->mActiveRequests.begin();
594
i != that->mActiveRequests.end(); i++) {
595
RequestState *state = *i;
596
if (state->request == request) {
597
state->response = response;
598
Poll_CallbackRemove(POLL_CS_MAIN, 0, OnIdleProcessResponses, that,
600
Poll_Callback(POLL_CS_MAIN, 0, OnIdleProcessResponses, that,
601
POLL_REALTIME, 0, NULL);
609
*-----------------------------------------------------------------------------
611
* cdk::BaseXml::OnIdleProcessResponses --
613
* Process any pending responses (probably at most one).
621
*-----------------------------------------------------------------------------
625
BaseXml::OnIdleProcessResponses(void *data) // IN
627
BaseXml *that = reinterpret_cast<BaseXml *>(data);
630
std::list<RequestState *>::iterator i = that->mActiveRequests.begin();
631
while (i != that->mActiveRequests.end()) {
632
RequestState *state = *i;
633
if (!state->response) {
636
i = that->mActiveRequests.erase(i);
637
bool wasDeleted = that->ProcessResponse(state);
648
*-----------------------------------------------------------------------------
650
* cdk::BaseXml::ProcessResponse --
652
* Parse an XML API response based on the response operation. Invokes the
653
* onAbort/onDone handler passed to the initial request.
656
* TRUE if no more responses should be processed.
659
* Callbacks called from this function may have deleted this
660
* object before they return.
662
*-----------------------------------------------------------------------------
666
BaseXml::ProcessResponse(RequestState *state) // IN
668
// XXX: keep code churn down (this was originally static)
669
BaseXml *that = this;
671
BasicHttpRequest *request = state->request;
672
BasicHttpResponse *response = state->response;
503
674
xmlDoc *doc = NULL;
504
675
xmlNode *docNode;
510
681
that->mRequestId++;
512
RequestState *state = NULL;
513
for (std::list<RequestState *>::iterator i = that->mActiveRequests.begin();
514
i != that->mActiveRequests.end(); i++) {
515
if ((*i)->request == request) {
517
that->mActiveRequests.erase(i);
522
683
if (that->mResetWatch) {
523
684
resetWatch = that->mResetWatch;
525
686
that->mResetWatch = resetWatch;
528
ASSERT(state->request == request);
529
state->request = request;
530
state->response = response;
690
* If we've been redirected and we're not using a proxy, then we can run into
691
* long delays due to cURL leaving connections open. Thus, we need to use
692
* the redirected protocol and port in the future. See bz 513320.
694
#if !defined(_WIN32) || defined(__MINGW32__)
695
if (response->effectiveURL) {
700
Util::ParseHostLabel(response->effectiveURL, &port, &secure);
707
#endif // !defined(_WIN32) || defined(__MINGW32)
532
709
MultiRequestState *multi = dynamic_cast<MultiRequestState *>(state);
533
710
std::list<RequestState *> requests;
535
712
if (response->errorCode != BASICHTTP_ERROR_NONE
536
713
|| !HTTP_IS_SUCCESS(response->responseCode)) {
538
if (response->errorCode == BASICHTTP_ERROR_SSL_SECURITY) {
539
msg = Util::Format(_("SSL Security Error."));
541
msg = Util::Format(_("Could not connect to server."));
544
714
Log("Could not connect to server. (BasicHttp error=%u, response=%ld)\n",
545
response->errorCode, response->responseCode);
546
state->onAbort(false, Util::exception(msg));
715
response->errorCode, response->responseCode);
717
* If alwaysDispatchResponse is true, dispatch response without a node and
718
* with an empty Result object. Only call abort slot if dispatch response
719
* somehow does not process response.
722
if (state->alwaysDispatchResponse) {
723
doAbort = !(that->ResponseDispatch(NULL, *state, result));
726
InvokeAbortOnConnectError(response->errorCode,
727
response->responseCode, state);
730
915
BaseXml::CancelRequests()
917
// Remove any pending completed responses.
918
Poll_CallbackRemove(POLL_CS_MAIN, 0, OnIdleProcessResponses, this,
921
std::list<RequestState*> &pendingRequests = mMulti ? mMulti->requests
732
924
std::list<Util::AbortSlot> slots;
734
926
* It is extremely likely that an onAbort() handler will delete
735
927
* this object, which will re-enter here and double-free things, so
736
928
* clear the list, and then call the abort handlers.
738
for (std::list<RequestState *>::iterator i = mActiveRequests.begin();
739
i != mActiveRequests.end(); i++) {
930
for (std::list<RequestState *>::iterator i = pendingRequests.begin();
931
i != pendingRequests.end(); i++) {
740
932
BasicHttp_FreeRequest((*i)->request);
741
933
slots.push_back((*i)->onAbort);
744
mActiveRequests.clear();
936
pendingRequests.clear();
745
940
Log("Cancelling %d %s XML requests.\n", (int)slots.size(),
746
941
mDocElementName.c_str());
747
942
for (std::list<Util::AbortSlot>::iterator i = slots.begin();
1056
1251
// NOTE: We get a 404 if we access "/<base name>/xml/"
1057
Util::string url = Util::Format("%s://%s:%d/%s/xml",
1252
Util::string url = Util::Format("%s://%s:%hu/%s/xml",
1058
1253
mSecure ? "https" : "http",
1059
1254
mHostname.c_str(), mPort,
1060
1255
mDocElementName.c_str());
1063
1258
Warning("BROKER REQUEST: %s\n", CensorXml(body).c_str());
1084
1279
BasicHttp_SetSslCtxProc(req->request, OnSslCtx);
1281
if (req->proxy.empty()) {
1282
CdkProxyType proxyType = CDK_PROXY_NONE;
1283
char *proxy = CdkProxy_GetProxyForUrl(url.c_str(), &proxyType);
1285
switch (proxyType) {
1286
case CDK_PROXY_HTTP:
1287
req->proxyType = BASICHTTP_PROXY_HTTP;
1289
case CDK_PROXY_SOCKS4:
1290
req->proxyType = BASICHTTP_PROXY_SOCKS4;
1299
req->proxyType = BASICHTTP_PROXY_NONE;
1086
1302
if (req->proxyType != BASICHTTP_PROXY_NONE) {
1087
1303
ASSERT(!req->proxy.empty());
1088
1304
BasicHttp_SetProxy(req->request, req->proxy.c_str(), req->proxyType);
1307
BasicHttp_SetConnectTimeout(req->request, CalculateConnectTimeout(req));
1091
1309
for (size_t i = 0; i < req->extraHeaders.size(); i++) {
1092
1310
BasicHttp_AppendRequestHeader(req->request,
1093
1311
req->extraHeaders[i].c_str());
1133
1351
NOT_IMPLEMENTED();
1356
*-----------------------------------------------------------------------------
1358
* cdk::BaseXml::CalculateConnectTimeout --
1360
* Calculates the minimum request timeout of all the requests in a multi-request.
1363
* The timeout to be used for the entire multi-rpc. 0 implies no timeout.
1368
*-----------------------------------------------------------------------------
1372
BaseXml::CalculateConnectTimeout(const cdk::BaseXml::RequestState *req) // IN:
1375
unsigned long timeoutSec = 0;
1377
if (const MultiRequestState *multiReq =
1378
dynamic_cast<const MultiRequestState *>(req)) {
1380
* This is a multi-request.
1381
* Compute the minimum non-zero timeout of all the requests in the multi-request
1383
BOOST_FOREACH(const RequestState *reqState, multiReq->requests) {
1384
if (reqState->connectTimeoutSec != 0) {
1385
timeoutSec = timeoutSec == 0 ? reqState->connectTimeoutSec
1386
: std::min(timeoutSec,
1387
reqState->connectTimeoutSec);
1391
// Uni-request. Simply return the request timeout from reqState.
1392
timeoutSec = req->connectTimeoutSec;
1137
1400
*-----------------------------------------------------------------------------