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