(file) Return to WsmRequestDecoder.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / WsmServer

   1 martin 1.5 //%LICENSE////////////////////////////////////////////////////////////////
   2 martin 1.6 //
   3 martin 1.5 // Licensed to The Open Group (TOG) under one or more contributor license
   4            // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
   5            // this work for additional information regarding copyright ownership.
   6            // Each contributor licenses this file to you under the OpenPegasus Open
   7            // Source License; you may not use this file except in compliance with the
   8            // License.
   9 martin 1.6 //
  10 martin 1.5 // Permission is hereby granted, free of charge, to any person obtaining a
  11            // copy of this software and associated documentation files (the "Software"),
  12            // to deal in the Software without restriction, including without limitation
  13            // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  14            // and/or sell copies of the Software, and to permit persons to whom the
  15            // Software is furnished to do so, subject to the following conditions:
  16 martin 1.6 //
  17 martin 1.5 // The above copyright notice and this permission notice shall be included
  18            // in all copies or substantial portions of the Software.
  19 martin 1.6 //
  20 martin 1.5 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  21 martin 1.6 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22 martin 1.5 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  23            // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  24            // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  25            // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  26            // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27 martin 1.6 //
  28 martin 1.5 //////////////////////////////////////////////////////////////////////////
  29 kumpf  1.2 //
  30            //%////////////////////////////////////////////////////////////////////////////
  31            
  32            #include <cctype>
  33            #include <cstdio>
  34            #include <Pegasus/Common/Config.h>
  35            #include <Pegasus/Common/XmlParser.h>
  36            #include <Pegasus/Common/Tracer.h>
  37            #include <Pegasus/Common/CommonUTF.h>
  38            #include <Pegasus/Common/MessageLoader.h>
  39            #include <Pegasus/Common/AutoPtr.h>
  40 mike   1.12 #include <Pegasus/Common/SharedPtr.h>
  41 kumpf  1.2  
  42             #include "WsmConstants.h"
  43             #include "WsmReader.h"
  44             #include "WsmWriter.h"
  45             #include "WsmProcessor.h"
  46             #include "WsmRequestDecoder.h"
  47             
  48             PEGASUS_NAMESPACE_BEGIN
  49             
  50 mike   1.12 static bool _parseInvokeAction(
  51                 const String& action,
  52                 String& className,
  53                 String& methodName)
  54             {
  55                 // Parse the action as though it is a method invocation. If so, set
  56                 // className and methodName and return true. Else return false. Invoke
  57                 // actions have the following form:
  58                 //
  59                 //     http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/<CLASS>/<METHOD>
  60             
  61                 // Expect "http://" prefix.
  62             
  63                 CString cstr = action.getCString();
  64                 const char* p = cstr;
  65             
  66                 if (strncmp(p, "http://", 7) != 0)
  67                     return false;
  68             
  69                 p += 7;
  70             
  71 mike   1.12     // Find slash that terminates the host name.
  72             
  73                 if (!(p = strchr(p, '/')))
  74                     return false;
  75             
  76                 p++;
  77             
  78                 // Expect "wbem/wscim/1/cim-schema/2/" sequence.
  79             
  80                 if (strncmp(p, "wbem/wscim/1/cim-schema/2/", 26) != 0)
  81                     return false;
  82             
  83                 p += 26;
  84             
  85                 // Get classname:
  86             
  87                 char* slash = strchr(const_cast<char*>(p), '/');
  88             
  89                 if (!slash)
  90                     return false;
  91             
  92 mike   1.12     *slash = '\0';
  93                 className = p;
  94                 *slash = '/';
  95                 p = slash + 1;
  96             
  97                 // Get methodname:
  98             
  99                 methodName = p;
 100             
 101                 // If we got this far, then action refers to a method.
 102                 return true;
 103             }
 104             
 105 kumpf  1.2  WsmRequestDecoder::WsmRequestDecoder(WsmProcessor* wsmProcessor)
 106 sahana.prabhakar 1.11     : MessageQueue(PEGASUS_QUEUENAME_WSMREQDECODER),
 107 kumpf            1.2        _wsmProcessor(wsmProcessor),
 108                             _serverTerminating(false)
 109                       {
 110                       }
 111                       
 112                       WsmRequestDecoder::~WsmRequestDecoder()
 113                       {
 114                       }
 115                       
 116                       void WsmRequestDecoder::sendResponse(
 117                           Uint32 queueId,
 118                           Buffer& message,
 119                           Boolean httpCloseConnect)
 120                       {
 121                           MessageQueue* queue = MessageQueue::lookup(queueId);
 122                       
 123                           if (queue)
 124                           {
 125                               AutoPtr<HTTPMessage> httpMessage(new HTTPMessage(message));
 126                               httpMessage->setCloseConnect(httpCloseConnect);
 127                               queue->enqueue(httpMessage.release());
 128 kumpf            1.2      }
 129                       }
 130                       
 131                       void WsmRequestDecoder::sendHttpError(
 132                           Uint32 queueId,
 133                           const String& status,
 134                           const String& cimError,
 135                           const String& pegasusError,
 136                           Boolean httpCloseConnect)
 137                       {
 138                           Buffer message;
 139                           message = WsmWriter::formatHttpErrorRspMessage(
 140                               status,
 141                               cimError,
 142                               pegasusError);
 143                       
 144                           sendResponse(queueId, message, httpCloseConnect);
 145                       }
 146                       
 147                       void WsmRequestDecoder::handleEnqueue(Message* message)
 148                       {
 149 kumpf            1.2      PEGASUS_ASSERT(message);
 150                           PEGASUS_ASSERT(message->getType() == HTTP_MESSAGE);
 151                       
 152                           handleHTTPMessage((HTTPMessage*)message);
 153                       
 154                           delete message;
 155                       }
 156                       
 157                       void WsmRequestDecoder::handleEnqueue()
 158                       {
 159                           Message* message = dequeue();
 160                           if (message)
 161                               handleEnqueue(message);
 162                       }
 163                       
 164                       //-----------------------------------------------------------------------------
 165                       //
 166                       // From the HTTP/1.1 Specification (RFC 2626):
 167                       //
 168                       // Both types of message consist of a start-line, zero or more header fields
 169                       // (also known as "headers"), an empty line (i.e., a line with nothing
 170 kumpf            1.2  // preceding the CRLF) indicating the end of the header fields, and possibly
 171                       // a message-body.
 172                       //
 173                       //-----------------------------------------------------------------------------
 174                       void WsmRequestDecoder::handleHTTPMessage(HTTPMessage* httpMessage)
 175                       {
 176                           PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmRequestDecoder::handleHTTPMessage()");
 177                       
 178                           // Set the Accept-Language into the thread for this service.
 179                           // This will allow all code in this thread to get
 180                           // the languages for the messages returned to the client.
 181                           Thread::setLanguages(httpMessage->acceptLanguages);
 182                       
 183                           // Save queueId:
 184                           Uint32 queueId = httpMessage->queueId;
 185                       
 186                           // Save userName and authType:
 187                           String userName;
 188                           String authType;
 189                           Boolean httpCloseConnect = httpMessage->getCloseConnect();
 190                       
 191 marek            1.3      PEG_TRACE((TRC_WSMSERVER, Tracer::LEVEL4,
 192 kumpf            1.2          "WsmRequestDecoder::handleHTTPMessage()- "
 193                                   "httpMessage->getCloseConnect() returned %d",
 194                               httpCloseConnect));
 195                       
 196                           userName = httpMessage->authInfo->getAuthenticatedUser();
 197                           authType = httpMessage->authInfo->getAuthType();
 198                       
 199                           // Parse the HTTP message:
 200                           String startLine;
 201                           Array<HTTPHeader> headers;
 202                           char* content;
 203                           Uint32 contentLength;
 204                       
 205                           httpMessage->parse(startLine, headers, contentLength);
 206                       
 207                           // Parse the request line:
 208                           String methodName;
 209                           String requestUri;
 210                           String httpVersion;
 211                           HttpMethod httpMethod = HTTP_METHOD__POST;
 212                       
 213 kumpf            1.2      HTTPMessage::parseRequestLine(
 214                               startLine, methodName, requestUri, httpVersion);
 215                       
 216                           //  Set HTTP method for the request
 217                           if (methodName == "M-POST")
 218                           {
 219                               httpMethod = HTTP_METHOD_M_POST;
 220                           }
 221                       
 222                           // Unsupported methods are caught in the HTTPAuthenticatorDelegator
 223                           PEGASUS_ASSERT(methodName == "M-POST" || methodName == "POST");
 224                       
 225                           //  Mismatch of method and version is caught in HTTPAuthenticatorDelegator
 226                           PEGASUS_ASSERT(!((httpMethod == HTTP_METHOD_M_POST) &&
 227                                            (httpVersion == "HTTP/1.0")));
 228                       
 229                           // Process M-POST and POST messages:
 230                           if (httpVersion == "HTTP/1.1")
 231                           {
 232                               // Validate the presence of a "Host" header.  The HTTP/1.1
 233                               // specification says this in section 14.23 regarding the Host
 234 kumpf            1.2          // header field:
 235                               //
 236                               //     All Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad
 237                               //     Request) status code to any HTTP/1.1 request message which lacks
 238                               //     a Host header field.
 239                               //
 240                               // Note:  The Host header value is not validated.
 241                       
 242 kumpf            1.8          const char* hostHeader;
 243 kumpf            1.2          Boolean hostHeaderFound = HTTPMessage::lookupHeader(
 244                                   headers, "Host", hostHeader, false);
 245                       
 246                               if (!hostHeaderFound)
 247                               {
 248                                   MessageLoaderParms parms(
 249                                       "Server.WsmRequestDecoder.MISSING_HOST_HEADER",
 250                                       "HTTP request message lacks a Host header field.");
 251                                   sendHttpError(
 252                                       queueId,
 253                                       HTTP_STATUS_BADREQUEST,
 254                                       "",
 255                                       MessageLoader::getMessage(parms),
 256                                       httpCloseConnect);
 257                                   PEG_METHOD_EXIT();
 258                                   return;
 259                               }
 260                           }
 261                       
 262                           // Calculate the beginning of the content from the message size and
 263                           // the content length.
 264 kumpf            1.2      content = (char*) httpMessage->message.getData() +
 265                               httpMessage->message.size() - contentLength;
 266                       
 267 mike             1.12     // Lookup HTTP "User-Agent" header. For example:
 268                           //
 269                           //     User-Agent: Microsoft WinRM Client
 270                           //
 271                           // If it contains "WinRM", then omit the XML processing instruction from
 272                           // the response (first line of XML response). A typical XML processing
 273                           // instruction looks like this:
 274                           //
 275                           //     <?xml version="1.0" encoding="utf-8"?>
 276                           //
 277                           // The WinRM user agent should never receive this line.
 278                       
 279                           Boolean omitXMLProcessingInstruction;
 280                           {
 281                               String value;
 282                       
 283                               if (HTTPMessage::lookupHeader(headers, "User-Agent", value, true) &&
 284                                   value.find("WinRM") != Uint32(-1))
 285                               {
 286                                   omitXMLProcessingInstruction = true;
 287                               }
 288 mike             1.12         else
 289                               {
 290                                   omitXMLProcessingInstruction = false;
 291                               }
 292                           }
 293                       
 294 kumpf            1.2      // Validate the "Content-Type" header:
 295 kumpf            1.8      const char* contentType;
 296 kumpf            1.2      Boolean contentTypeHeaderFound = HTTPMessage::lookupHeader(
 297                               headers, "Content-Type", contentType, true);
 298                           String type;
 299                           String charset;
 300                       
 301                           if (!contentTypeHeaderFound ||
 302                               !HTTPMessage::parseContentTypeHeader(contentType, type, charset) ||
 303                               (!String::equalNoCase(type, "application/soap+xml") &&
 304                                !String::equalNoCase(type, "text/xml")))
 305                           {
 306                               MessageLoaderParms parms(
 307                                   "Server.WsmRequestDecoder.CONTENTTYPE_SYNTAX_ERROR",
 308                                   "HTTP Content-Type header error.");
 309                               sendHttpError(
 310                                   queueId,
 311                                   HTTP_STATUS_BADREQUEST,
 312                                   "",
 313                                   MessageLoader::getMessage(parms),
 314                                   httpCloseConnect);
 315                               PEG_METHOD_EXIT();
 316                               return;
 317 kumpf            1.2      }
 318                       
 319 mike             1.12     if (String::equalNoCase(charset, "utf-16"))
 320                           {
 321                               // Reject utf-16 requests.
 322                               WsmFault fault(
 323                                   WsmFault::wsman_EncodingLimit,
 324                                   "UTF-16 is not supported; Please use UTF-8",
 325                                   ContentLanguageList(),
 326                                   WSMAN_FAULTDETAIL_CHARACTERSET);
 327                                _wsmProcessor->sendResponse(new WsmFaultResponse(
 328                                    String::EMPTY, queueId, httpMethod, httpCloseConnect,
 329                                       omitXMLProcessingInstruction, fault));
 330                                PEG_METHOD_EXIT();
 331                                return;
 332                           }
 333                       
 334 kumpf            1.2      if (!String::equalNoCase(charset, "utf-8"))
 335                           {
 336                               // DSP0226 R13.1-5:  A service shall emit Responses using the same
 337                               // encoding as the original request. If the service does not support
 338                               // the requested encoding or cannot determine the encoding, it should
 339                               // use UTF-8 encoding to return a wsman:EncodingLimit fault with the
 340                               // following detail code:
 341                               // http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/CharacterSet
 342                       
 343                               WsmFault fault(
 344                                   WsmFault::wsman_EncodingLimit,
 345                                   String::EMPTY,
 346                                   ContentLanguageList(),
 347                                   WSMAN_FAULTDETAIL_CHARACTERSET);
 348                                _wsmProcessor->sendResponse(new WsmFaultResponse(
 349 mike             1.12               String::EMPTY, queueId, httpMethod, httpCloseConnect,
 350                                     omitXMLProcessingInstruction, fault));
 351 kumpf            1.2           PEG_METHOD_EXIT();
 352                                return;
 353                           }
 354                       
 355                           // SoapAction header is optional, but if present, it must match
 356                           // the content of <wsa:Action>
 357                           String soapAction;
 358                           HTTPMessage::lookupHeader(headers, "SOAPAction", soapAction, true);
 359                       
 360                           // Remove the quotes around the SOAPAction value
 361                           if ((soapAction.size() > 1) &&
 362                               (soapAction[0] == '\"') &&
 363                               (soapAction[soapAction.size()-1] == '\"'))
 364                           {
 365                               soapAction = soapAction.subString(1, soapAction.size() - 2);
 366                           }
 367                       
 368                           // Validating content falls within UTF8
 369                           // (required to be compliant with section C12 of Unicode 4.0 spec,
 370                           // chapter 3.)
 371                           Uint32 count = 0;
 372 kumpf            1.2      while (count < contentLength)
 373                           {
 374                               if (!(isUTF8((char*) &content[count])))
 375                               {
 376                                   MessageLoaderParms parms(
 377                                       "Server.WsmRequestDecoder.INVALID_UTF8_CHARACTER",
 378                                       "Invalid UTF-8 character detected.");
 379                                   sendHttpError(
 380                                       queueId,
 381                                       HTTP_STATUS_BADREQUEST,
 382                                       "request-not-valid",
 383                                       MessageLoader::getMessage(parms),
 384                                       httpCloseConnect);
 385                       
 386                                   PEG_METHOD_EXIT();
 387                                   return;
 388                               }
 389                               UTF8_NEXT(content, count);
 390                           }
 391                       
 392                           handleWsmMessage(
 393 kumpf            1.2          queueId,
 394                               httpMethod,
 395                               content,
 396                               contentLength,
 397                               soapAction,
 398                               authType,
 399                               userName,
 400                               httpMessage->ipAddress,
 401                               httpMessage->acceptLanguages,
 402                               httpMessage->contentLanguages,
 403 mike             1.12         httpCloseConnect,
 404                               omitXMLProcessingInstruction);
 405 kumpf            1.2  
 406                           PEG_METHOD_EXIT();
 407                       }
 408                       
 409                       void WsmRequestDecoder::handleWsmMessage(
 410                           Uint32 queueId,
 411                           HttpMethod httpMethod,
 412                           char* content,
 413                           Uint32 contentLength,
 414                           String& soapAction,
 415                           const String& authType,
 416                           const String& userName,
 417                           const String& ipAddress,
 418                           const AcceptLanguageList& httpAcceptLanguages,
 419                           const ContentLanguageList& httpContentLanguages,
 420 mike             1.12     Boolean httpCloseConnect,
 421                           Boolean omitXMLProcessingInstruction)
 422 kumpf            1.2  {
 423                           PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmRequestDecoder::handleWsmMessage()");
 424                       
 425 mike             1.12 
 426 kumpf            1.2      // If CIMOM is shutting down, return "Service Unavailable" response
 427                           if (_serverTerminating)
 428                           {
 429                               MessageLoaderParms parms(
 430                                   "Server.WsmRequestDecoder.CIMSERVER_SHUTTING_DOWN",
 431                                   "CIM Server is shutting down.");
 432                               sendHttpError(
 433                                   queueId,
 434                                   HTTP_STATUS_SERVICEUNAVAILABLE,
 435                                   String::EMPTY,
 436                                   MessageLoader::getMessage(parms),
 437                                   httpCloseConnect);
 438                               PEG_METHOD_EXIT();
 439                               return;
 440                           }
 441                       
 442                           WsmReader wsmReader(content);
 443                           XmlEntry entry;
 444                           AutoPtr<WsmRequest> request;
 445                           String wsaMessageId;
 446                       
 447 kumpf            1.2      // Process <?xml ... >
 448                           try
 449                           {
 450                               // These values are currently unused
 451                               const char* xmlVersion = 0;
 452                               const char* xmlEncoding = 0;
 453                       
 454                               // Note: WinRM does not send an XML declaration in its requests.
 455                               // This return value is ignored.
 456                               wsmReader.getXmlDeclaration(xmlVersion, xmlEncoding);
 457                       
 458                               // Decode the SOAP envelope
 459                       
 460                               wsmReader.expectStartTag(
 461                                   entry, WsmNamespaces::SOAP_ENVELOPE, "Envelope");
 462                       
 463                               String wsaAction;
 464                               String wsaFrom;
 465                               String wsaReplyTo;
 466                               String wsaFaultTo;
 467                               WsmEndpointReference epr;
 468 kumpf            1.2          Uint32 wsmMaxEnvelopeSize = 0;
 469                               AcceptLanguageList wsmLocale;
 470                               Boolean wsmRequestEpr = false;
 471 kumpf            1.4          Boolean wsmRequestItemCount = false;
 472 kumpf            1.2  
 473                               try
 474                               {
 475                                   wsmReader.decodeRequestSoapHeaders(
 476                                       wsaMessageId,
 477                                       epr.address,
 478                                       wsaAction,
 479                                       wsaFrom,
 480                                       wsaReplyTo,
 481                                       wsaFaultTo,
 482                                       epr.resourceUri,
 483                                       *epr.selectorSet,
 484                                       wsmMaxEnvelopeSize,
 485                                       wsmLocale,
 486 kumpf            1.4                  wsmRequestEpr,
 487                                       wsmRequestItemCount);
 488 kumpf            1.2          }
 489                               catch (XmlException&)
 490                               {
 491                                   // Do not treat this as an InvalidMessageInformationHeader fault.
 492                                   throw;
 493                               }
 494                               catch (Exception& e)
 495                               {
 496                                   throw WsmFault(
 497                                       WsmFault::wsa_InvalidMessageInformationHeader,
 498                                       e.getMessage(),
 499                                       e.getContentLanguages());
 500                               }
 501                       
 502 mike             1.12         // If no "Action" header was found, then this might still be a legal
 503                               // identify request.
 504                       
 505                               if (wsaAction.size() == 0 && _isIdentifyRequest(wsmReader))
 506                               {
 507                                   _sendIdentifyResponse(queueId);
 508                                   return;
 509                               }
 510                       
 511 kumpf            1.2          // Set the Locale language into the thread for processing this request.
 512                               Thread::setLanguages(wsmLocale);
 513                       
 514                               _checkRequiredHeader("wsa:To", epr.address.size());
 515                               _checkRequiredHeader("wsa:MessageID", wsaMessageId.size());
 516                               _checkRequiredHeader("wsa:Action", wsaAction.size());
 517                       
 518                               if (soapAction.size() && (soapAction != wsaAction))
 519                               {
 520                                   throw WsmFault(
 521                                       WsmFault::wsa_MessageInformationHeaderRequired,
 522                                       MessageLoaderParms(
 523                                           "WsmServer.WsmRequestDecoder.SOAPACTION_HEADER_MISMATCH",
 524                                           "The HTTP SOAPAction header value \"$0\" does not match "
 525                                               "the wsa:Action value \"$1\".",
 526                                           soapAction,
 527                                           wsaAction));
 528                               }
 529                       
 530                               // Note: The wsa:To header is not validated.  DSP0226 section 5.3
 531                               // indicates that this header is primarily useful for routing through
 532 kumpf            1.2          // intermediaries.  The HTTPAuthenticatorDelegator examines the path
 533                               // specified in the HTTP start line.
 534                       
 535                               // DSP0226 R5.3-1: The wsa:To header shall be present in all messages,
 536                               // whether requests, responses, or events. In the absence of other
 537                               // requirements, it is recommended that the network address for
 538                               // resources that require authentication be suffixed by the token
 539                               // sequence /wsman. If /wsman is used, unauthenticated access should
 540                               // not be allowed.
 541                               //     (1) <wsa:To> http://123.15.166.67/wsman </wsa:To>
 542                       
 543                               // DSP0226 R5.3-2: In the absence of other requirements, it is
 544                               // recommended that the network address for resources that do not
 545                               // require authentication be suffixed by the token sequence
 546                               // /wsman-anon. If /wsman-anon is used, authenticated access shall
 547                               // not be required.
 548                               //     (1) <wsa:To> http://123.15.166.67/wsman-anon </wsa:To>
 549                       
 550                               if (wsaReplyTo != WSM_ADDRESS_ANONYMOUS)
 551                               {
 552                                   // DSP0226 R5.4.2-2: A conformant service may require that all
 553 kumpf            1.2              // responses be delivered over the same connection on which the
 554                                   // request arrives.
 555                                   throw WsmFault(
 556                                       WsmFault::wsman_UnsupportedFeature,
 557                                       MessageLoaderParms(
 558                                           "WsmServer.WsmRequestDecoder.REPLYTO_ADDRESS_NOT_ANONYMOUS",
 559                                           "Responses may only be delivered over the same connection "
 560                                               "on which the request arrives."),
 561                                       WSMAN_FAULTDETAIL_ADDRESSINGMODE);
 562                               }
 563                       
 564                               if (wsaFaultTo.size() && (wsaFaultTo != WSM_ADDRESS_ANONYMOUS))
 565                               {
 566                                   // DSP0226 R5.4.3-3: A conformant service may require that all
 567                                   // faults be delivered to the client over the same transport or
 568                                   // connection on which the request arrives.
 569                                   throw WsmFault(
 570                                       WsmFault::wsman_UnsupportedFeature,
 571                                       MessageLoaderParms(
 572                                           "WsmServer.WsmRequestDecoder.FAULTTO_ADDRESS_NOT_ANONYMOUS",
 573                                           "Responses may only be delivered over the same connection "
 574 kumpf            1.2                          "on which the request arrives."),
 575                                       WSMAN_FAULTDETAIL_ADDRESSINGMODE);
 576                               }
 577                       
 578                               //
 579                               // Parse the SOAP Body while decoding each action
 580                               //
 581                       
 582 mike             1.12         String className;
 583                               String methodName;
 584                       
 585 kumpf            1.2          if (wsaAction == WSM_ACTION_GET)
 586                               {
 587                                   request.reset(_decodeWSTransferGet(
 588                                       wsmReader,
 589                                       wsaMessageId,
 590                                       epr));
 591                               }
 592                               else if (wsaAction == WSM_ACTION_PUT)
 593                               {
 594                                   request.reset(_decodeWSTransferPut(
 595                                       wsmReader,
 596                                       wsaMessageId,
 597                                       epr));
 598                               }
 599                               else if (wsaAction == WSM_ACTION_CREATE)
 600                               {
 601                                   request.reset(_decodeWSTransferCreate(
 602                                       wsmReader,
 603                                       wsaMessageId,
 604                                       epr));
 605                               }
 606 kumpf            1.2          else if (wsaAction == WSM_ACTION_DELETE)
 607                               {
 608                                   request.reset(_decodeWSTransferDelete(
 609                                       wsmReader,
 610                                       wsaMessageId,
 611                                       epr));
 612                               }
 613 kumpf            1.4          else if (wsaAction == WSM_ACTION_ENUMERATE)
 614                               {
 615                                   request.reset(_decodeWSEnumerationEnumerate(
 616                                       wsmReader,
 617                                       wsaMessageId,
 618                                       epr,
 619                                       wsmRequestItemCount));
 620                               }
 621                               else if (wsaAction == WSM_ACTION_PULL)
 622                               {
 623                                   request.reset(_decodeWSEnumerationPull(
 624                                       wsmReader,
 625                                       wsaMessageId,
 626                                       epr,
 627                                       wsmRequestItemCount));
 628                               }
 629                               else if (wsaAction == WSM_ACTION_RELEASE)
 630                               {
 631                                   request.reset(_decodeWSEnumerationRelease(
 632                                       wsmReader,
 633                                       wsaMessageId,
 634 kumpf            1.4                  epr));
 635                               }
 636 mike             1.12         else if (_parseInvokeAction(wsaAction, className, methodName))
 637                               {
 638                                   request.reset(_decodeWSInvoke(
 639                                       wsmReader,
 640                                       wsaMessageId,
 641                                       epr,
 642                                       className,
 643                                       methodName));
 644                               }
 645 kumpf            1.2          else
 646                               {
 647                                   throw WsmFault(
 648                                       WsmFault::wsa_ActionNotSupported,
 649                                       MessageLoaderParms(
 650                                           "WsmServer.WsmRequestDecoder.ACTION_NOT_SUPPORTED",
 651                                           "The wsa:Action value \"$0\" is not supported.",
 652                                           wsaAction));
 653                               }
 654                       
 655                               wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Envelope");
 656                       
 657                               request->authType = authType;
 658                               request->userName = userName;
 659                               request->ipAddress = ipAddress;
 660                               request->httpMethod = httpMethod;
 661                               // Note:  The HTTP Accept-Languages header is ignored
 662                               request->acceptLanguages = wsmLocale;
 663                               request->contentLanguages = httpContentLanguages;
 664                               request->httpCloseConnect = httpCloseConnect;
 665 mike             1.12         request->omitXMLProcessingInstruction = omitXMLProcessingInstruction;
 666 kumpf            1.2          request->queueId = queueId;
 667                               request->requestEpr = wsmRequestEpr;
 668                               request->maxEnvelopeSize = wsmMaxEnvelopeSize;
 669                           }
 670                           catch (WsmFault& fault)
 671                           {
 672                               _wsmProcessor->sendResponse(new WsmFaultResponse(
 673 mike             1.12             wsaMessageId, queueId, httpMethod, httpCloseConnect,
 674                                   omitXMLProcessingInstruction, fault));
 675 kumpf            1.2          PEG_METHOD_EXIT();
 676                               return;
 677                           }
 678                           catch (SoapNotUnderstoodFault& fault)
 679                           {
 680                               _wsmProcessor->sendResponse(new SoapFaultResponse(
 681 mike             1.12             wsaMessageId, queueId, httpMethod, httpCloseConnect,
 682                                   omitXMLProcessingInstruction, fault));
 683 kumpf            1.2          PEG_METHOD_EXIT();
 684                               return;
 685                           }
 686                           catch (XmlException& e)
 687                           {
 688                               WsmFault fault(
 689                                   WsmFault::wsman_SchemaValidationError,
 690                                   e.getMessage(),
 691                                   e.getContentLanguages());
 692                               _wsmProcessor->sendResponse(new WsmFaultResponse(
 693 mike             1.12             wsaMessageId, queueId, httpMethod, httpCloseConnect,
 694                                   omitXMLProcessingInstruction, fault));
 695 kumpf            1.2          PEG_METHOD_EXIT();
 696                               return;
 697                           }
 698 marek            1.14.4.1     catch (TooManyElementsException& e)
 699                               {
 700                                   WsmFault fault(
 701                                       WsmFault::wsman_EncodingLimit,
 702                                       e.getMessage(),
 703                                       e.getContentLanguages(),
 704                                       WSMAN_FAULTDETAIL_OPTION_LIMIT);
 705                                   _wsmProcessor->sendResponse(new WsmFaultResponse(
 706                                       wsaMessageId, queueId, httpMethod, httpCloseConnect,
 707                                       omitXMLProcessingInstruction, fault));
 708                                   PEG_METHOD_EXIT();
 709                                   return;
 710                               }
 711 kumpf            1.2          catch (Exception& e)
 712                               {
 713                                   WsmFault fault(
 714                                       WsmFault::wsman_InternalError,
 715                                       e.getMessage(),
 716                                       e.getContentLanguages());
 717                                   _wsmProcessor->sendResponse(new WsmFaultResponse(
 718 mike             1.12                 wsaMessageId, queueId, httpMethod, httpCloseConnect,
 719                                       omitXMLProcessingInstruction, fault));
 720 kumpf            1.2              PEG_METHOD_EXIT();
 721                                   return;
 722                               }
 723                               catch (const PEGASUS_STD(exception)& e)
 724                               {
 725                                   WsmFault fault(WsmFault::wsman_InternalError, e.what());
 726                                   _wsmProcessor->sendResponse(new WsmFaultResponse(
 727 mike             1.12                 wsaMessageId, queueId, httpMethod, httpCloseConnect,
 728                                       omitXMLProcessingInstruction, fault));
 729 kumpf            1.2              PEG_METHOD_EXIT();
 730                                   return;
 731                               }
 732                               catch (...)
 733                               {
 734                                   WsmFault fault(WsmFault::wsman_InternalError);
 735                                   _wsmProcessor->sendResponse(new WsmFaultResponse(
 736 mike             1.12                 wsaMessageId, queueId, httpMethod, httpCloseConnect,
 737                                       omitXMLProcessingInstruction, fault));
 738 kumpf            1.2              PEG_METHOD_EXIT();
 739                                   return;
 740                               }
 741                           
 742                               _wsmProcessor->handleRequest(request.release());
 743                           
 744                               PEG_METHOD_EXIT();
 745                           }
 746                           
 747                           void WsmRequestDecoder::_checkRequiredHeader(
 748                               const char* headerName,
 749                               Boolean headerSpecified)
 750                           {
 751                               if (!headerSpecified)
 752                               {
 753                                   throw WsmFault(
 754                                       WsmFault::wsa_MessageInformationHeaderRequired,
 755                                       MessageLoaderParms(
 756                                           "WsmServer.WsmRequestDecoder.MISSING_HEADER",
 757                                           "Required SOAP header \"$0\" was not specified.",
 758                                           headerName));
 759 kumpf            1.2          }
 760                           }
 761                           
 762 kumpf            1.4      void WsmRequestDecoder::_checkNoSelectorsEPR(const WsmEndpointReference& epr)
 763                           {
 764 kumpf            1.9          // Make sure that at most __cimnamespace selector is present
 765                               if (epr.selectorSet->selectors.size())
 766 kumpf            1.4          {
 767                                   if (epr.selectorSet->selectors.size() > 1 ||
 768                                       epr.selectorSet->selectors[0].type != WsmSelector::VALUE ||
 769                                       epr.selectorSet->selectors[0].name != "__cimnamespace")
 770                                   {
 771                                       throw WsmFault(
 772                                           WsmFault::wsman_InvalidSelectors,
 773                                           MessageLoaderParms(
 774                                               "WsmServer.WsmRequestDecoder.UNEXPECTED_SELECTORS",
 775 kumpf            1.9                          "The operation allows only the __cimnamespace selector to "
 776 kumpf            1.4                          "be present."),
 777                                           WSMAN_FAULTDETAIL_UNEXPECTEDSELECTORS);
 778                                   }
 779                               }
 780                           }
 781                           
 782                           WxfGetRequest* WsmRequestDecoder::_decodeWSTransferGet(
 783 kumpf            1.2          WsmReader& wsmReader,
 784                               const String& messageId,
 785                               const WsmEndpointReference& epr)
 786                           {
 787                               _checkRequiredHeader("wsman:ResourceURI", epr.resourceUri.size());
 788                           
 789                               XmlEntry entry;
 790                               wsmReader.expectStartOrEmptyTag(
 791                                   entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
 792                               if (entry.type != XmlEntry::EMPTY_TAG)
 793                               {
 794                                   wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
 795                               }
 796                           
 797 kumpf            1.4          return new WxfGetRequest(messageId, epr);
 798 kumpf            1.2      }
 799                           
 800 kumpf            1.4      WxfPutRequest* WsmRequestDecoder::_decodeWSTransferPut(
 801 kumpf            1.2          WsmReader& wsmReader,
 802                               const String& messageId,
 803                               const WsmEndpointReference& epr)
 804                           {
 805                               _checkRequiredHeader("wsman:ResourceURI", epr.resourceUri.size());
 806                           
 807                               XmlEntry entry;
 808                               wsmReader.expectStartTag(entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
 809                           
 810                               // The soap body must contain an XML representation of the updated instance
 811                               WsmInstance instance;
 812                               wsmReader.getInstanceElement(instance);
 813                           
 814                               wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
 815                           
 816 kumpf            1.4          return new WxfPutRequest(messageId, epr, instance);
 817 kumpf            1.2      }
 818                           
 819 kumpf            1.4      WxfCreateRequest* WsmRequestDecoder::_decodeWSTransferCreate(
 820 kumpf            1.2          WsmReader& wsmReader,
 821                               const String& messageId,
 822                               const WsmEndpointReference& epr)
 823                           {
 824                               _checkRequiredHeader("wsman:ResourceURI", epr.resourceUri.size());
 825 kumpf            1.4          _checkNoSelectorsEPR(epr);
 826 kumpf            1.2      
 827                               XmlEntry entry;
 828                               wsmReader.expectStartTag(entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
 829                           
 830                               // The soap body must contain an XML representation of the new instance
 831                               WsmInstance instance;
 832                               wsmReader.getInstanceElement(instance);
 833                           
 834                               wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
 835                           
 836 kumpf            1.4          return new WxfCreateRequest(messageId, epr, instance);
 837 kumpf            1.2      }
 838                           
 839 kumpf            1.4      WxfDeleteRequest* WsmRequestDecoder::_decodeWSTransferDelete(
 840 kumpf            1.2          WsmReader& wsmReader,
 841                               const String& messageId,
 842                               const WsmEndpointReference& epr)
 843                           {
 844                               _checkRequiredHeader("wsman:ResourceURI", epr.resourceUri.size());
 845                           
 846                               XmlEntry entry;
 847                               wsmReader.expectStartOrEmptyTag(
 848                                   entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
 849                               if (entry.type != XmlEntry::EMPTY_TAG)
 850                               {
 851                                   wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
 852                               }
 853                           
 854 kumpf            1.4          return new WxfDeleteRequest(messageId, epr);
 855                           }
 856                           
 857                           WsenEnumerateRequest* WsmRequestDecoder::_decodeWSEnumerationEnumerate(
 858                               WsmReader& wsmReader,
 859                               const String& messageId,
 860                               const WsmEndpointReference& epr,
 861                               Boolean requestItemCount)
 862                           {
 863 karl             1.13         PEG_METHOD_ENTER(TRC_WSMSERVER,
 864                                   "WsmRequestDecoder::_decodeWSEnumerationEnumerate()");
 865                           
 866 kumpf            1.4          _checkRequiredHeader("wsman:ResourceURI", epr.resourceUri.size());
 867                               _checkNoSelectorsEPR(epr);
 868                           
 869                               String expiration;
 870                               WsmbPolymorphismMode polymorphismMode = WSMB_PM_UNKNOWN;
 871                               WsenEnumerationMode enumerationMode = WSEN_EM_UNKNOWN;
 872                               Boolean optimized = false;
 873                               Uint32 maxElements = 0;
 874 karl             1.13         WsmFilter wsmFilter;
 875 kumpf            1.4      
 876                               XmlEntry entry;
 877                               wsmReader.expectStartOrEmptyTag(
 878                                   entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
 879                               if (entry.type != XmlEntry::EMPTY_TAG)
 880                               {
 881 kumpf            1.7              wsmReader.decodeEnumerateBody(expiration, polymorphismMode,
 882 karl             1.13                 enumerationMode, optimized, maxElements, wsmFilter);
 883                           
 884 kumpf            1.4              wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
 885                               }
 886                           
 887                               // If PolymorphismMode header is not specified, set it to default
 888                               if (polymorphismMode == WSMB_PM_UNKNOWN)
 889                               {
 890 kumpf            1.7              // DSP0227, R8.1-4: A service MAY optionally support the
 891                                   // wsmb:PolymorphismMode modifier element with a value of
 892                                   // IncludeSubClassProperties, which returns instances of the base
 893                                   // class and derived classes using the actual classs GED and XSD
 894 kumpf            1.4              // type. This is the same as not specifying the polymorphism mode.
 895                                   polymorphismMode = WSMB_PM_INCLUDE_SUBCLASS_PROPERTIES;
 896                               }
 897                               else
 898                               {
 899 kumpf            1.7              // DSP0227, R8.1-6: The service SHOULD also return a
 900                                   // wsmb:PolymorphismModeNotSupported fault for requests using the
 901                                   // all classes ResourceURI if the PolymorphismMode is present and
 902 kumpf            1.4              // does not equal IncludeSubClassProperties.
 903 mike             1.12     
 904                                   CString tmp(epr.resourceUri.getCString());
 905                                   const char* suffix = WsmUtils::skipHostUri(tmp);
 906                           
 907                                   if (strcmp(suffix, WSM_RESOURCEURI_ALLCLASSES_SUFFIX) == 0 &&
 908 kumpf            1.4                  polymorphismMode != WSMB_PM_INCLUDE_SUBCLASS_PROPERTIES)
 909                                   {
 910 karl             1.13                 PEG_METHOD_EXIT();
 911 kumpf            1.4                  throw WsmFault(
 912                                           WsmFault::wsmb_PolymorphismModeNotSupported,
 913                                           MessageLoaderParms(
 914                                               "WsmServer.WsmReader.ENUMERATE_"
 915                                                   "POLYMORPHISM_INCLUDE_SUBCLASS",
 916                                               "\"All classes\" resource URI requires "
 917                                                   "IncludeSubClassProperties polymorphism mode."));
 918                                   }
 919                               }
 920                           
 921                               // If EnumerationMode header is not specified, set it to default
 922                               if (enumerationMode == WSEN_EM_UNKNOWN)
 923                               {
 924                                   enumerationMode = WSEN_EM_OBJECT;
 925                               }
 926                           
 927                               // If optimized enumeration is requested but maxElements is not specified,
 928                               // set it to default value of 1.
 929                               if (optimized && maxElements == 0)
 930                               {
 931                                   maxElements = 1;
 932 kumpf            1.4          }
 933                           
 934 karl             1.14         PEG_METHOD_EXIT();
 935                           
 936 kumpf            1.4          return new WsenEnumerateRequest(
 937 kumpf            1.7              messageId,
 938                                   epr,
 939                                   expiration,
 940                                   requestItemCount,
 941                                   optimized,
 942                                   maxElements,
 943                                   enumerationMode,
 944 mike             1.12             polymorphismMode,
 945 karl             1.13             wsmFilter);
 946 kumpf            1.4      }
 947                           
 948                           WsenPullRequest* WsmRequestDecoder::_decodeWSEnumerationPull(
 949                               WsmReader& wsmReader,
 950                               const String& messageId,
 951                               const WsmEndpointReference& epr,
 952                               Boolean requestItemCount)
 953                           {
 954                               _checkRequiredHeader("wsman:ResourceURI", epr.resourceUri.size());
 955                               _checkNoSelectorsEPR(epr);
 956                           
 957 kumpf            1.10         Uint64 enumerationContext = 0;
 958 kumpf            1.4          String maxTime;
 959                               Uint32 maxElements = 0;
 960                               Uint32 maxCharacters = 0;
 961                           
 962                               XmlEntry entry;
 963 kumpf            1.10         wsmReader.expectStartTag(entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
 964                               wsmReader.decodePullBody(
 965                                   enumerationContext, maxTime, maxElements, maxCharacters);
 966                               wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
 967 kumpf            1.4      
 968                               // If maxElements is not specified, set it to default value of 1.
 969                               if (maxElements == 0)
 970                               {
 971                                   maxElements = 1;
 972                               }
 973                           
 974                               return new WsenPullRequest(
 975 kumpf            1.7              messageId,
 976                                   epr,
 977 kumpf            1.4              enumerationContext,
 978                                   maxTime,
 979 kumpf            1.7              requestItemCount,
 980 kumpf            1.4              maxElements,
 981                                   maxCharacters);
 982                           }
 983                           
 984                           WsenReleaseRequest* WsmRequestDecoder::_decodeWSEnumerationRelease(
 985                               WsmReader& wsmReader,
 986                               const String& messageId,
 987                               const WsmEndpointReference& epr)
 988                           {
 989                               _checkRequiredHeader("wsman:ResourceURI", epr.resourceUri.size());
 990                               _checkNoSelectorsEPR(epr);
 991                           
 992 kumpf            1.10         Uint64 enumerationContext = 0;
 993 kumpf            1.4      
 994                               XmlEntry entry;
 995 kumpf            1.10         wsmReader.expectStartTag(entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
 996                               wsmReader.decodeReleaseBody(enumerationContext);
 997                               wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
 998 kumpf            1.4      
 999                               return new WsenReleaseRequest(
1000 kumpf            1.7              messageId,
1001                                   epr,
1002 kumpf            1.4              enumerationContext);
1003 kumpf            1.2      }
1004                           
1005 mike             1.12     WsmRequest* WsmRequestDecoder::_decodeWSInvoke(
1006                               WsmReader& wsmReader,
1007                               const String& messageId,
1008                               const WsmEndpointReference& epr,
1009                               const String& className,
1010                               const String& methodName)
1011                           {
1012                               XmlEntry entry;
1013                           
1014                               //
1015                               // Parse the <s:Body> element. Here is an example:
1016                               //
1017                               //   <s:Body>
1018                               //     <p:Foo_INPUT xmlns:p=
1019                               //       "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SomeClass">
1020                               //       <p:Arg1>
1021                               //         1234
1022                               //       </p:Arg1>
1023                               //       <p:Arg2>
1024                               //         Hello!
1025                               //       </p:Arg2>
1026 mike             1.12         //     </p:Foo_INPUT>
1027                               //   </s:Body>
1028                               //
1029                           
1030                               WsmInstance instance;
1031                               wsmReader.expectStartTag(entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
1032                               wsmReader.decodeInvokeInputBody(className, methodName, instance);
1033                               wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
1034                           
1035                               return new WsInvokeRequest(messageId, epr, className, methodName, instance);
1036                           }
1037                           
1038                           bool WsmRequestDecoder::_isIdentifyRequest(WsmReader& wsmReader)
1039                           {
1040                               // Parse the <s:Body> element. Here is an example:
1041                               //
1042                               //   <s:Body>
1043                               //     <wsmid:Identify>
1044                               //   </s:Body>
1045                           
1046                               XmlEntry entry;
1047 mike             1.12         wsmReader.setHideEmptyTags(true);
1048                               wsmReader.expectStartTag(entry, WsmNamespaces::SOAP_ENVELOPE, "Body");
1049                           
1050                               try
1051                               {
1052                                   // Expect an identify element. Ignore the namespace to be more
1053                                   // tolerant.
1054                                   int nsType = wsmReader.expectStartTag(entry, "Identify");
1055                                   wsmReader.expectEndTag(nsType, "Identify");
1056                               }
1057                               catch (...)
1058                               {
1059                                   wsmReader.setHideEmptyTags(false);
1060                                   return false;
1061                               }
1062                           
1063                               wsmReader.expectEndTag(WsmNamespaces::SOAP_ENVELOPE, "Body");
1064                               wsmReader.setHideEmptyTags(false);
1065                           
1066                               return true;
1067                           }
1068 mike             1.12     
1069                           void WsmRequestDecoder::_sendIdentifyResponse(Uint32 queueId)
1070                           {
1071                               const char HTTP[] =
1072                                   "HTTP/1.1 200 OK\r\n"
1073                                   "Content-Type: application/soap+xml;charset=UTF-8\r\n"
1074                                   "Content-Length: ";
1075                           
1076                               const char XML[] =
1077                                   "<s:Envelope xmlns:s=\""
1078                                   "http://www.w3.org/2003/05/soap-envelope"
1079                                   "\" xmlns:wsmid=\""
1080                                   "http://schemas.dmtf.org/wbem/wsman/identify/1/wsmanidentity.xsd"
1081                                   "\">"
1082                                   "<s:Header>"
1083                                   "</s:Header>"
1084                                   "<s:Body>"
1085                                   "<wsmid:IdentifyResponse>"
1086                                   "<wsmid:ProtocolVersion>"
1087                                   WSMAN_PROTOCOL_VERSION
1088                                   "</wsmid:ProtocolVersion>"
1089 mike             1.12             "<wsmid:ProductVendor>"
1090                                   WSMAN_PRODUCT_VENDOR
1091                                   "</wsmid:ProductVendor>"
1092                                   "<wsmid:ProductVersion>"
1093                                   WSMAN_PRODUCT_VERSION
1094                                   "</wsmid:ProductVersion>"
1095                                   "</wsmid:IdentifyResponse>"
1096                                   "</s:Body>"
1097                                   "</s:Envelope>";
1098                           
1099                               Buffer message;
1100                               message.append(HTTP, sizeof(HTTP) - 1);
1101                           
1102                               char buf[32];
1103                               int n = sprintf(buf, "%d\r\n\r\n", int(sizeof(XML) - 1));
1104                               message.append(buf, n);
1105                           
1106                               message.append(XML, sizeof(XML) - 1);
1107                           
1108                               sendResponse(queueId, message, false);
1109                           }
1110 mike             1.12     
1111 kumpf            1.2      PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2