1 karl 1.61 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.49 // 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 karl 1.38 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.49 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.52 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.61 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.2 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 kumpf 1.20 // 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 mike 1.2 // 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 ms.aruran 1.68 //
|
21 kumpf 1.20 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
22 mike 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 kumpf 1.20 // 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 mike 1.2 // 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 <Pegasus/Common/Config.h>
|
35 david 1.30 #include <Pegasus/Common/Tracer.h>
|
36 mike 1.2 #include <cctype>
37 #include <cstdio>
|
38 kumpf 1.15 #include <Pegasus/Common/Constants.h>
|
39 mike 1.2 #include <Pegasus/Common/XmlParser.h>
40 #include <Pegasus/Common/XmlReader.h>
41 #include <Pegasus/Common/XmlWriter.h>
|
42 kumpf 1.21 #include <Pegasus/Common/System.h>
|
43 mike 1.2 #include <Pegasus/Common/Logger.h>
44 #include "CIMExportRequestDecoder.h"
|
45 david 1.30 #include <Pegasus/Common/CommonUTF.h>
|
46 humberto 1.43 #include <Pegasus/Common/MessageLoader.h>
|
47 kumpf 1.59 #include <Pegasus/Common/LanguageParser.h>
|
48 mike 1.2
49 PEGASUS_USING_STD;
50
51 PEGASUS_NAMESPACE_BEGIN
52
53 CIMExportRequestDecoder::CIMExportRequestDecoder(
|
54 kumpf 1.77 MessageQueueService* outputQueue,
55 Uint32 returnQueueId)
56 : Base(PEGASUS_QUEUENAME_EXPORTREQDECODER),
57 _outputQueue(outputQueue),
58 _returnQueueId(returnQueueId),
59 _serverTerminating(false)
|
60 mike 1.2 {
61 }
62
63 CIMExportRequestDecoder::~CIMExportRequestDecoder()
64 {
65 }
66
67 void CIMExportRequestDecoder::sendResponse(
|
68 ms.aruran 1.68 Uint32 queueId,
|
69 mike 1.58 Buffer& message,
|
70 j.alex 1.57 Boolean closeConnect)
|
71 mike 1.2 {
|
72 kumpf 1.77 MessageQueue* queue = MessageQueue::lookup(queueId);
|
73 mike 1.2
|
74 kumpf 1.77 if (queue)
75 {
76 HTTPMessage* httpMessage = new HTTPMessage(message);
77 httpMessage->setCloseConnect(closeConnect);
78 queue->enqueue(httpMessage);
79 }
|
80 mike 1.2 }
81
|
82 kumpf 1.7 void CIMExportRequestDecoder::sendEMethodError(
|
83 kumpf 1.77 Uint32 queueId,
84 HttpMethod httpMethod,
85 const String& messageId,
86 const String& eMethodName,
87 const CIMException& cimException,
88 Boolean closeConnect)
|
89 mike 1.2 {
|
90 mike 1.58 Buffer message;
|
91 kumpf 1.8 message = XmlWriter::formatSimpleEMethodErrorRspMessage(
92 eMethodName,
93 messageId,
|
94 kumpf 1.22 httpMethod,
|
95 kumpf 1.14 cimException);
|
96 kumpf 1.7
|
97 j.alex 1.57 sendResponse(queueId, message,closeConnect);
|
98 mike 1.2 }
99
|
100 kumpf 1.12 void CIMExportRequestDecoder::sendHttpError(
|
101 kumpf 1.77 Uint32 queueId,
102 const String& status,
103 const String& cimError,
104 const String& messageBody,
105 Boolean closeConnect)
|
106 kumpf 1.9 {
|
107 mike 1.58 Buffer message;
|
108 kumpf 1.12 message = XmlWriter::formatHttpErrorRspMessage(
109 status,
110 cimError,
111 messageBody);
|
112 kumpf 1.9
|
113 j.alex 1.57 sendResponse(queueId, message,closeConnect);
|
114 kumpf 1.9 }
|
115 mday 1.5
|
116 kumpf 1.77 void CIMExportRequestDecoder::handleEnqueue(Message* message)
|
117 mike 1.2 {
|
118 kumpf 1.77 PEGASUS_ASSERT(message != 0);
|
119 mike 1.2
|
120 kumpf 1.77 switch (message->getType())
121 {
|
122 karl 1.73 case HTTP_MESSAGE:
123 handleHTTPMessage((HTTPMessage*)message);
124 break;
|
125 carolann.graves 1.62
126 default:
127 PEGASUS_ASSERT(0);
128 break;
|
129 kumpf 1.77 }
|
130 mday 1.5
|
131 kumpf 1.77 delete message;
|
132 mday 1.5 }
|
133 mike 1.2
134
|
135 mday 1.5 void CIMExportRequestDecoder::handleEnqueue()
136 {
|
137 kumpf 1.77 Message* message = dequeue();
138 if (message)
139 handleEnqueue(message);
|
140 mike 1.2 }
141
142 //------------------------------------------------------------------------------
143 //
144 // From the HTTP/1.1 Specification (RFC 2626):
145 //
|
146 ms.aruran 1.68 // Both types of message consist of a start-line, zero or more header fields
147 // (also known as "headers"), an empty line (i.e., a line with nothing
148 // preceding the CRLF) indicating the end of the header fields, and possibly
|
149 mike 1.2 // a message-body.
150 //
151 // Example CIM request:
152 //
|
153 ms.aruran 1.68 // M-POST /cimom HTTP/1.1
154 // HOST: www.erewhon.com
155 // Content-Type: application/xml; charset="utf-8"
156 // Content-Length: xxxx
157 // Man: http://www.dmtf.org/cim/operation ; ns=73
|
158 mike 1.2 // 73-CIMExport: MethodRequest
159 // 73-CIMExportMethod: ExportIndication
|
160 ms.aruran 1.68 // 73-CIMObject: root/cimv2
161 //
|
162 mike 1.2 //------------------------------------------------------------------------------
163
164 void CIMExportRequestDecoder::handleHTTPMessage(HTTPMessage* httpMessage)
165 {
|
166 kumpf 1.78 PEGASUS_ASSERT(httpMessage->message.size() != 0);
167
168 // Save queueId and userName
|
169 mike 1.2
|
170 kumpf 1.77 Uint32 queueId = httpMessage->queueId;
|
171 kumpf 1.78 String userName = httpMessage->authInfo->getAuthenticatedUser();
|
172 kumpf 1.55
|
173 kumpf 1.77 Boolean closeConnect = httpMessage->getCloseConnect();
174 PEG_TRACE((
175 TRC_HTTP,
176 Tracer::LEVEL3,
177 "CIMOperationRequestDecoder::handleHTTPMessage() -"
178 " httpMessage->getCloseConnect() returned %d",
179 httpMessage->getCloseConnect()));
180
181 // Parse the HTTP message:
182
183 String startLine;
184 Array<HTTPHeader> headers;
185 char* content;
186 Uint32 contentLength;
187
188 httpMessage->parse(startLine, headers, contentLength);
189
190 // Parse the request line:
191
192 String methodName;
193 String requestUri;
194 kumpf 1.77 String httpVersion;
195 HttpMethod httpMethod = HTTP_METHOD__POST;
196
197 // ATTN-RK-P3-20020404: The requestUri may need to be pruned of the host
198 // name. All we care about at this point is the path.
199 HTTPMessage::parseRequestLine(
200 startLine, methodName, requestUri, httpVersion);
201
202 //
203 // Set HTTP method for the request
204 //
205 if (methodName == "M-POST")
206 {
207 httpMethod = HTTP_METHOD_M_POST;
208 }
|
209 kumpf 1.13
|
210 kumpf 1.77 // Unsupported methods are caught in the HTTPAuthenticatorDelegator
211 //<Bug #351>
212 //PEGASUS_ASSERT(methodName == "M-POST" || methodName == "POST");
213 if (methodName != "M-POST" && methodName != "POST")
214 {
215 sendHttpError(
216 queueId,
217 HTTP_STATUS_NOTIMPLEMENTED,
218 "Only POST and M-POST are implemented",
219 String::EMPTY,
220 closeConnect);
221 return;
222 }
223 //</bug>
224 //
225 // Not true: "Mismatch of method and version is caught in
226 // HTTPAuthenticatorDelegator", bug #351 fixes this:
227 //
228 //PEGASUS_ASSERT (!((httpMethod == HTTP_METHOD_M_POST) &&
229 // (httpVersion == "HTTP/1.0")));
230 if ((httpMethod == HTTP_METHOD_M_POST) &&
231 kumpf 1.77 (httpVersion == "HTTP/1.0"))
232 {
233 sendHttpError(
|
234 j.alex 1.57 queueId,
235 HTTP_STATUS_BADREQUEST,
|
236 kumpf 1.77 "M-POST method is not valid with version 1.0",
|
237 j.alex 1.57 String::EMPTY,
238 closeConnect);
|
239 kumpf 1.55 return;
|
240 kumpf 1.77 }
241 //</bug>
242
243 // Process M-POST and POST messages:
244 String cimContentType;
245 String cimExport;
246 String cimExportBatch;
247 Boolean cimExportBatchFlag;
248 String cimProtocolVersion;
249 String cimExportMethod;
250
251 if (httpVersion == "HTTP/1.1")
252 {
253 // Validate the presence of a "Host" header. The HTTP/1.1 specification
254 // says this in section 14.23 regarding the Host header field:
255 //
256 // All Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad
257 // Request) status code to any HTTP/1.1 request message which lacks
258 // a Host header field.
259 //
260 // Note: The Host header value is not validated.
261 kumpf 1.77
262 String hostHeader;
263 Boolean hostHeaderFound = HTTPMessage::lookupHeader(
264 headers, "Host", hostHeader, false);
265
266 if (!hostHeaderFound)
267 {
268 MessageLoaderParms parms(
269 "ExportServer.CIMExportRequestDecoder.MISSING_HOST_HEADER",
270 "HTTP request message lacks a Host header field.");
271 String msg(MessageLoader::getMessage(parms));
272 sendHttpError(
273 queueId,
274 HTTP_STATUS_BADREQUEST,
275 "",
276 msg,
277 closeConnect);
278 return;
279 }
280 }
281
282 kumpf 1.77 // Validate the "CIMExport" header:
283
284 Boolean exportHeaderFound = HTTPMessage::lookupHeader(
285 headers, "CIMExport", cimExport, true);
286 // If the CIMExport header was missing, the HTTPAuthenticatorDelegator
287 // would not have passed the message to us.
288
289 // <bug #351>
290 // PEGASUS_ASSERT(exportHeaderFound);
291 if (!exportHeaderFound)
292 {
293 sendHttpError(
|
294 ms.aruran 1.68 queueId,
295 HTTP_STATUS_BADREQUEST,
|
296 kumpf 1.77 "Export header not found",
|
297 j.alex 1.57 String::EMPTY,
298 closeConnect);
|
299 kumpf 1.13 return;
|
300 kumpf 1.77 }
301 // </bug>
302
303 if (!String::equalNoCase(cimExport, "MethodRequest"))
304 {
305 // The Specification for CIM Operations over HTTP reads:
306 // 3.3.5. CIMExport
307 // If a CIM Listener receives CIM Export request with this
308 // header, but with a missing value or a value that is not
309 // "MethodRequest", then it MUST fail the request with
310 // status "400 Bad Request". The CIM Server MUST include a
311 // CIMError header in the response with a value of
312 // unsupported-operation.
313 sendHttpError(
314 queueId,
315 HTTP_STATUS_BADREQUEST,
316 "unsupported-operation",
317 String::EMPTY,
318 closeConnect);
319 return;
320 }
|
321 kumpf 1.10
|
322 kumpf 1.77 // Validate the "CIMExportBatch" header:
323
324 cimExportBatchFlag = HTTPMessage::lookupHeader(
325 headers, "CIMExportBatch", cimExportBatch, true);
326 if (cimExportBatchFlag)
327 {
328 // The Specification for CIM Operations over HTTP reads:
329 // 3.3.10. CIMExportBatch
330 // If a CIM Listener receives CIM Export Request for which the
331 // CIMExportBatch header is present, but the Listener does not
332 // support Multiple Exports, then it MUST fail the request and
333 // return a status of "501 Not Implemented".
334 sendHttpError(
335 queueId,
336 HTTP_STATUS_NOTIMPLEMENTED,
337 "multiple-requests-unsupported",
338 String::EMPTY,
339 closeConnect);
340 return;
341 }
342
343 kumpf 1.77 // Save these headers for later checking
344
345 if (!HTTPMessage::lookupHeader(
346 headers, "CIMProtocolVersion", cimProtocolVersion, true))
347 {
348 // Mandated by the Specification for CIM Operations over HTTP
349 cimProtocolVersion.assign("1.0");
350 }
351
352 if (HTTPMessage::lookupHeader(
353 headers, "CIMExportMethod", cimExportMethod, true))
354 {
355 if (cimExportMethod == String::EMPTY)
356 {
357 // This is not a valid value, and we use EMPTY to mean "absent"
358 sendHttpError(
359 queueId,
360 HTTP_STATUS_BADREQUEST,
361 "header-mismatch",
362 String::EMPTY,
363 closeConnect);
364 kumpf 1.77 return;
|
365 karl 1.73 }
366 }
367
|
368 kumpf 1.77 AcceptLanguageList acceptLanguages;
369 ContentLanguageList contentLanguages;
370 try
371 {
372 if (httpMessage->acceptLanguagesDecoded)
373 {
374 acceptLanguages = httpMessage->acceptLanguages;
375 }
376 else
377 {
378 // Get and validate the Accept-Language header, if set
379 String acceptLanguageHeader;
380 if (HTTPMessage::lookupHeader(
381 headers,
382 "Accept-Language",
383 acceptLanguageHeader,
384 false))
385 {
386 acceptLanguages = LanguageParser::parseAcceptLanguageHeader(
387 acceptLanguageHeader);
388 }
389 kumpf 1.77 }
390
391 if (httpMessage->contentLanguagesDecoded)
392 {
393 contentLanguages = httpMessage->contentLanguages;
394 }
395 else
396 {
397 // Get and validate the Content-Language header, if set
398 String contentLanguageHeader;
399 if (HTTPMessage::lookupHeader(
400 headers,
401 "Content-Language",
402 contentLanguageHeader,
403 false))
404 {
405 contentLanguages = LanguageParser::parseContentLanguageHeader(
406 contentLanguageHeader);
407 }
|
408 karl 1.73 }
409 }
|
410 kumpf 1.77 catch (Exception& e)
411 {
412 Thread::clearLanguages();
413 MessageLoaderParms msgParms(
414 "ExportServer.CIMExportRequestDecoder.REQUEST_NOT_VALID",
|
415 karl 1.73 "request-not-valid");
|
416 kumpf 1.77 String msg(MessageLoader::getMessage(msgParms));
417 sendHttpError(
|
418 ms.aruran 1.68 queueId,
419 HTTP_STATUS_BADREQUEST,
|
420 j.alex 1.57 msg,
421 e.getMessage(),
|
422 ms.aruran 1.68 closeConnect);
|
423 karl 1.73 return;
|
424 kumpf 1.77 }
|
425 chuck 1.27
|
426 kumpf 1.77 // Calculate the beginning of the content from the message size and
427 // the content length.
|
428 mike 1.2
|
429 kumpf 1.77 content = (char *) httpMessage->message.getData() +
430 httpMessage->message.size() - contentLength;
|
431 chuck 1.40
|
432 kumpf 1.77 // Validate the "Content-Type" header:
|
433 chuck 1.40
|
434 kumpf 1.77 Boolean contentTypeHeaderFound = HTTPMessage::lookupHeader(
435 headers, "Content-Type", cimContentType, true);
436
|
437 venkat.puvvada 1.79 if (!contentTypeHeaderFound ||
438 !HTTPMessage::isSupportedContentType (cimContentType))
|
439 kumpf 1.77 {
440 sendHttpError(
441 queueId,
442 HTTP_STATUS_BADREQUEST,
443 "",
444 "HTTP Content-Type header error.",
445 closeConnect);
446 return;
447 }
448 else
449 {
450 // Validating content falls within UTF8 (required to be complaint
451 // with section C12 of Unicode 4.0 spec, chapter 3.)
452 Uint32 count = 0;
453 while(count<contentLength)
454 {
455 if (!(isUTF8((char *)&content[count])))
456 {
457 sendHttpError(
458 queueId,
459 HTTP_STATUS_BADREQUEST,
460 kumpf 1.77 "request-not-valid",
461 "Invalid UTF-8 character detected.",
462 closeConnect);
463 return;
464 }
465 UTF8_NEXT(content,count);
466 }
467 }
468
469 // If it is a method call, then dispatch it to be handled:
470
471 handleMethodRequest(
472 queueId,
473 httpMethod,
474 content,
475 requestUri,
476 cimProtocolVersion,
477 cimExportMethod,
478 userName,
479 httpMessage->ipAddress,
480 acceptLanguages,
481 kumpf 1.77 contentLanguages,
482 closeConnect);
|
483 mike 1.2 }
484
485 void CIMExportRequestDecoder::handleMethodRequest(
|
486 j.alex 1.57 Uint32 queueId,
487 HttpMethod httpMethod,
488 char* content,
489 const String& requestUri,
490 const String& cimProtocolVersionInHeader,
491 const String& cimExportMethodInHeader,
492 const String& userName,
|
493 kumpf 1.65 const String& ipAddress,
|
494 kumpf 1.60 const AcceptLanguageList& httpAcceptLanguages,
495 const ContentLanguageList& httpContentLanguages,
|
496 ms.aruran 1.68 Boolean closeConnect)
|
497 mday 1.5 {
|
498 karl 1.73 // Set the Accept-Language into the thread for this service.
499 // This will allow all code in this thread to get
500 // the languages for the messages returned to the client.
501 Thread::setLanguages(new AcceptLanguageList(httpAcceptLanguages));
|
502 chuck 1.28
|
503 kumpf 1.77 //
504 // If CIM Listener is shutting down, return error response
505 //
506 if (_serverTerminating)
507 {
508 sendHttpError(
509 queueId,
510 HTTP_STATUS_SERVICEUNAVAILABLE,
511 String::EMPTY,
512 "CIM Listener is shutting down.",
513 closeConnect);
514 return;
515 }
516
517 // Create a parser:
518
519 XmlParser parser(content);
520 XmlEntry entry;
521 String messageId;
522 const char* cimExportMethodName = "";
523 AutoPtr<CIMExportIndicationRequestMessage> request;
524 kumpf 1.77
525 try
526 {
527 //
528 // Process <?xml ... >
529 //
530
531 // These values are currently unused
532 const char* xmlVersion = 0;
533 const char* xmlEncoding = 0;
534
535 XmlReader::getXmlDeclaration(parser, xmlVersion, xmlEncoding);
536
537 // Expect <CIM ...>
538
539 const char* cimVersion = 0;
540 const char* dtdVersion = 0;
541
542 XmlReader::getCimStartTag(parser, cimVersion, dtdVersion);
543
544 if (!XmlReader::isSupportedCIMVersion(cimVersion))
545 kumpf 1.77 {
546 sendHttpError(
547 queueId,
548 HTTP_STATUS_NOTIMPLEMENTED,
549 "unsupported-cim-version",
550 String::EMPTY,
551 closeConnect);
552 return;
553 }
554
555 if (!XmlReader::isSupportedDTDVersion(dtdVersion))
556 {
557 sendHttpError(
558 queueId,
559 HTTP_STATUS_NOTIMPLEMENTED,
560 "unsupported-dtd-version",
561 String::EMPTY,
562 closeConnect);
563 return;
564 }
565
566 kumpf 1.77 // Expect <MESSAGE ...>
567
568 String protocolVersion;
569 if (!XmlReader::getMessageStartTag(
570 parser, messageId, protocolVersion))
571 {
572 MessageLoaderParms mlParms(
573 "ExportServer.CIMExportRequestDecoder.EXPECTED_MESSAGE_ELEMENT",
574 "expected MESSAGE element");
575
576 throw XmlValidationError(parser.getLine(), mlParms);
577 }
578
579 // Validate that the protocol version in the header matches the XML
580
581 if (!String::equalNoCase(protocolVersion, cimProtocolVersionInHeader))
582 {
583 sendHttpError(
584 queueId,
585 HTTP_STATUS_BADREQUEST,
586 "header-mismatch",
587 kumpf 1.77 String::EMPTY,
588 closeConnect);
589 return;
590 }
591
592 // We accept protocol version 1.x (see Bugzilla 1556)
593
594 Boolean protocolVersionAccepted = false;
595
596 if ((protocolVersion.size() >= 3) &&
597 (protocolVersion[0] == '1') &&
598 (protocolVersion[1] == '.'))
599 {
600 // Verify that all characters after the '.' are digits
601 Uint32 index = 2;
602 while ((index < protocolVersion.size()) &&
603 (protocolVersion[index] >= '0') &&
604 (protocolVersion[index] <= '9'))
605 {
606 index++;
607 }
608 kumpf 1.77
609 if (index == protocolVersion.size())
610 {
611 protocolVersionAccepted = true;
612 }
613 }
614
615 if (!protocolVersionAccepted)
616 {
617 // See Specification for CIM Operations over HTTP section 4.3
618 sendHttpError(
619 queueId,
620 HTTP_STATUS_NOTIMPLEMENTED,
621 "unsupported-protocol-version",
622 String::EMPTY,
623 closeConnect);
624 return;
625 }
626
627 if (XmlReader::testStartTag(parser, entry, "MULTIEXPREQ"))
628 {
629 kumpf 1.77 // We wouldn't have gotten here if CIMExportBatch header was
630 // specified, so this must be indicative of a header mismatch
631 sendHttpError(
632 queueId,
633 HTTP_STATUS_BADREQUEST,
634 "header-mismatch",
635 String::EMPTY,
636 closeConnect);
637 return;
638 // Future: When MULTIEXPREQ is supported, must ensure
639 // CIMExportMethod header is absent, and CIMExportBatch header
640 // is present.
641 }
|
642 kumpf 1.10
|
643 kumpf 1.77 // Expect <SIMPLEEXPREQ ...>
|
644 mday 1.5
|
645 kumpf 1.77 XmlReader::expectStartTag(parser, entry, "SIMPLEEXPREQ");
|
646 mday 1.5
|
647 kumpf 1.77 // Expect <EXPMETHODCALL ...>
|
648 humberto 1.32
|
649 kumpf 1.77 if (!XmlReader::getEMethodCallStartTag(parser, cimExportMethodName))
650 {
651 MessageLoaderParms mlParms(
652 "ExportServer.CIMExportRequestDecoder."
653 "EXPECTED_EXPMETHODCALL_ELEMENT",
654 "expected EXPMETHODCALL element");
|
655 humberto 1.32
|
656 kumpf 1.77 throw XmlValidationError(parser.getLine(), mlParms);
657 }
|
658 humberto 1.32
|
659 kumpf 1.77 // The Specification for CIM Operations over HTTP reads:
660 // 3.3.9. CIMExportMethod
661 //
662 // This header MUST be present in any CIM Export Request
663 // message that contains a Simple Export Request.
664 //
665 // It MUST NOT be present in any CIM Export Response message,
666 // nor in any CIM Export Request message that is not a
667 // Simple Export Request. It MUST NOT be present in any CIM
668 // Operation Request or Response message.
669 //
670 // The name of the CIM export method within a Simple Export
671 // Request is defined to be the value of the NAME attribute
672 // of the <EXPMETHODCALL> element.
673 //
674 // If a CIM Listener receives a CIM Export Request for which
675 // either:
676 //
677 // - The CIMExportMethod header is present but has an invalid
678 // value, or;
679 // - The CIMExportMethod header is not present but the Export
680 kumpf 1.77 // Request Message is a Simple Export Request, or;
681 // - The CIMExportMethod header is present but the Export
682 // Request Message is not a Simple Export Request, or;
683 // - The CIMExportMethod header is present, the Export Request
684 // Message is a Simple Export Request, but the CIMIdentifier
685 // value (when unencoded) does not match the unique method
686 // name within the Simple Export Request,
687 //
688 // then it MUST fail the request and return a status of
689 // "400 Bad Request" (and MUST include a CIMError header in the
690 // response with a value of header-mismatch), subject to the
691 // considerations specified in Errors.
692 if (!String::equalNoCase(cimExportMethodName, cimExportMethodInHeader))
693 {
694 // ATTN-RK-P3-20020404: How to decode cimExportMethodInHeader?
695 sendHttpError(
696 queueId,
697 HTTP_STATUS_BADREQUEST,
698 "header-mismatch",
699 String::EMPTY,
700 closeConnect);
701 kumpf 1.77 return;
702 }
|
703 mday 1.5
|
704 kumpf 1.77 // This try block only catches CIMExceptions, because they must be
705 // responded to with a proper EMETHODRESPONSE. Other exceptions are
706 // caught in the outer try block.
707 try
708 {
709 // Delegate to appropriate method to handle:
|
710 kumpf 1.10
|
711 kumpf 1.77 if (System::strcasecmp(
712 cimExportMethodName, "ExportIndication") == 0)
713 {
714 request.reset(decodeExportIndicationRequest(
715 queueId, parser, messageId, requestUri));
716 }
717 else
718 {
719 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_NOT_SUPPORTED,
720 MessageLoaderParms(
721 "ExportServer.CIMExportRequestDecoder."
722 "UNRECOGNIZED_EXPORT_METHOD",
723 "Unrecognized export method: $0",
724 cimExportMethodName));
725 }
726 }
727 catch (CIMException& e)
728 {
729 sendEMethodError(
730 queueId,
731 httpMethod,
732 kumpf 1.77 messageId,
733 cimExportMethodName,
734 e,
735 closeConnect);
|
736 kumpf 1.10
|
737 kumpf 1.77 return;
738 }
|
739 kumpf 1.47
|
740 kumpf 1.77 // Expect </EXPMETHODCALL>
|
741 kumpf 1.47
|
742 kumpf 1.77 XmlReader::expectEndTag(parser, "EXPMETHODCALL");
|
743 ms.aruran 1.68
|
744 kumpf 1.77 // Expect </SIMPLEEXPREQ>
|
745 mday 1.5
|
746 kumpf 1.77 XmlReader::expectEndTag(parser, "SIMPLEEXPREQ");
|
747 ms.aruran 1.68
|
748 kumpf 1.77 // Expect </MESSAGE>
|
749 mike 1.2
|
750 kumpf 1.77 XmlReader::expectEndTag(parser, "MESSAGE");
|
751 mike 1.2
|
752 kumpf 1.77 // Expect </CIM>
|
753 mike 1.2
|
754 kumpf 1.77 XmlReader::expectEndTag(parser, "CIM");
755 }
756 catch (XmlValidationError& e)
757 {
758 Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::TRACE,
759 "CIMExportRequestDecoder::handleMethodRequest - "
760 "XmlValidationError exception has occurred. Message: $0",
761 e.getMessage());
|
762 mike 1.2
|
763 kumpf 1.77 sendHttpError(
764 queueId,
765 HTTP_STATUS_BADREQUEST,
766 "request-not-valid",
767 e.getMessage(),
768 closeConnect);
769 return;
770 }
771 catch (XmlSemanticError& e)
772 {
773 Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::TRACE,
774 "CIMExportRequestDecoder::handleMethodRequest - "
775 "XmlSemanticError exception has occurred. Message: $0",
776 e.getMessage());
777 // ATTN-RK-P2-20020404: Is this the correct response for these errors?
778 sendHttpError(
779 queueId,
780 HTTP_STATUS_BADREQUEST,
781 "request-not-valid",
782 e.getMessage(),
783 closeConnect);
784 kumpf 1.77 return;
785 }
786 catch (XmlException& e)
787 {
788 Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::TRACE,
789 "CIMExportRequestDecoder::handleMethodRequest - "
790 "XmlException has occurred. Message: $0",e.getMessage());
|
791 mike 1.2
|
792 kumpf 1.77 sendHttpError(
793 queueId,
794 HTTP_STATUS_BADREQUEST,
795 "request-not-well-formed",
796 e.getMessage(),
797 closeConnect);
798 return;
799 }
800 catch (Exception& e)
801 {
802 // Don't know why I got this exception. Seems like a bad thing.
803 // Any exceptions we're expecting should be caught separately and
804 // dealt with appropriately. This is a last resort.
805 sendHttpError(
806 queueId,
807 HTTP_STATUS_INTERNALSERVERERROR,
808 String::EMPTY,
809 e.getMessage(),
810 closeConnect);
811 return;
812 }
813 kumpf 1.77 catch (...)
814 {
815 // Don't know why I got whatever this is. Seems like a bad thing.
816 // Any exceptions we're expecting should be caught separately and
817 // dealt with appropriately. This is a last resort.
818 sendHttpError(
819 queueId,
820 HTTP_STATUS_INTERNALSERVERERROR,
821 String::EMPTY,
822 String::EMPTY,
823 closeConnect);
824 return;
825 }
|
826 chuck 1.27
827 // l10n TODO - might want to move A-L and C-L to Message
828 // to make this more maintainable
|
829 karl 1.73 // Add the language headers to the request.
830 // Note: Since the text of an export error response will be ignored
831 // by the export client, ignore Accept-Language in the export request.
832 // This will cause any export error response message to be sent in the
833 // default language.
834 request->operationContext.insert(IdentityContainer(userName));
835 request->operationContext.set(
|
836 kumpf 1.77 ContentLanguageListContainer(httpContentLanguages));
|
837 karl 1.73 request->operationContext.set(
|
838 kumpf 1.77 AcceptLanguageListContainer(AcceptLanguageList()));
|
839 mike 1.2
|
840 kumpf 1.77 request->ipAddress = ipAddress;
|
841 kumpf 1.65
|
842 kumpf 1.77 request->setCloseConnect(closeConnect);
|
843 j.alex 1.57
|
844 kumpf 1.77 _outputQueue->enqueue(request.release());
|
845 mike 1.2 }
846
|
847 kumpf 1.77 CIMExportIndicationRequestMessage*
|
848 karl 1.73 CIMExportRequestDecoder::decodeExportIndicationRequest(
|
849 kumpf 1.77 Uint32 queueId,
850 XmlParser& parser,
851 const String& messageId,
852 const String& requestUri)
853 {
854 CIMInstance instanceName;
855
856 String destStr = requestUri.subString(
857 requestUri.find("/CIMListener") + 12, PEG_NOT_FOUND);
858
859 for (const char* name; XmlReader::getEParamValueTag(parser, name);)
860 {
861 if (System::strcasecmp(name, "NewIndication") == 0)
862 {
863 XmlReader::getInstanceElement(parser, instanceName);
864 }
865 else
866 {
867 MessageLoaderParms mlParms(
868 "ExportServer.CIMExportRequestDecoder."
869 "UNRECOGNIZED_EXPPARAMVALUE_NAME",
870 kumpf 1.77 "Unrecognized EXPPARAMVALUE Name $0", name);
871 throw PEGASUS_CIM_EXCEPTION(CIM_ERR_NOT_SUPPORTED, mlParms);
872 }
873
874 XmlReader::expectEndTag(parser, "EXPPARAMVALUE");
875 }
876
877 CIMExportIndicationRequestMessage* request =
878 new CIMExportIndicationRequestMessage(
879 messageId,
880 destStr,
881 instanceName,
882 QueueIdStack(queueId, _returnQueueId));
|
883 ms.aruran 1.68
|
884 kumpf 1.77 return request;
|
885 mike 1.2 }
886
887 void CIMExportRequestDecoder::setServerTerminating(Boolean flag)
888 {
|
889 kumpf 1.77 _serverTerminating = flag;
|
890 mike 1.2 }
891
892 PEGASUS_NAMESPACE_END
|