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