~ubuntu-branches/ubuntu/maverick/vmware-view-open-client/maverick

« back to all changes in this revision

Viewing changes to baseXml.cc

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2010-06-04 17:45:04 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20100604174504-zjltuc0hdp4mv7de
Tags: 4.5.0-264434+dfsg-1
* Merging upstream version 4.5.0-264434+dfsg.
* Updating date and version header in manpage.
* Rediffing doc-pdf.patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
 
31
31
 
32
32
#include <boost/bind.hpp>
 
33
#include <boost/foreach.hpp>
33
34
#include <gmodule.h>
34
35
#include <libxml/parser.h>
35
36
#include <libxml/xmlsave.h>
 
37
#include <algorithm>
36
38
#include <list>
37
39
 
38
 
#ifdef _WIN32
 
40
#if defined(_WIN32) && !defined(__MINGW32__)
39
41
#define _(String) (String)
40
 
#else
41
 
#include <glib/gi18n.h>
 
42
#define NOMINMAX
42
43
#endif
43
44
 
44
45
 
45
46
#include "baseXml.hh"
 
47
#include "cdkProxy.h"
46
48
 
47
49
 
48
50
#define XML_V1_HDR "<?xml version=\"1.0\"?>"
77
79
     mPort(port),
78
80
     mSecure(secure),
79
81
     mCookieJar(BasicHttp_CreateCookieJar()),
80
 
     mVersion(VERSION_4),
 
82
     mVersion(VERSION_4_5),
81
83
     mMulti(NULL),
82
84
     mResetWatch(NULL),
83
85
     mDocElementName(docName),
220
222
 *       Get the int content from a named child node.
221
223
 *
222
224
 * Results:
223
 
 *       Integer value or -1 if invalid content or empty.
 
225
 *       Integer value or 0 if invalid content or empty.
224
226
 *
225
227
 * Side effects:
226
228
 *       None.
234
236
{
235
237
   Util::string strval = GetChildContent(parentNode, targetName);
236
238
   if (strval.empty()) {
237
 
      return -1;
 
239
      return 0;
238
240
   }
239
241
   return strtol(strval.c_str(), NULL, 10);
240
242
}
295
297
 
296
298
   result = GetChildContent(parentNode, "result");
297
299
   if (result.empty()) {
298
 
      onAbort(false, Util::exception(_("Invalid response: "
299
 
                                       "Invalid \"result\" in XML.")));
 
300
      onAbort(false, Util::exception(_("Invalid response"), "",
 
301
                                     _("Invalid \"result\" in XML.")));
300
302
      return false;
301
303
   }
302
304
 
319
321
         onAbort(false, Util::exception(errorMessage, errorCode));
320
322
      } else {
321
323
         onAbort(false, Util::exception(Util::Format(_("Unknown error: %s"),
322
 
                                                     errorCode.c_str()),
 
324
                                                       errorCode.c_str()),
323
325
                                        errorCode));
324
326
      }
325
327
      return false;
335
337
 * cdk::BaseXml::Param::Parse --
336
338
 *
337
339
 *       Parse a <param> node parentNode containing a name element and
338
 
 *       possibly multiple value elements.
 
340
 *       zero or more value elements.
339
341
 *
340
342
 * Results:
341
343
 *       true if parsed successfully, false otherwise and the onAbort handler
353
355
{
354
356
   name = GetChildContent(parentNode, "name");
355
357
   if (name.empty()) {
356
 
      onAbort(false, Util::exception(_("Invalid response: "
357
 
                                       "Parameter with no name.")));
 
358
      onAbort(false, Util::exception(_("Invalid response"), "",
 
359
                                     _("Parameter with no name.")));
358
360
      return false;
359
361
   }
360
362
 
478
480
/*
479
481
 *-----------------------------------------------------------------------------
480
482
 *
 
483
 * cdk::BaseXml::InvokeAbortOnConnectError --
 
484
 *
 
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
 
488
 *      the RequestState.
 
489
 *
 
490
 * Results:
 
491
 *      None
 
492
 *
 
493
 * Side effects:
 
494
 *      None
 
495
 *
 
496
 *-----------------------------------------------------------------------------
 
497
 */
 
498
 
 
499
void
 
500
BaseXml::InvokeAbortOnConnectError(BasicHttpErrorCode errorCode,       // IN
 
501
                                   BasicHttpResponseCode responseCode, // IN
 
502
                                   RequestState *state)                // IN
 
503
{
 
504
   Util::string code;
 
505
   Util::string detail;
 
506
 
 
507
#define ERR_CASE(c, d) case c: code = #c; detail = d; break
 
508
 
 
509
   /*
 
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.
 
513
    */
 
514
   if (errorCode == BASICHTTP_ERROR_NONE && !HTTP_IS_SUCCESS(responseCode)) {
 
515
      errorCode = BASICHTTP_ERROR_HTTP_RETURNED_ERROR;
 
516
   }
 
517
 
 
518
   switch (errorCode) {
 
519
   case BASICHTTP_ERROR_NONE:
 
520
      NOT_REACHED();
 
521
      break;
 
522
      ERR_CASE(BASICHTTP_ERROR_UNSUPPORTED_PROTOCOL,
 
523
               _("Unsupported protocol"));
 
524
      ERR_CASE(BASICHTTP_ERROR_URL_MALFORMAT,
 
525
               _("Invalid URL"));
 
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"));
 
540
 
 
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"));
 
546
 
 
547
   default:
 
548
      /* generic error. */
 
549
      ERR_CASE(BASICHTTP_ERROR_GENERIC,
 
550
               _("Unknown error"));
 
551
   }
 
552
 
 
553
#undef ERR_CASE
 
554
 
 
555
   state->onAbort(
 
556
      false,
 
557
      Util::exception(
 
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())));
 
563
}
 
564
 
 
565
 
 
566
/*
 
567
 *-----------------------------------------------------------------------------
 
568
 *
481
569
 * cdk::BaseXml::OnResponse --
482
570
 *
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
 
574
 *      another RPC.
485
575
 *
486
576
 * Results:
487
577
 *      None
488
578
 *
489
579
 * Side effects:
490
 
 *      Frees the BasicHttpRequest.
 
580
 *      None
491
581
 *
492
582
 *-----------------------------------------------------------------------------
493
583
 */
497
587
                    BasicHttpResponse *response, // IN
498
588
                    void *data)                  // IN
499
589
{
500
 
   BaseXml *that = reinterpret_cast<BaseXml*>(data);
501
 
   ASSERT(that);
 
590
   BaseXml *that = reinterpret_cast<BaseXml *>(data);
 
591
   ASSERT(that);
 
592
 
 
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,
 
599
                             POLL_REALTIME);
 
600
         Poll_Callback(POLL_CS_MAIN, 0, OnIdleProcessResponses, that,
 
601
                       POLL_REALTIME, 0, NULL);
 
602
         break;
 
603
      }
 
604
   }
 
605
}
 
606
 
 
607
 
 
608
/*
 
609
 *-----------------------------------------------------------------------------
 
610
 *
 
611
 * cdk::BaseXml::OnIdleProcessResponses --
 
612
 *
 
613
 *      Process any pending responses (probably at most one).
 
614
 *
 
615
 * Results:
 
616
 *      None
 
617
 *
 
618
 * Side effects:
 
619
 *      None
 
620
 *
 
621
 *-----------------------------------------------------------------------------
 
622
 */
 
623
 
 
624
void
 
625
BaseXml::OnIdleProcessResponses(void *data) // IN
 
626
{
 
627
   BaseXml *that = reinterpret_cast<BaseXml *>(data);
 
628
   ASSERT(that);
 
629
 
 
630
   std::list<RequestState *>::iterator i = that->mActiveRequests.begin();
 
631
   while (i != that->mActiveRequests.end()) {
 
632
      RequestState *state = *i;
 
633
      if (!state->response) {
 
634
         ++i;
 
635
      } else {
 
636
         i = that->mActiveRequests.erase(i);
 
637
         bool wasDeleted = that->ProcessResponse(state);
 
638
         delete state;
 
639
         if (wasDeleted) {
 
640
            break;
 
641
         }
 
642
      }
 
643
   }
 
644
}
 
645
 
 
646
 
 
647
/*
 
648
 *-----------------------------------------------------------------------------
 
649
 *
 
650
 * cdk::BaseXml::ProcessResponse --
 
651
 *
 
652
 *      Parse an XML API response based on the response operation.  Invokes the
 
653
 *      onAbort/onDone handler passed to the initial request.
 
654
 *
 
655
 * Results:
 
656
 *      TRUE if no more responses should be processed.
 
657
 *
 
658
 * Side effects:
 
659
 *      Callbacks called from this function may have deleted this
 
660
 *      object before they return.
 
661
 *
 
662
 *-----------------------------------------------------------------------------
 
663
 */
 
664
 
 
665
bool
 
666
BaseXml::ProcessResponse(RequestState *state) // IN
 
667
{
 
668
   // XXX: keep code churn down (this was originally static)
 
669
   BaseXml *that = this;
 
670
 
 
671
   BasicHttpRequest *request = state->request;
 
672
   BasicHttpResponse *response = state->response;
502
673
 
503
674
   xmlDoc *doc = NULL;
504
675
   xmlNode *docNode;
509
680
 
510
681
   that->mRequestId++;
511
682
 
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) {
516
 
         state = *i;
517
 
         that->mActiveRequests.erase(i);
518
 
         break;
519
 
      }
520
 
   }
521
 
 
522
683
   if (that->mResetWatch) {
523
684
      resetWatch = that->mResetWatch;
524
685
   } else {
525
686
      that->mResetWatch = resetWatch;
526
687
   }
527
688
 
528
 
   ASSERT(state->request == request);
529
 
   state->request = request;
530
 
   state->response = response;
 
689
   /*
 
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.
 
693
    */
 
694
#if !defined(_WIN32) || defined(__MINGW32__)
 
695
   if (response->effectiveURL) {
 
696
      unsigned short port;
 
697
      bool secure;
 
698
 
 
699
      Util::string host =
 
700
         Util::ParseHostLabel(response->effectiveURL, &port, &secure);
 
701
      if (!host.empty()) {
 
702
         mHostname = host;
 
703
         mPort = port;
 
704
         mSecure = secure;
 
705
      }
 
706
   }
 
707
#endif // !defined(_WIN32) || defined(__MINGW32)
531
708
 
532
709
   MultiRequestState *multi = dynamic_cast<MultiRequestState *>(state);
533
710
   std::list<RequestState *> requests;
534
711
 
535
712
   if (response->errorCode != BASICHTTP_ERROR_NONE
536
713
       || !HTTP_IS_SUCCESS(response->responseCode)) {
537
 
      Util::string msg;
538
 
      if (response->errorCode == BASICHTTP_ERROR_SSL_SECURITY) {
539
 
         msg = Util::Format(_("SSL Security Error."));
540
 
      } else {
541
 
         msg = Util::Format(_("Could not connect to server."));
542
 
      }
543
 
 
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);
 
716
      /*
 
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.
 
720
       */
 
721
      bool doAbort = true;
 
722
      if (state->alwaysDispatchResponse) {
 
723
         doAbort = !(that->ResponseDispatch(NULL, *state, result));
 
724
      }
 
725
      if (doAbort) {
 
726
         InvokeAbortOnConnectError(response->errorCode,
 
727
                                   response->responseCode, state);
 
728
      }
547
729
      goto exit;
548
730
   }
549
731
 
572
754
      Log("%s XML general error: %s\n", that->mDocElementName.c_str(),
573
755
          errCode.c_str());
574
756
      if (result.Parse(docNode, state->onAbort)) {
575
 
         state->onAbort(false, Util::exception(_("Invalid response: "
576
 
                                                 "General error.")));
 
757
         state->onAbort(false, Util::exception(_("Invalid response"), "",
 
758
                                               _("General error.")));
577
759
      }
578
760
      goto exit;
579
761
   }
667
849
         that->mResetWatch = NULL;
668
850
      }
669
851
      BasicHttp_FreeRequest(request);
 
852
      state->request = NULL;
670
853
      BasicHttp_FreeResponse(response);
 
854
      state->response = NULL;
671
855
   }
672
856
   xmlFreeDoc(doc);
673
 
   delete state;
 
857
 
 
858
   return *resetWatch;
674
859
}
675
860
 
676
861
 
729
914
int
730
915
BaseXml::CancelRequests()
731
916
{
 
917
   // Remove any pending completed responses.
 
918
   Poll_CallbackRemove(POLL_CS_MAIN, 0, OnIdleProcessResponses, this,
 
919
                       POLL_REALTIME);
 
920
 
 
921
   std::list<RequestState*> &pendingRequests = mMulti ? mMulti->requests
 
922
                                                      : mActiveRequests;
 
923
 
732
924
   std::list<Util::AbortSlot> slots;
733
925
   /*
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.
737
929
    */
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);
742
934
      delete *i;
743
935
   }
744
 
   mActiveRequests.clear();
 
936
   pendingRequests.clear();
 
937
   delete mMulti;
 
938
   mMulti = NULL;
 
939
 
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();
1054
1249
#endif
1055
1250
 
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());
1061
1256
 
1062
 
#ifdef  VMX86_DEBUG
 
1257
#ifdef VMX86_DEBUG
1063
1258
   Warning("BROKER REQUEST: %s\n", CensorXml(body).c_str());
1064
1259
#endif
1065
1260
 
1083
1278
 
1084
1279
   BasicHttp_SetSslCtxProc(req->request, OnSslCtx);
1085
1280
 
 
1281
   if (req->proxy.empty()) {
 
1282
      CdkProxyType proxyType = CDK_PROXY_NONE;
 
1283
      char *proxy = CdkProxy_GetProxyForUrl(url.c_str(), &proxyType);
 
1284
      if (proxy) {
 
1285
         switch (proxyType) {
 
1286
         case CDK_PROXY_HTTP:
 
1287
            req->proxyType = BASICHTTP_PROXY_HTTP;
 
1288
            break;
 
1289
         case CDK_PROXY_SOCKS4:
 
1290
            req->proxyType = BASICHTTP_PROXY_SOCKS4;
 
1291
            break;
 
1292
         default:
 
1293
            NOT_REACHED();
 
1294
            break;
 
1295
         }
 
1296
         req->proxy = proxy;
 
1297
         free(proxy);
 
1298
      } else {
 
1299
         req->proxyType = BASICHTTP_PROXY_NONE;
 
1300
      }
 
1301
   }
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);
1089
1305
   }
1090
1306
 
 
1307
   BasicHttp_SetConnectTimeout(req->request, CalculateConnectTimeout(req));
 
1308
 
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();
1134
1352
}
1135
1353
 
 
1354
 
 
1355
/*
 
1356
 *-----------------------------------------------------------------------------
 
1357
 *
 
1358
 *  cdk::BaseXml::CalculateConnectTimeout --
 
1359
 *
 
1360
 *     Calculates the minimum request timeout of all the requests in a multi-request.
 
1361
 *
 
1362
 * Results:
 
1363
 *     The timeout to be used for the entire multi-rpc. 0 implies no timeout.
 
1364
 *
 
1365
 * Side effects:
 
1366
 *     None.
 
1367
 *
 
1368
 *-----------------------------------------------------------------------------
 
1369
 */
 
1370
 
 
1371
unsigned long
 
1372
BaseXml::CalculateConnectTimeout(const cdk::BaseXml::RequestState *req)  // IN:
 
1373
   const
 
1374
{
 
1375
   unsigned long timeoutSec = 0;
 
1376
 
 
1377
   if (const MultiRequestState *multiReq =
 
1378
         dynamic_cast<const MultiRequestState *>(req)) {
 
1379
      /*
 
1380
       * This is a multi-request.
 
1381
       * Compute the minimum non-zero timeout of all the requests in the multi-request
 
1382
       */
 
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);
 
1388
         }
 
1389
      }
 
1390
   } else {
 
1391
      // Uni-request. Simply return the request timeout from reqState.
 
1392
      timeoutSec = req->connectTimeoutSec;
 
1393
   }
 
1394
 
 
1395
   return timeoutSec;
 
1396
}
 
1397
 
 
1398
 
1136
1399
/*
1137
1400
 *-----------------------------------------------------------------------------
1138
1401
 *
1168
1431
 *     Get the uint64 content from a named child node.
1169
1432
 *
1170
1433
 * Results:
1171
 
 *     Integer value or -1 if invalid content or empty.
 
1434
 *     Integer value or 0 if invalid content or empty.
1172
1435
 *
1173
1436
 * Side effects:
1174
1437
 *     None.
1181
1444
{
1182
1445
   Util::string strVal = GetChildContent(parentNode, targetName);
1183
1446
   if (strVal.empty()) {
1184
 
      return -1;
 
1447
      return 0;
1185
1448
   }
1186
1449
 
1187
1450
   return g_ascii_strtoull(strVal.c_str(), NULL, 10);
1205
1468
 *
1206
1469
 *-----------------------------------------------------------------------------
1207
1470
 */
1208
 
#ifdef VMX86_DEBUG
 
1471
#ifdef  VMX86_DEBUG
1209
1472
Util::string
1210
1473
BaseXml::CensorXml(const Util::string &xmlStr) // IN
1211
1474
{
1212
1475
    Util::string censored;
1213
1476
 
1214
 
    if (xmlStr.empty()) {
 
1477
    if (xmlStr.c_str()[0] == '\0') {
1215
1478
        return censored;
1216
1479
    }
1217
1480
 
1219
1482
 
1220
1483
    static const char *params[] = {
1221
1484
                                    "<name>password</name>",
 
1485
                                    "<name>passcode</name>",
1222
1486
                                    "<name>pin",
1223
1487
                                    "<name>smartCardPIN</name>"
1224
1488
    };