1 kumpf 1.2 //%2006////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
11 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 kumpf 1.2 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #include <cctype>
35 #include <cstdio>
36 #include <Pegasus/Common/Config.h>
37 #include <Pegasus/Common/HTTPConnection.h>
38 #include <Pegasus/Common/HTTPMessage.h>
39 #include <Pegasus/Common/Tracer.h>
40 #include <Pegasus/Common/AutoPtr.h>
41 #include <Pegasus/Common/MessageLoader.h>
42
43 kumpf 1.2 #include "WsmConstants.h"
44 #include "WsmReader.h"
45 #include "WsmWriter.h"
46 #include "WsmResponseEncoder.h"
|
47 kumpf 1.4 #include "WsmToCimRequestMapper.h"
48 #include "SoapResponse.h"
|
49 kumpf 1.2
50 PEGASUS_USING_STD;
51
52 PEGASUS_NAMESPACE_BEGIN
53
54 WsmResponseEncoder::WsmResponseEncoder()
55 {
56 }
57
58 WsmResponseEncoder::~WsmResponseEncoder()
59 {
60 }
61
|
62 kumpf 1.4 void WsmResponseEncoder::_sendResponse(SoapResponse* response)
|
63 kumpf 1.2 {
64 PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmResponseEncoder::sendResponse");
65 PEG_TRACE((TRC_WSMSERVER, Tracer::LEVEL3,
|
66 kumpf 1.4 "WsmResponseEncoder::sendResponse()"));
|
67 kumpf 1.2
68 if (!response)
69 {
70 PEG_METHOD_EXIT();
71 return;
72 }
73
74 Uint32 queueId = response->getQueueId();
75 Boolean httpCloseConnect = response->getHttpCloseConnect();
76
|
77 marek 1.3 PEG_TRACE((TRC_WSMSERVER, Tracer::LEVEL4,
|
78 kumpf 1.2 "WsmResponseEncoder::sendResponse()- "
79 "response->getHttpCloseConnect() returned %d",
80 httpCloseConnect));
81
82 MessageQueue* queue = MessageQueue::lookup(queueId);
83 if (!queue)
84 {
|
85 marek 1.3 PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL1,
|
86 kumpf 1.2 "ERROR: non-existent queueId = %u, response not sent.", queueId));
87 PEG_METHOD_EXIT();
88 return;
89 }
90 PEGASUS_ASSERT(dynamic_cast<HTTPConnection*>(queue) != 0);
91
|
92 kumpf 1.4 Buffer message = response->getResponseContent();
|
93 kumpf 1.2
94 // Note: WS-Management responses are never sent in chunks, so there is no
95 // need to check dynamic_cast<HTTPConnection*>(queue)->isChunkRequested().
96 // HTTPMessage::isComplete() defaults to true, and we leave it that way.
97
98 AutoPtr<HTTPMessage> httpMessage(new HTTPMessage(message));
99
100 httpMessage->setCloseConnect(httpCloseConnect);
101 queue->enqueue(httpMessage.release());
102
103 PEG_METHOD_EXIT();
104 }
105
|
106 kumpf 1.4 void WsmResponseEncoder::_sendUnreportableSuccess(WsmResponse* response)
107 {
108 // DSP0226 R6.2-2: If the mustUnderstand attribute is set to
109 // "true", the service shall comply with the request. If the
110 // response would exceed the maximum size, the service should
111 // return a wsman:EncodingLimit fault. Because a service might
112 // execute the operation prior to knowing the response size, the
113 // service should undo any effects of the operation before
114 // issuing the fault. If the operation cannot be reversed (such
115 // as a destructive wxf:Put or wxf:Delete, or a wxf:Create), the
116 // service shall indicate that the operation succeeded in the
117 // wsman:EncodingLimit fault with the following detail code:
118 // http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/
119 // UnreportableSuccess
120
121 WsmFault fault(WsmFault::wsman_EncodingLimit,
122 MessageLoaderParms(
123 "WsmServer.WsmResponseEncoder.UNREPORTABLE_SUCCESS",
124 "Success response could not be encoded within "
125 "requested envelope size limits."),
126 WSMAN_FAULTDETAIL_UNREPORTABLESUCCESS);
127 kumpf 1.4 WsmFaultResponse faultResponse(
128 response->getRelatesTo(),
129 response->getQueueId(),
130 response->getHttpMethod(),
131 response->getHttpCloseConnect(),
132 fault);
133
134 SoapResponse soapResponse(&faultResponse);
135 _sendResponse(&soapResponse);
136 }
137
138 void WsmResponseEncoder::_sendEncodingLimitFault(WsmResponse* response)
139 {
140 WsmFault fault(WsmFault::wsman_EncodingLimit,
141 MessageLoaderParms(
142 "WsmServer.WsmResponseEncoder.MAX_ENV_SIZE_EXCEEDED",
143 "Response could not be encoded within requested "
144 "envelope size limits."),
145 WSMAN_FAULTDETAIL_MAXENVELOPESIZE);
146 WsmFaultResponse faultResponse(
147 response->getRelatesTo(),
148 kumpf 1.4 response->getQueueId(),
149 response->getHttpMethod(),
150 response->getHttpCloseConnect(),
151 fault);
152
153 SoapResponse soapResponse(&faultResponse);
154 _sendResponse(&soapResponse);
155 }
156
|
157 kumpf 1.2 void WsmResponseEncoder::enqueue(WsmResponse* response)
158 {
159 PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmResponseEncoder::enqueue()");
160 PEGASUS_ASSERT(response);
161
|
162 marek 1.3 PEG_TRACE((TRC_WSMSERVER, Tracer::LEVEL4,
|
163 kumpf 1.2 "WsmResponseEncoder::enqueue()- "
164 "response->getHttpCloseConnect() returned %d",
165 response->getHttpCloseConnect()));
166
|
167 kumpf 1.4 try
|
168 kumpf 1.2 {
|
169 kumpf 1.4 switch (response->getType())
170 {
171 case WS_TRANSFER_GET:
172 _encodeWxfGetResponse((WxfGetResponse*) response);
173 break;
174
175 case WS_TRANSFER_PUT:
176 _encodeWxfPutResponse((WxfPutResponse*) response);
177 break;
178
179 case WS_TRANSFER_CREATE:
180 _encodeWxfCreateResponse((WxfCreateResponse*) response);
181 break;
182
183 case WS_TRANSFER_DELETE:
184 _encodeWxfDeleteResponse((WxfDeleteResponse*) response);
185 break;
186
187 case WS_ENUMERATION_ENUMERATE:
188 _encodeWsenEnumerateResponse((WsenEnumerateResponse*) response);
189 break;
190 kumpf 1.4
191 case WS_ENUMERATION_PULL:
192 _encodeWsenPullResponse((WsenPullResponse*) response);
193 break;
194
195 case WS_ENUMERATION_RELEASE:
196 _encodeWsenReleaseResponse((WsenReleaseResponse*) response);
197 break;
198
199 case WSM_FAULT:
200 _encodeWsmFaultResponse((WsmFaultResponse*) response);
201 break;
202
203 case SOAP_FAULT:
204 _encodeSoapFaultResponse((SoapFaultResponse*) response);
205 break;
206
207 default:
208 // Unexpected message type
209 PEGASUS_ASSERT(0);
210 break;
211 kumpf 1.4 }
212 }
213 catch (PEGASUS_STD(bad_alloc)&)
214 {
215 WsmFault fault(WsmFault::wsman_InternalError,
216 MessageLoaderParms(
217 "WsmServer.WsmResponseEncoder.OUT_OF_MEMORY",
218 "A System error has occurred. Please retry the "
219 "WS-Management operation at a later time."));
220 WsmFaultResponse outofmem(
221 response->getRelatesTo(),
222 response->getQueueId(),
223 response->getHttpMethod(),
224 response->getHttpCloseConnect(),
225 fault);
226 _encodeWsmFaultResponse(&outofmem);
|
227 kumpf 1.2 }
228
229 PEG_METHOD_EXIT();
230 }
231
|
232 kumpf 1.4 void WsmResponseEncoder::_encodeWxfGetResponse(WxfGetResponse* response)
|
233 kumpf 1.2 {
|
234 kumpf 1.4 SoapResponse soapResponse(response);
|
235 kumpf 1.2 Buffer body;
236 WsmWriter::appendInstanceElement(body, response->getInstance());
|
237 kumpf 1.4 if (soapResponse.appendBodyContent(body))
238 {
239 _sendResponse(&soapResponse);
240 }
241 else
242 {
243 _sendUnreportableSuccess(response);
244 }
|
245 kumpf 1.2 }
246
|
247 kumpf 1.4 void WsmResponseEncoder::_encodeWxfPutResponse(WxfPutResponse* response)
|
248 kumpf 1.2 {
|
249 kumpf 1.4 SoapResponse soapResponse(response);
|
250 kumpf 1.2 Buffer headers;
251
252 // DSP0226 R6.5-1: A service receiving a message that contains the
253 // wsman:RequestEPR header block should return a response that contains
254 // a wsman:RequestedEPR header block. This block contains the most recent
255 // EPR of the resource being accessed or a status code if the service
256 // cannot determine or return the EPR. This EPR reflects any identity
257 // changes that may have occurred as a result of the current operation, as
258 // set forth in the following behavior. The header block in the
259 // corresponding response message has the following format:
260 // <wsman:RequestedEPR...>
261 // [ <wsa:EndpointReference>
262 // wsa:EndpointReferenceType
263 // </wsa:EndpointReference> |
264 // <wsman:EPRInvalid/> |
265 // <wsman:EPRUnknown/> ]
266 // </wsman:RequestedEPR>
267 if (response->getRequestedEPR())
268 {
269 WsmWriter::appendStartTag(
270 headers, WsmNamespaces::WS_MAN, STRLIT("RequestedEPR"));
271 kumpf 1.2 WsmWriter::appendStartTag(
|
272 kumpf 1.4 headers,
273 WsmNamespaces::WS_ADDRESSING, STRLIT("EndpointReference"));
|
274 kumpf 1.2 WsmWriter::appendEPRElement(headers, response->getEPR());
275 WsmWriter::appendEndTag(
|
276 kumpf 1.4 headers,
277 WsmNamespaces::WS_ADDRESSING, STRLIT("EndpointReference"));
|
278 kumpf 1.2 WsmWriter::appendEndTag(
279 headers, WsmNamespaces::WS_MAN, STRLIT("RequestedEPR"));
280 }
|
281 kumpf 1.4
282 if (soapResponse.appendHeader(headers))
283 {
284 _sendResponse(&soapResponse);
285 }
286 else
287 {
288 _sendUnreportableSuccess(response);
289 }
|
290 kumpf 1.2 }
291
|
292 kumpf 1.4 void WsmResponseEncoder::_encodeWxfCreateResponse(WxfCreateResponse* response)
|
293 kumpf 1.2 {
|
294 kumpf 1.4 SoapResponse soapResponse(response);
|
295 kumpf 1.2 Buffer body;
|
296 kumpf 1.4
|
297 kumpf 1.2 WsmWriter::appendStartTag(
298 body, WsmNamespaces::WS_TRANSFER, STRLIT("ResourceCreated"));
299 WsmWriter::appendEPRElement(body, response->getEPR());
300 WsmWriter::appendEndTag(
301 body, WsmNamespaces::WS_TRANSFER, STRLIT("ResourceCreated"));
|
302 kumpf 1.4
303 if (soapResponse.appendBodyContent(body))
304 {
305 _sendResponse(&soapResponse);
306 }
307 else
308 {
309 _sendUnreportableSuccess(response);
310 }
311 }
312
313 void WsmResponseEncoder::_encodeWxfDeleteResponse(WxfDeleteResponse* response)
314 {
315 SoapResponse soapResponse(response);
316 _sendResponse(&soapResponse);
317 }
318
319 void WsmResponseEncoder::_encodeWsenEnumerateResponse(
320 WsenEnumerateResponse* response)
321 {
322 SoapResponse soapResponse(response);
323 kumpf 1.4 Buffer headers;
324
325 if (response->requestedItemCount())
326 {
327 WsmWriter::appendStartTag(
328 headers, WsmNamespaces::WS_MAN, STRLIT("TotalItemsCountEstimate"));
329 WsmWriter::append(headers, response->getItemCount());
330 WsmWriter::appendEndTag(
331 headers, WsmNamespaces::WS_MAN, STRLIT("TotalItemsCountEstimate"));
332 }
333
334 if (!_encodeEnumerationData(
335 soapResponse,
336 headers,
337 WS_ENUMERATION_ENUMERATE,
338 response->getEnumerationContext(),
339 response->isComplete(),
340 response->getEnumerationData()))
341 {
342 _sendEncodingLimitFault(response);
343 return;
344 kumpf 1.4 }
345
346 _sendResponse(&soapResponse);
347 }
348
349 void WsmResponseEncoder::_encodeWsenPullResponse(WsenPullResponse* response)
350 {
351 SoapResponse soapResponse(response);
352 Buffer headers;
353
354 if (!_encodeEnumerationData(
355 soapResponse,
356 headers,
357 WS_ENUMERATION_PULL,
358 response->getEnumerationContext(),
359 response->isComplete(),
360 response->getEnumerationData()))
361 {
362 _sendEncodingLimitFault(response);
363 return;
364 }
365 kumpf 1.4
366 _sendResponse(&soapResponse);
367 }
368
369 Boolean WsmResponseEncoder::_encodeEnumerationData(
370 SoapResponse& soapResponse,
371 Buffer& headers,
372 WsmOperationType operation,
373 Uint64 contextId,
374 Boolean isComplete,
375 WsenEnumerationData& data)
376 {
377 Buffer bodyHeader, bodyTrailer;
378
379 PEGASUS_ASSERT(operation == WS_ENUMERATION_ENUMERATE ||
380 operation == WS_ENUMERATION_PULL);
381
382 WsmWriter::appendStartTag(
383 bodyHeader, WsmNamespaces::WS_ENUMERATION,
384 operation == WS_ENUMERATION_ENUMERATE ?
385 STRLIT("EnumerateResponse") : STRLIT("PullResponse"));
386 kumpf 1.4
387 if (!isComplete)
388 {
389 WsmWriter::appendStartTag(
390 bodyHeader, WsmNamespaces::WS_ENUMERATION,
391 STRLIT("EnumerationContext"));
392 WsmWriter::append(bodyHeader, contextId);
393 WsmWriter::appendEndTag(
394 bodyHeader, WsmNamespaces::WS_ENUMERATION,
395 STRLIT("EnumerationContext"));
396 }
397 else
398 {
399 WsmWriter::appendEmptyTag(
400 bodyHeader, WsmNamespaces::WS_ENUMERATION,
401 STRLIT("EnumerationContext"));
402 }
403
404 if (data.getSize() > 0)
405 {
406 WsmWriter::appendStartTag(
407 kumpf 1.4 bodyHeader,
408 operation == WS_ENUMERATION_ENUMERATE ?
409 WsmNamespaces::WS_MAN : WsmNamespaces::WS_ENUMERATION,
410 STRLIT("Items"));
411 WsmWriter::appendEndTag(
412 bodyTrailer,
413 operation == WS_ENUMERATION_ENUMERATE ?
414 WsmNamespaces::WS_MAN : WsmNamespaces::WS_ENUMERATION,
415 STRLIT("Items"));
416 }
417
418 Uint32 eosPos = bodyTrailer.size();
419 Uint32 eosSize = 0;
420 if (isComplete)
421 {
422 WsmWriter::appendEmptyTag(
423 bodyTrailer,
424 operation == WS_ENUMERATION_ENUMERATE ?
425 WsmNamespaces::WS_MAN : WsmNamespaces::WS_ENUMERATION,
426 STRLIT("EndOfSequence"));
427 eosSize = bodyTrailer.size() - eosPos;
428 kumpf 1.4 }
429
430 WsmWriter::appendEndTag(
431 bodyTrailer, WsmNamespaces::WS_ENUMERATION,
432 operation == WS_ENUMERATION_ENUMERATE ?
433 STRLIT("EnumerateResponse") : STRLIT("PullResponse"));
434
435 // Fault the request if it can't be encoded within the limits
436 if (!soapResponse.appendHeader(headers) ||
437 !soapResponse.appendBodyHeader(bodyHeader) ||
438 !soapResponse.appendBodyTrailer(bodyTrailer))
439 {
440 return false;
441 }
442
443 // Now add the list of items
444 Uint32 i;
445
446 if (data.enumerationMode == WSEN_EM_OBJECT)
447 {
448 for (i = 0; i < data.instances.size(); i++)
449 kumpf 1.4 {
450 Buffer body;
451
452 if (data.polymorphismMode == WSMB_PM_EXCLUDE_SUBCLASS_PROPERTIES)
453 {
454 // The response does not contain the subclass properties, but
455 // the class name is still that of the subclass.
456 // Replace it here.
457 data.instances[i].setClassName(
458 WsmToCimRequestMapper::convertResourceUriToClassName(
459 data.classUri).getString());
460 }
461
462 WsmWriter::appendInstanceElement(body, data.instances[i]);
463 if (!soapResponse.appendBodyContent(body))
464 {
465 break;
466 }
467 }
468 }
469 else if (data.enumerationMode == WSEN_EM_EPR)
470 kumpf 1.4 {
471 for (i = 0; i < data.eprs.size(); i++)
472 {
473 Buffer body;
474
475 WsmWriter::appendStartTag(
476 body,
477 WsmNamespaces::WS_ADDRESSING,
478 STRLIT("EndpointReference"));
479 WsmWriter::appendEPRElement(body, data.eprs[i]);
480 WsmWriter::appendEndTag(
481 body,
482 WsmNamespaces::WS_ADDRESSING,
483 STRLIT("EndpointReference"));
484 if (!soapResponse.appendBodyContent(body))
485 {
486 break;
487 }
488 }
489 }
490 else if (data.enumerationMode == WSEN_EM_OBJECT_AND_EPR)
491 kumpf 1.4 {
492 for (i = 0; i < data.instances.size(); i++)
493 {
494 Buffer body;
495
496 WsmWriter::appendStartTag(
497 body,
498 WsmNamespaces::WS_MAN,
499 STRLIT("Item"));
500
501 if (data.polymorphismMode == WSMB_PM_EXCLUDE_SUBCLASS_PROPERTIES)
502 {
503 // The response does not contain the subclass properties, but
504 // the class name is still that of the subclass.
505 // Replace it here.
506 data.instances[i].setClassName(
507 WsmToCimRequestMapper::convertResourceUriToClassName(
508 data.classUri).getString());
509 }
510
511 WsmWriter::appendInstanceElement(body, data.instances[i]);
512 kumpf 1.4
513 WsmWriter::appendStartTag(
514 body,
515 WsmNamespaces::WS_ADDRESSING,
516 STRLIT("EndpointReference"));
517 WsmWriter::appendEPRElement(body, data.eprs[i]);
518 WsmWriter::appendEndTag(
519 body,
520 WsmNamespaces::WS_ADDRESSING,
521 STRLIT("EndpointReference"));
522
523 WsmWriter::appendEndTag(
524 body,
525 WsmNamespaces::WS_MAN,
526 STRLIT("Item"));
527
528 if (!soapResponse.appendBodyContent(body))
529 {
530 break;
531 }
532 }
533 kumpf 1.4 }
534 else
535 {
536 PEGASUS_ASSERT(0);
537 }
538
539 // If the list is not empty, but none of the items have been successfully
540 // added to the soapResponse, fault the request because it cannot be
541 // encoded within the specified limits.
542 if (data.getSize() > 0 && i == 0)
543 {
544 return false;
545 }
546
547 // Remove the items we processed. The rest will be added back
548 // to the context
549 if (i != 0)
550 {
551 data.remove(0, i);
552 }
553
554 kumpf 1.4 // The request is complete but could not be encoded with MaxEnvelopeSize.
555 // Clear EndOfSequence tag.
556 if (isComplete && data.getSize() > 0)
557 {
558 soapResponse.getBodyTrailer().remove(eosPos, eosSize);
559 }
560
561 return true;
|
562 kumpf 1.2 }
563
|
564 kumpf 1.4 void WsmResponseEncoder::_encodeWsenReleaseResponse(
565 WsenReleaseResponse* response)
|
566 kumpf 1.2 {
|
567 kumpf 1.4 SoapResponse soapResponse(response);
568 _sendResponse(&soapResponse);
|
569 kumpf 1.2 }
570
571 void WsmResponseEncoder::_encodeWsmFaultResponse(WsmFaultResponse* response)
572 {
|
573 kumpf 1.4 SoapResponse soapResponse(response);
574 _sendResponse(&soapResponse);
|
575 kumpf 1.2 }
576
577 void WsmResponseEncoder::_encodeSoapFaultResponse(SoapFaultResponse* response)
578 {
|
579 kumpf 1.4 SoapResponse soapResponse(response);
580 _sendResponse(&soapResponse);
|
581 kumpf 1.2 }
582
583 PEGASUS_NAMESPACE_END
|