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
48 PEGASUS_USING_STD;
49
50 PEGASUS_NAMESPACE_BEGIN
51
52 WsmResponseEncoder::WsmResponseEncoder()
53 {
54 }
55
56 WsmResponseEncoder::~WsmResponseEncoder()
57 {
58 }
59
60 void WsmResponseEncoder::sendResponse(
61 WsmResponse* response,
62 const String& action,
63 Buffer* bodygiven,
64 kumpf 1.2 Buffer* extraHeaders)
65 {
66 PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmResponseEncoder::sendResponse");
67 PEG_TRACE((TRC_WSMSERVER, Tracer::LEVEL3,
68 "WsmResponseEncoder::sendResponse(): action = %s",
69 (const char*)action.getCString()));
70
71 if (!response)
72 {
73 PEG_METHOD_EXIT();
74 return;
75 }
76
77 Uint32 queueId = response->getQueueId();
78 Boolean httpCloseConnect = response->getHttpCloseConnect();
79
80 PEG_TRACE((TRC_WSMSERVER, Tracer::LEVEL3,
81 "WsmResponseEncoder::sendResponse()- "
82 "response->getHttpCloseConnect() returned %d",
83 httpCloseConnect));
84
85 kumpf 1.2 MessageQueue* queue = MessageQueue::lookup(queueId);
86 if (!queue)
87 {
88 PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL2,
89 "ERROR: non-existent queueId = %u, response not sent.", queueId));
90 PEG_METHOD_EXIT();
91 return;
92 }
93 PEGASUS_ASSERT(dynamic_cast<HTTPConnection*>(queue) != 0);
94
95 HttpMethod httpMethod = response->getHttpMethod();
96 String messageId = response->getMessageId();
97 String relatesTo = response->getRelatesTo();
98 Buffer message;
99
100 // Note: the language is ALWAYS passed empty to the xml formatters because
101 // it is HTTPConnection that needs to make the decision of whether to add
102 // the languages to the HTTP message.
103 ContentLanguageList contentLanguage;
104
105 Uint32 httpHeaderSize = 0;
106 kumpf 1.2 Buffer bodylocal, headerslocal;
107 Buffer& body = bodygiven ? *bodygiven : bodylocal;
108 Buffer& headers = extraHeaders ? *extraHeaders : headerslocal;
109
110 if (response->getType() == SOAP_FAULT)
111 {
112 message = WsmWriter::formatSoapFault(
113 ((SoapFaultResponse*) response)->getFault(),
114 messageId,
115 relatesTo,
116 httpMethod,
117 httpHeaderSize);
118 }
119 else if (response->getType() == WSM_FAULT)
120 {
121 message = WsmWriter::formatWsmFault(
122 ((WsmFaultResponse*) response)->getFault(),
123 messageId,
124 relatesTo,
125 httpMethod,
126 httpHeaderSize);
127 kumpf 1.2 }
128 else
129 {
130 // else non-error condition
131 try
132 {
133 message = WsmWriter::formatWsmRspMessage(
134 action,
135 messageId,
136 relatesTo,
137 httpMethod,
138 contentLanguage,
139 body,
140 headers,
141 httpHeaderSize);
142 }
143 catch (PEGASUS_STD(bad_alloc)&)
144 {
145 WsmFault fault(WsmFault::wsman_InternalError,
146 MessageLoaderParms(
147 "WsmServer.WsmResponseEncoder.OUT_OF_MEMORY",
148 kumpf 1.2 "A System error has occurred. Please retry the "
149 "WS-Management operation at a later time."));
150 WsmFaultResponse outofmem(relatesTo, queueId, httpMethod,
151 httpCloseConnect, fault);
152
153 // try again with new error and no body
154 body.clear();
155 sendResponse(&outofmem);
156 PEG_METHOD_EXIT();
157 return;
158 }
159 }
160
161 // If MaxEnvelopeSize is not set, it's never been specified
162 // in the request
163 if (response->getMaxEnvelopeSize() &&
164 message.size() - httpHeaderSize > response->getMaxEnvelopeSize())
165 {
166 // try again with new error and no body
167 body.clear();
168
169 kumpf 1.2 if (response->getType() == WSM_FAULT ||
170 response->getType() == SOAP_FAULT)
171 {
172 WsmFault fault(WsmFault::wsman_EncodingLimit,
173 MessageLoaderParms(
174 "WsmServer.WsmResponseEncoder.FAULT_MAX_ENV_SIZE_EXCEEDED",
175 "Fault response could not be encoded within requested "
176 "envelope size limits."),
177 WSMAN_FAULTDETAIL_MAXENVELOPESIZE);
178 WsmFaultResponse faultResponse(relatesTo, queueId, httpMethod,
179 httpCloseConnect, fault);
180
181 sendResponse(&faultResponse);
182 }
183 else
184 {
185 // DSP0226 R6.2-2: If the mustUnderstand attribute is set to
186 // "true", the service shall comply with the request. If the
187 // response would exceed the maximum size, the service should
188 // return a wsman:EncodingLimit fault. Because a service might
189 // execute the operation prior to knowing the response size, the
190 kumpf 1.2 // service should undo any effects of the operation before
191 // issuing the fault. If the operation cannot be reversed (such
192 // as a destructive wxf:Put or wxf:Delete, or a wxf:Create), the
193 // service shall indicate that the operation succeeded in the
194 // wsman:EncodingLimit fault with the following detail code:
195 // http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/
196 // UnreportableSuccess
197
198 WsmFault fault(WsmFault::wsman_EncodingLimit,
199 MessageLoaderParms(
200 "WsmServer.WsmResponseEncoder.UNREPORTABLE_SUCCESS",
201 "Success response could not be encoded within "
202 "requested envelope size limits."),
203 WSMAN_FAULTDETAIL_UNREPORTABLESUCCESS);
204 WsmFaultResponse faultResponse(relatesTo, queueId, httpMethod,
205 httpCloseConnect, fault);
206
207 sendResponse(&faultResponse);
208 }
209
210 PEG_METHOD_EXIT();
211 kumpf 1.2 return;
212 }
213
214 // Note: WS-Management responses are never sent in chunks, so there is no
215 // need to check dynamic_cast<HTTPConnection*>(queue)->isChunkRequested().
216 // HTTPMessage::isComplete() defaults to true, and we leave it that way.
217
218 AutoPtr<HTTPMessage> httpMessage(new HTTPMessage(message));
219
220 if (response->getType() == SOAP_FAULT)
221 {
222 httpMessage->contentLanguages =
223 ((SoapFaultResponse*) response)->getFault().getMessageLanguage();
224 }
225 else if (response->getType() == WSM_FAULT)
226 {
227 httpMessage->contentLanguages =
228 ((WsmFaultResponse*) response)->getFault().getReasonLanguage();
229 }
230 else
231 {
232 kumpf 1.2 httpMessage->contentLanguages = response->getContentLanguages();
233 }
234
235 httpMessage->setCloseConnect(httpCloseConnect);
236 queue->enqueue(httpMessage.release());
237
238 PEG_METHOD_EXIT();
239 }
240
241 void WsmResponseEncoder::enqueue(WsmResponse* response)
242 {
243 PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmResponseEncoder::enqueue()");
244 PEGASUS_ASSERT(response);
245
246 PEG_TRACE((TRC_WSMSERVER, Tracer::LEVEL3,
247 "WsmResponseEncoder::enqueue()- "
248 "response->getHttpCloseConnect() returned %d",
249 response->getHttpCloseConnect()));
250
251 switch (response->getType())
252 {
253 kumpf 1.2 case WS_TRANSFER_GET:
254 _encodeGetResponse((WsmGetResponse*) response);
255 break;
256
257 case WS_TRANSFER_PUT:
258 _encodePutResponse((WsmPutResponse*) response);
259 break;
260
261 case WS_TRANSFER_CREATE:
262 _encodeCreateResponse((WsmCreateResponse*) response);
263 break;
264
265 case WS_TRANSFER_DELETE:
266 _encodeDeleteResponse((WsmDeleteResponse*) response);
267 break;
268
269 case WSM_FAULT:
270 _encodeWsmFaultResponse((WsmFaultResponse*) response);
271 break;
272
273 case SOAP_FAULT:
274 kumpf 1.2 _encodeSoapFaultResponse((SoapFaultResponse*) response);
275 break;
276
277 default:
278 // Unexpected message type
279 PEGASUS_ASSERT(0);
280 break;
281 }
282
283 PEG_METHOD_EXIT();
284 }
285
286 void WsmResponseEncoder::_encodeGetResponse(WsmGetResponse* response)
287 {
288 Buffer body;
289 WsmWriter::appendInstanceElement(body, response->getInstance());
290 sendResponse(response, WSM_ACTION_GET_RESPONSE, &body);
291 }
292
293 void WsmResponseEncoder::_encodePutResponse(WsmPutResponse* response)
294 {
295 kumpf 1.2 Buffer body;
296 Buffer headers;
297
298 // DSP0226 R6.5-1: A service receiving a message that contains the
299 // wsman:RequestEPR header block should return a response that contains
300 // a wsman:RequestedEPR header block. This block contains the most recent
301 // EPR of the resource being accessed or a status code if the service
302 // cannot determine or return the EPR. This EPR reflects any identity
303 // changes that may have occurred as a result of the current operation, as
304 // set forth in the following behavior. The header block in the
305 // corresponding response message has the following format:
306 // <wsman:RequestedEPR...>
307 // [ <wsa:EndpointReference>
308 // wsa:EndpointReferenceType
309 // </wsa:EndpointReference> |
310 // <wsman:EPRInvalid/> |
311 // <wsman:EPRUnknown/> ]
312 // </wsman:RequestedEPR>
313 if (response->getRequestedEPR())
314 {
315 WsmWriter::appendStartTag(
316 kumpf 1.2 headers, WsmNamespaces::WS_MAN, STRLIT("RequestedEPR"));
317 WsmWriter::appendStartTag(
318 headers, WsmNamespaces::WS_ADDRESSING, STRLIT("EndpointReference"));
319 WsmWriter::appendEPRElement(headers, response->getEPR());
320 WsmWriter::appendEndTag(
321 headers, WsmNamespaces::WS_ADDRESSING, STRLIT("EndpointReference"));
322 WsmWriter::appendEndTag(
323 headers, WsmNamespaces::WS_MAN, STRLIT("RequestedEPR"));
324 }
325 sendResponse(response, WSM_ACTION_PUT_RESPONSE, &body, &headers);
326 }
327
328 void WsmResponseEncoder::_encodeCreateResponse(WsmCreateResponse* response)
329 {
330 Buffer body;
331 WsmWriter::appendStartTag(
332 body, WsmNamespaces::WS_TRANSFER, STRLIT("ResourceCreated"));
333 WsmWriter::appendEPRElement(body, response->getEPR());
334 WsmWriter::appendEndTag(
335 body, WsmNamespaces::WS_TRANSFER, STRLIT("ResourceCreated"));
336 sendResponse(response, WSM_ACTION_CREATE_RESPONSE, &body);
337 kumpf 1.2 }
338
339 void WsmResponseEncoder::_encodeDeleteResponse(WsmDeleteResponse* response)
340 {
341 sendResponse(response, WSM_ACTION_DELETE_RESPONSE);
342 }
343
344 void WsmResponseEncoder::_encodeWsmFaultResponse(WsmFaultResponse* response)
345 {
346 sendResponse(response);
347 }
348
349 void WsmResponseEncoder::_encodeSoapFaultResponse(SoapFaultResponse* response)
350 {
351 sendResponse(response);
352 }
353
354 PEGASUS_NAMESPACE_END
|