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
|