00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00036 #include "OW_config.h"
00037 #include "OW_HTTPSvrConnection.hpp"
00038 #include "OW_IOException.hpp"
00039 #include "OW_HTTPStatusCodes.hpp"
00040 #include "OW_TempFileStream.hpp"
00041 #include "OW_HTTPChunkedIStream.hpp"
00042 #include "OW_HTTPChunkedOStream.hpp"
00043 #include "OW_HTTPDeflateIStream.hpp"
00044 #include "OW_HTTPDeflateOStream.hpp"
00045 #include "OW_HTTPLenLimitIStream.hpp"
00046 #include "OW_Select.hpp"
00047 #include "OW_Format.hpp"
00048 #include "OW_ConfigOpts.hpp"
00049 #include "OW_Assertion.hpp"
00050 #include "OW_TempFileStream.hpp"
00051 #include "OW_CIMErrorException.hpp"
00052 #include "OW_CIMFeatures.hpp"
00053 #include "OW_HTTPException.hpp"
00054 #include "OW_CIMOMHandleIFC.hpp"
00055 #include "OW_SortedVectorMap.hpp"
00056 #include "OW_StringBuffer.hpp"
00057 #include "OW_ThreadCancelledException.hpp"
00058 #include "OW_OperationContext.hpp"
00059 #include "OW_SessionLanguage.hpp"
00060 #include "OW_AuthenticationException.hpp"
00061
00062 #if defined(BAD)
00063 #undef BAD
00064 #endif
00065
00066 #include <iostream>
00067
00068 namespace OW_NAMESPACE
00069 {
00070
00071 using std::ios;
00072 using std::istream;
00073 using std::ostream;
00074 using std::flush;
00075 using std::cout;
00076 using std::cerr;
00077 using std::endl;
00078
00079 namespace
00080 {
00081 const String COMPONENT_NAME("ow.httpserver");
00082 }
00083
00084 #define OW_LOGDEBUG(x) OW_LOG_DEBUG(m_options.env->getLogger(COMPONENT_NAME), x)
00085 #define OW_LOGERROR(x) OW_LOG_ERROR(m_options.env->getLogger(COMPONENT_NAME), x)
00086 #define OW_LOGCUSTINFO(x) OW_LOG_INFO(m_options.env->getLogger(COMPONENT_NAME), x)
00087 #define OW_LOGFATALERROR(x) OW_LOG_FATAL_ERROR(m_options.env->getLogger(COMPONENT_NAME), x)
00088
00090 #ifdef OW_WIN32
00091 HTTPSvrConnection::HTTPSvrConnection(
00092 const Socket& socket,
00093 HTTPServer* htin,
00094 HANDLE eventArg,
00095 const HTTPServer::Options& opts)
00096 #else
00097 HTTPSvrConnection::HTTPSvrConnection(const Socket& socket,
00098 HTTPServer* htin,
00099 IntrusiveReference<UnnamedPipe>& upipe,
00100 const HTTPServer::Options& opts)
00101 #endif
00102 : Runnable()
00103 , m_requestLine()
00104 , m_requestHeaders()
00105 , m_pHTTPServer(htin)
00106 , m_socket(socket)
00107 , m_ostr(m_socket.getOutputStream())
00108 , m_resCode(SC_OK)
00109 , m_needSendError(false)
00110 , m_responseHeaders()
00111 , m_httpVersion(HTTP_VER_BAD)
00112 , m_method(BAD)
00113 , m_istr(m_socket.getInputStream())
00114 , m_isClose(false)
00115 , m_contentLength(-1)
00116 , m_chunkedIn(false)
00117 , m_deflateCompressionIn(false)
00118 , m_deflateCompressionOut(false)
00119 , m_errDetails()
00120 , m_reqHeaderPrefix()
00121 , m_respHeaderPrefix()
00122 , m_isAuthenticated(false)
00123 #ifdef OW_WIN32
00124 , m_event(eventArg)
00125 #else
00126 , m_upipe(upipe)
00127 #endif
00128 , m_chunkedOut(false)
00129 , m_userName()
00130 , m_clientIsOpenWBEM2(false)
00131 , m_requestHandler()
00132 , m_options(opts)
00133 , m_shutdown(false)
00134 {
00135 m_socket.setTimeouts(m_options.timeout);
00136 }
00138
00139 HTTPSvrConnection::~HTTPSvrConnection()
00140 {
00141 try
00142 {
00143 m_socket.disconnect();
00144 }
00145 catch (...)
00146 {
00147
00148 }
00149 }
00151 void
00152 HTTPSvrConnection::run()
00153 {
00154 CIMProtocolIStreamIFCRef istrToReadFrom(0);
00155 SelectTypeArray selArray;
00156 #ifdef OW_WIN32
00157 Select_t st;
00158 st.event = m_event;
00159 selArray.push_back(st);
00160 #else
00161 selArray.push_back(m_upipe->getSelectObj());
00162 #endif
00163 selArray.push_back(m_socket.getSelectObj());
00164 try
00165 {
00166 m_isAuthenticated = false;
00167 OperationContext context;
00168 while (m_istr.good())
00169 {
00170
00171 m_errDetails.erase();
00172 m_requestLine.clear();
00173 m_requestHeaders.clear();
00174 m_reqHeaderPrefix.erase();
00175 m_responseHeaders.clear();
00176 m_needSendError = false;
00177 m_resCode = SC_OK;
00178 m_contentLength = -1;
00179 m_chunkedIn = false;
00180
00181
00182
00183 addHeader("Date",
00184 HTTPUtils::date());
00185 addHeader("Cache-Control",
00186 "no-cache");
00187 addHeader("Server",
00188 OW_PACKAGE "/" OW_VERSION " (CIMOM)");
00189
00190
00191 if (m_istr.rdbuf()->in_avail() == 0)
00192 {
00193 int selType = Select::SELECT_INTERRUPTED;
00194 while(selType == Select::SELECT_INTERRUPTED)
00195 {
00196 selType = Select::select(selArray, m_options.timeout * 1000);
00197 }
00198
00199 if (selType == Select::SELECT_ERROR)
00200 {
00201 OW_THROW(SocketException, "Error occurred during select()");
00202 }
00203 if (selType == Select::SELECT_TIMEOUT)
00204 {
00205 m_resCode = SC_REQUEST_TIMEOUT;
00206 m_errDetails = "Timeout waiting for request.";
00207 sendError(m_resCode);
00208 return;
00209 }
00210 if (selType == 0)
00211 {
00212 m_resCode = SC_SERVICE_UNAVAILABLE;
00213 m_errDetails = "Server is shutting down."
00214 " Please try again later.";
00215 sendError(m_resCode);
00216 return;
00217 }
00218 }
00219 else
00220 {
00221
00222 int selType = Select::select(selArray, 0);
00223 if (selType == 0)
00224 {
00225 m_resCode = SC_SERVICE_UNAVAILABLE;
00226 m_errDetails = "Server is shutting down."
00227 " Please try again later.";
00228 sendError(m_resCode);
00229 return;
00230 }
00231 }
00232
00233 if (!HTTPUtils::parseHeader(m_requestHeaders, m_requestLine, m_istr))
00234 {
00235 if (m_shutdown)
00236 {
00237 m_errDetails = "Server is shutting down!";
00238 m_resCode = SC_INTERNAL_SERVER_ERROR;
00239 }
00240 else if (!m_istr)
00241 {
00242
00243 return;
00244 }
00245 else
00246 {
00247 m_errDetails = "There was a problem parsing the request Header";
00248 m_resCode = SC_BAD_REQUEST;
00249 }
00250 sendError(m_resCode);
00251 return;
00252 }
00253
00254
00255
00256 m_resCode = processRequestLine();
00257 if (m_resCode >= 300)
00258 {
00259 sendError(m_resCode);
00260 return;
00261 }
00262
00263
00264 context.setStringData(OperationContext::CLIENT_IPADDR, m_socket.getPeerAddress().toString());
00265 context.setStringData(OperationContext::HTTP_PATH, m_requestLine[1]);
00266
00267
00268
00269
00270 m_resCode = processHeaders(context);
00271 istrToReadFrom = convertToFiniteStream(m_istr);
00272 if (m_resCode >= 300)
00273 {
00274 cleanUpIStreams(istrToReadFrom);
00275 sendError(m_resCode);
00276 return;
00277 }
00278
00279
00280
00281
00282 switch (m_method)
00283 {
00284 case TRACE:
00285 trace();
00286 break;
00287 case M_POST:
00288 case POST:
00289 if (!istrToReadFrom)
00290 {
00291 OW_THROW(HTTPException,
00292 "POST, but no content-length or chunking");
00293 }
00294 post(*istrToReadFrom, context);
00295 break;
00296 case OPTIONS:
00297 options(context);
00298 break;
00299 default:
00300
00301 m_errDetails = "This should never happen.";
00302 m_resCode = SC_INTERNAL_SERVER_ERROR;
00303 cleanUpIStreams(istrToReadFrom);
00304 sendError(m_resCode);
00305 return;
00306 }
00307 m_ostr.flush();
00308 cleanUpIStreams(istrToReadFrom);
00309 if (m_isClose)
00310 {
00311 break;
00312 }
00313 }
00314 }
00315 catch (CIMErrorException& cee)
00316 {
00317 addHeader("CIMError", cee.getMessage());
00318 if (m_errDetails.empty())
00319 {
00320 m_errDetails = String("CIMError: ") + cee.getMessage();
00321 }
00322 cleanUpIStreams(istrToReadFrom);
00323 String errMsg(cee.getMessage());
00324 if (errMsg == CIMErrorException::unsupported_protocol_version ||
00325 errMsg == CIMErrorException::multiple_requests_unsupported ||
00326 errMsg == CIMErrorException::unsupported_cim_version ||
00327 errMsg == CIMErrorException::unsupported_dtd_version)
00328 {
00329 sendError(SC_NOT_IMPLEMENTED);
00330 }
00331 else
00332 {
00333 sendError(SC_BAD_REQUEST);
00334 }
00335 }
00336 catch (Exception& e)
00337 {
00338 OW_LOGERROR(Format("%1", e));
00339 m_errDetails = e.getMessage();
00340 cleanUpIStreams(istrToReadFrom);
00341 sendError(SC_INTERNAL_SERVER_ERROR);
00342 }
00343
00344 #if !defined(__GNUC__) || __GNUC__ > 2
00345 catch (std::ios_base::failure& e)
00346 {
00347
00348 OW_LOGDEBUG("Caught std::ios_base::failure, client has closed the connection");
00349 }
00350 #endif
00351 catch (std::exception& e)
00352 {
00353 m_errDetails = Format("Caught std::exception (%1) in HTTPSvrConnection::run()", e.what());
00354 OW_LOGERROR(m_errDetails);
00355 cleanUpIStreams(istrToReadFrom);
00356 sendError(SC_INTERNAL_SERVER_ERROR);
00357 }
00358 catch (ThreadCancelledException&)
00359 {
00360 OW_LOGERROR("Got Thread Cancelled Exception in HTTPSvrConnection::run()");
00361 m_errDetails = "HTTP Server thread cancelled";
00362 cleanUpIStreams(istrToReadFrom);
00363 sendError(SC_INTERNAL_SERVER_ERROR);
00364 throw;
00365 }
00366 catch (...)
00367 {
00368 OW_LOGERROR("Got Unknown Exception in HTTPSvrConnection::run()");
00369 m_errDetails = "HTTP Server caught unknown exception";
00370 cleanUpIStreams(istrToReadFrom);
00371 sendError(SC_INTERNAL_SERVER_ERROR);
00372 }
00373
00374 }
00375 void
00376 HTTPSvrConnection::cleanUpIStreams(const CIMProtocolIStreamIFCRef& istr)
00377 {
00378 if (istr)
00379 {
00380 HTTPUtils::eatEntity(*istr);
00381 }
00382 }
00383 void
00384 HTTPSvrConnection::beginPostResponse()
00385 {
00386 m_respHeaderPrefix = HTTPUtils::getCounterStr();
00387 addHeader(
00388 "Content-Type", m_requestHandler->getContentType() + "; charset=\"utf-8\"");
00389 if (m_method == M_POST)
00390 {
00391 addHeader("Ext","");
00392 }
00393 addHeader("Man",
00394 "http://www.dmtf.org/cim/mapping/http/v1.0 ; ns=" + m_respHeaderPrefix);
00395 m_respHeaderPrefix += "-";
00396 if (m_deflateCompressionOut && m_chunkedOut)
00397 {
00398 addHeader("Content-Encoding", "deflate");
00399 }
00400 if (m_chunkedOut)
00401 {
00402 addHeader( "Transfer-Encoding", "chunked");
00403 addHeader(m_respHeaderPrefix + "CIMOperation", "MethodResponse");
00404 if (m_clientIsOpenWBEM2)
00405 {
00406 addHeader("Trailer",
00407 m_respHeaderPrefix + "CIMError, "
00408 + m_respHeaderPrefix + "CIMErrorCode, "
00409 + m_respHeaderPrefix + "CIMErrorDescription");
00410 }
00411 else
00412 {
00413 addHeader("Trailer",
00414 m_respHeaderPrefix + "CIMError, "
00415 + m_respHeaderPrefix + "CIMStatusCode, "
00416 + m_respHeaderPrefix + "CIMStatusDescription");
00417 }
00418 sendHeaders(m_resCode);
00419 }
00420 }
00422 void
00423 HTTPSvrConnection::initRespStream(ostream*& ostrEntity)
00424 {
00425 OW_ASSERT(ostrEntity == 0);
00426
00427
00428
00429 #ifdef OW_HAVE_ZLIB_H
00430 m_HTTPDeflateOStreamRef = 0;
00431 #endif
00432 m_HTTPChunkedOStreamRef = 0;
00433 m_TempFileStreamRef = 0;
00434
00435 if (m_chunkedOut)
00436 {
00437 m_HTTPChunkedOStreamRef = new HTTPChunkedOStream(m_ostr);
00438 ostrEntity = m_HTTPChunkedOStreamRef.getPtr();
00439 ostrEntity->exceptions(std::ios::badbit);
00440 if (m_deflateCompressionOut)
00441 {
00442 #ifdef OW_HAVE_ZLIB_H
00443 m_HTTPDeflateOStreamRef = new HTTPDeflateOStream(*ostrEntity);
00444 ostrEntity = m_HTTPDeflateOStreamRef.getPtr();
00445 ostrEntity->exceptions(std::ios::badbit);
00446 #else
00447 OW_THROW(HTTPException, "Trying to deflate output, but no zlib!");
00448 #endif
00449 }
00450 }
00451 else
00452 {
00453 m_TempFileStreamRef = new TempFileStream;
00454 ostrEntity = m_TempFileStreamRef.getPtr();
00455 ostrEntity->exceptions(std::ios::badbit);
00456 }
00457 }
00459 void
00460 HTTPSvrConnection::sendPostResponse(ostream* ostrEntity,
00461 TempFileStream& ostrError, OperationContext& context)
00462 {
00463 int clen = -1;
00464 Int32 errCode = 0;
00465 String errDescr = "";
00466 if (!m_chunkedOut)
00467 {
00468 ostream* ostrToSend = ostrEntity;
00469
00470
00471
00472
00473 bool clientSpecified, setByProvider;
00474 String clang = getContentLanguage(context, setByProvider,
00475 clientSpecified);
00476 if (setByProvider || clientSpecified)
00477 {
00478 addHeader("Content-Language", clang);
00479 }
00480
00481 if (m_requestHandler && m_requestHandler->hasError(errCode, errDescr))
00482 {
00483 ostrToSend = &ostrError;
00484 }
00485 addHeader(m_respHeaderPrefix + "CIMOperation", "MethodResponse");
00486 TempFileStream* tfs = NULL;
00487 if ((tfs = dynamic_cast<TempFileStream*>(ostrToSend)))
00488 {
00489 clen = tfs->getSize();
00490 }
00491 if (m_deflateCompressionOut && tfs)
00492 {
00493 addHeader("Transfer-Encoding", "chunked");
00494 addHeader("Content-Encoding", "deflate");
00495 sendHeaders(m_resCode, -1);
00496 }
00497 else if (!m_requestHandler->getCIMError().empty())
00498 {
00499 addHeader(m_respHeaderPrefix + "CIMError",
00500 m_requestHandler->getCIMError());
00501 }
00502 else
00503 {
00504 sendHeaders(m_resCode, clen);
00505 }
00506 if (tfs)
00507 {
00508 if (clen > 0)
00509 {
00510 if (m_deflateCompressionOut)
00511 {
00512 #ifdef OW_HAVE_ZLIB_H
00513
00514 HTTPChunkedOStream costr(m_ostr);
00515 HTTPDeflateOStream deflateostr(costr);
00516 deflateostr << tfs->rdbuf();
00517 deflateostr.termOutput();
00518 costr.termOutput(HTTPChunkedOStream::E_SEND_LAST_CHUNK);
00519 #else
00520 OW_THROW(HTTPException, "Attempting to deflate response "
00521 " but we're not compiled with zlib! (shouldn't happen)");
00522 #endif // #ifdef OW_HAVE_ZLIB_H
00523 }
00524 else
00525 {
00526 m_ostr << tfs->rdbuf();
00527 if (!m_ostr)
00528 {
00529 OW_THROW_ERRNO_MSG(IOException, "Failed writing");
00530 }
00531 }
00532 }
00533 }
00534 m_ostr.flush();
00535 }
00536 else
00537 {
00538 HTTPChunkedOStream* ostrChunk = NULL;
00539 if (m_deflateCompressionOut)
00540 {
00541 #ifdef OW_HAVE_ZLIB_H
00542 OW_ASSERT(dynamic_cast<HTTPDeflateOStream*>(ostrEntity));
00543 HTTPDeflateOStream* deflateostr = static_cast<HTTPDeflateOStream*>(ostrEntity);
00544 deflateostr->termOutput();
00545 OW_ASSERT(dynamic_cast<HTTPChunkedOStream*>(&deflateostr->getOutputStreamOrig()));
00546 ostrChunk = static_cast<HTTPChunkedOStream*>(&deflateostr->getOutputStreamOrig());
00547 #else
00548 OW_THROW(HTTPException, "Attempting to deflate response "
00549 " but we're not compiled with zlib! (shouldn't happen)");
00550 #endif
00551 }
00552 else
00553 {
00554 OW_ASSERT(dynamic_cast<HTTPChunkedOStream*>(ostrEntity));
00555 ostrChunk = static_cast<HTTPChunkedOStream*>(ostrEntity);
00556 }
00557 OW_ASSERT(ostrChunk);
00558
00559
00560
00561
00562 bool clientSpecified, setByProvider;
00563 String clang = getContentLanguage(context, setByProvider,
00564 clientSpecified);
00565 if (setByProvider || clientSpecified)
00566 {
00567 OW_LOGDEBUG(Format("HTTPSvrConnection::sendPostResponse (chunk)"
00568 " setting Content-Language to %1", clang).c_str());
00569
00570 ostrChunk->addTrailer("Content-Language", clang);
00571 }
00572
00573 if (m_requestHandler && m_requestHandler->hasError(errCode, errDescr))
00574 {
00575 const char* CIMStatusCodeTrailer = "CIMStatusCode";
00576 if (m_clientIsOpenWBEM2)
00577 {
00578 CIMStatusCodeTrailer = "CIMErrorCode";
00579 }
00580 const char* CIMStatusDescriptionTrailer = "CIMStatusDescription";
00581 if (m_clientIsOpenWBEM2)
00582 {
00583 CIMStatusDescriptionTrailer = "CIMErrorDescription";
00584 }
00585
00586 ostrChunk->addTrailer(m_respHeaderPrefix + CIMStatusCodeTrailer,
00587 String(errCode));
00588 if (!errDescr.empty())
00589 {
00590 StringArray lines = errDescr.tokenize("\n");
00591 errDescr.erase();
00592 for (size_t i = 0; i < lines.size(); ++i)
00593 {
00594 errDescr += lines[i] + " ";
00595 }
00596 ostrChunk->addTrailer(m_respHeaderPrefix + CIMStatusDescriptionTrailer,
00597 errDescr);
00598 }
00599 if (!m_requestHandler->getCIMError().empty())
00600 {
00601 ostrChunk->addTrailer(m_respHeaderPrefix + "CIMError",
00602 m_requestHandler->getCIMError());
00603 }
00604 ostrChunk->termOutput(HTTPChunkedOStream::E_DISCARD_LAST_CHUNK);
00605 }
00606 else
00607 {
00608 ostrChunk->termOutput(HTTPChunkedOStream::E_SEND_LAST_CHUNK);
00609 }
00610 }
00611 }
00613 int
00614 HTTPSvrConnection::processRequestLine()
00615 {
00616 switch (m_requestLine.size())
00617 {
00618 case 2:
00619 m_httpVersion = HTTP_VER_10;
00620 break;
00621 case 3:
00622 if (m_requestLine[2].equalsIgnoreCase("HTTP/1.1"))
00623 {
00624 m_httpVersion = HTTP_VER_11;
00625 }
00626 else if (m_requestLine[2].equalsIgnoreCase("HTTP/1.0"))
00627 {
00628 m_httpVersion = HTTP_VER_10;
00629 }
00630 else
00631 {
00632 m_httpVersion = HTTP_VER_BAD;
00633 m_errDetails = "The HTTP protocol version " +
00634 m_requestLine[2] + " is not supported by this server.";
00635 return SC_HTTP_VERSION_NOT_SUPPORTED;
00636 }
00637 break;
00638 default:
00639 m_errDetails = "Invalid number of tokens on request line: " +
00640 String(static_cast<unsigned int>(m_requestLine.size()));
00641 return SC_BAD_REQUEST;
00642 }
00643
00644 if (m_requestLine[0].equals("M-POST"))
00645 {
00646 m_method = M_POST;
00647 }
00648 else if (m_requestLine[0].equals("POST"))
00649 {
00650 m_method = POST;
00651 }
00652 else if (m_requestLine[0].equals("TRACE"))
00653 {
00654 m_method = TRACE;
00655 }
00656 else if (m_requestLine[0].equals("OPTIONS"))
00657 {
00658 m_method = OPTIONS;
00659 }
00660 else
00661 {
00662 m_method = BAD;
00663 m_errDetails = "Method not allowed by server: " + m_requestLine[0];
00664 return SC_METHOD_NOT_ALLOWED;
00665 }
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675 return SC_OK;
00676 }
00678
00679
00680 int
00681 HTTPSvrConnection::processHeaders(OperationContext& context)
00682 {
00683
00684
00685
00686
00687 if (m_options.allowAnonymous == false)
00688 {
00689 if (!m_isAuthenticated)
00690 {
00691 m_isAuthenticated = false;
00692 try
00693 {
00694 if (performAuthentication(getHeaderValue("Authorization"), context) < 300 )
00695 {
00696 m_isAuthenticated = true;
00697 }
00698 }
00699 catch (AuthenticationException& e)
00700 {
00701 m_errDetails = e.getMessage();
00702 m_isAuthenticated = false;
00703 return SC_INTERNAL_SERVER_ERROR;
00704 }
00705 if (m_isAuthenticated == false)
00706 {
00707 return SC_UNAUTHORIZED;
00708 }
00709 }
00710 context.setStringData(OperationContext::USER_NAME, m_userName);
00711 }
00712
00713
00714
00715 if (m_httpVersion == HTTP_VER_11)
00716 {
00717 if ( ! headerHasKey("Host"))
00718 {
00719 m_errDetails = "Your browser sent a request that this server could"
00720 "not understand. "
00721 "Client sent HTTP/1.1 request without hostname "
00722 "(see RFC2068 section 9, and 14.23)";
00723 return SC_BAD_REQUEST;
00724 }
00725 }
00726
00727
00728
00729 if (m_httpVersion != HTTP_VER_11)
00730 {
00731 m_isClose = true;
00732
00733 }
00734 else
00735 {
00736 if (headerHasKey("Connection"))
00737 {
00738 if (getHeaderValue("Connection").equals("close"))
00739 {
00740 m_isClose = true;
00741 }
00742 }
00743 }
00744
00745
00746
00747 m_contentLength = -1;
00748 m_chunkedIn = false;
00749 if (headerHasKey("Transfer-Encoding"))
00750 {
00751
00752
00753
00754
00755 if (!getHeaderValue("Transfer-Encoding").equals("identity"))
00756 {
00757 m_contentLength = -1;
00758 m_chunkedIn = true;
00759 }
00760 }
00761 if (!m_chunkedIn)
00762 {
00763
00764 if (headerHasKey("Content-Length"))
00765 {
00766 String cLen = getHeaderValue("Content-Length");
00767 if (!cLen.empty())
00768 {
00769 m_contentLength = cLen.toInt64();
00770 if (m_contentLength < 0)
00771 {
00772 m_errDetails = "Bad (negative) Content-Length";
00773 return SC_BAD_REQUEST;
00774 }
00775 }
00776 }
00777
00778
00779 if (m_method == M_POST || m_method == POST)
00780 {
00781 if (m_contentLength < 0 && m_httpVersion == HTTP_VER_11)
00782 {
00783 m_errDetails = "No Content-Length or Transfer-Encoding"
00784 " was specified.";
00785 return SC_LENGTH_REQUIRED;
00786 }
00787 }
00788
00789 else if (m_method == TRACE)
00790 {
00791 if (m_contentLength > 0 || m_chunkedIn)
00792 {
00793 m_errDetails = "An entity cannot be supplied with the TRACE "
00794 "method.";
00795 return SC_BAD_REQUEST;
00796 }
00797 }
00798 }
00799
00800
00801
00802 m_deflateCompressionIn = false;
00803 if (headerHasKey("Content-Encoding"))
00804 {
00805 String cc = getHeaderValue("Content-Encoding");
00806 if (cc.equalsIgnoreCase("deflate"))
00807 {
00808 #ifdef OW_HAVE_ZLIB_H
00809 m_deflateCompressionIn = true;
00810 m_deflateCompressionOut = m_options.enableDeflate;
00811 #else
00812 m_errDetails = "Content-Encoding \"deflate\" is not supported. "
00813 "(CIMOM not compiled with zlib)";
00814 return SC_NOT_ACCEPTABLE;
00815 #endif // #ifdef OW_HAVE_ZLIB_H
00816 }
00817 else if (!cc.equals("identity"))
00818 {
00819 m_errDetails = "Invalid Content-Encoding: " + cc
00820 #ifdef OW_HAVE_ZLIB_H
00821 + " Only \"deflate\" is supported."
00822 #endif
00823 ;
00824 return SC_NOT_ACCEPTABLE;
00825 }
00826 }
00827
00828
00829
00830 if (m_method == POST || m_method == M_POST)
00831 {
00832 if (headerHasKey("Accept"))
00833 {
00834 String ac = getHeaderValue("Accept");
00835 if (ac.indexOf("text/xml") == String::npos
00836 && ac.indexOf("application/xml") == String::npos
00837 && ac.indexOf("*/*") == String::npos
00838 && ac.indexOf("text/*") == String::npos
00839 && ac.indexOf("application/*") == String::npos
00840 )
00841 {
00842 m_errDetails = "Only entities of type \"text/xml\" or "
00843 "\"application/xml\" are supported.";
00844 return SC_NOT_ACCEPTABLE;
00845 }
00846 }
00847 }
00848
00849
00850
00851 if (m_method == POST || m_method == M_POST)
00852 {
00853 if (headerHasKey("Accept-Charset"))
00854 {
00855 if (getHeaderValue("Accept-Charset").indexOf("utf-8") == String::npos)
00856 {
00857 m_errDetails = "Only the utf-8 charset is acceptable.";
00858 return SC_NOT_ACCEPTABLE;
00859 }
00860 }
00861 }
00862
00863
00864
00865 if (m_method == POST || m_method == M_POST)
00866 {
00867 if (headerHasKey("Accept-Encoding"))
00868 {
00869 if (getHeaderValue("Accept-Encoding").indexOf("deflate") != String::npos)
00870 {
00871 #ifdef OW_HAVE_ZLIB_H
00872 m_deflateCompressionOut = m_options.enableDeflate;
00873 #endif
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884 }
00885 }
00886
00887
00888
00889 if (getHeaderValue("TE").indexOf("trailers") != String::npos)
00890 {
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900 if (getHeaderValue("User-Agent") == "RPT-HTTPClient/0.3-2")
00901 {
00902 m_chunkedOut = false;
00903 }
00904 else
00905 {
00906 m_chunkedOut = true;
00907 }
00908
00909
00910
00911
00912 if (getHeaderValue("User-Agent").startsWith("openwbem/2"))
00913 {
00914 m_clientIsOpenWBEM2 = true;
00915 }
00916 }
00917
00918
00919
00920 if (headerHasKey("Accept-Language"))
00921 {
00922 String al = getHeaderValue("Accept-Language");
00923 if (al.length())
00924 {
00925 SessionLanguageRef psl(new SessionLanguage);
00926 psl->assign(al.c_str());
00927 context.setData(OperationContext::SESSION_LANGUAGE_KEY, psl);
00928 context.setStringData(OperationContext::HTTP_ACCEPT_LANGUAGE_KEY, al);
00929 }
00930 }
00931
00932
00933
00934
00935 if (
00936 headerHasKey("Accept-Ranges")
00937 || headerHasKey("Content-Range")
00938 || headerHasKey("If-Range")
00939 || headerHasKey("Range")
00940 || headerHasKey("Accept-Ranges")
00941 )
00942 {
00943 m_errDetails = "Illegal header in request. See: "
00944 "http://www.dmtf.org/cim/mapping/http/v1.0";
00945 return SC_NOT_ACCEPTABLE;
00946 }
00947
00948
00949
00950
00951
00952
00953
00954 if (m_method == M_POST || m_method == POST)
00955 {
00956 if (headerHasKey("Content-Type"))
00957 {
00958 String ct = getHeaderValue("Content-Type");
00959
00960 ct = ct.substring(0, ct.indexOf(';'));
00961
00962
00963 m_requestHandler = m_options.env->getRequestHandler(ct);
00964 if (!m_requestHandler)
00965 {
00966 m_errDetails = Format("Content-Type \"%1\" is not supported.", ct);
00967 return SC_UNSUPPORTED_MEDIA_TYPE;
00968 }
00969 }
00970 else
00971 {
00972 m_errDetails = "A Content-Type must be specified";
00973 return SC_NOT_ACCEPTABLE;
00974 }
00975 }
00976
00977
00978
00979 if (m_method == M_POST)
00980 {
00981 if (headerHasKey("Man"))
00982 {
00983 String manLine = getHeaderValue("Man");
00984 if (manLine.indexOf("http://www.dmtf.org/cim/mapping/http/v1.0") == String::npos)
00985 {
00986 m_errDetails = "Unknown extension URI";
00987 return SC_NOT_EXTENDED;
00988 }
00989 size_t idx = manLine.indexOf(';');
00990 if (idx > 0 && idx != String::npos)
00991 {
00992 manLine = manLine.substring(idx + 0);
00993 idx = manLine.indexOf("ns");
00994 if (idx != String::npos)
00995 {
00996 idx = manLine.indexOf('=');
00997 if (idx > 0 && idx != String::npos)
00998 {
00999 m_reqHeaderPrefix = manLine.substring(idx + 1).trim();
01000 }
01001 }
01002 }
01003 }
01004 else
01005 {
01006 m_errDetails = "Cannot use M-POST method with no Man: header. See: "
01007 "http://www.ietf.org/rfc/rfc2774.txt";
01008 return SC_NOT_EXTENDED;
01009 }
01010 }
01011
01012
01013
01014 if (headerHasKey(HTTPUtils::Header_BypassLocker))
01015 {
01016 if (getHeaderValue(HTTPUtils::Header_BypassLocker) == HTTPUtils::HeaderValue_true)
01017 {
01018 context.setStringData(OperationContext::BYPASS_LOCKERKEY, "true");
01019 }
01020 }
01021
01022
01023
01024
01025 return SC_OK;
01026 }
01028 void
01029 HTTPSvrConnection::trace()
01030 {
01031 addHeader("TransferEncoding", "chunked");
01032 sendHeaders(m_resCode);
01033 HTTPChunkedOStream ostr(m_ostr);
01034 for (size_t i = 0; i < m_requestLine.size(); i++)
01035 {
01036 ostr << m_requestLine[i] << " ";
01037 }
01038 ostr << "\r\n";
01039 Map<String, String>::iterator iter;
01040 for (iter = m_requestHeaders.begin(); iter != m_requestHeaders.end(); iter++)
01041 {
01042 ostr << iter->first << ": " << iter->second << "\r\n" ;
01043 }
01044 ostr.termOutput(HTTPChunkedOStream::E_SEND_LAST_CHUNK);
01045 }
01047 void
01048 HTTPSvrConnection::post(istream& istr, OperationContext& context)
01049 {
01050 ostream* ostrEntity = NULL;
01051 initRespStream(ostrEntity);
01052 OW_ASSERT(ostrEntity);
01053 TempFileStream ostrError(400);
01054
01055 m_requestHandler->setEnvironment(m_options.env);
01056 beginPostResponse();
01057
01058
01059 m_requestHandler->process(&istr, ostrEntity, &ostrError, context);
01060 sendPostResponse(ostrEntity, ostrError, context);
01061
01062 }
01064 void
01065 HTTPSvrConnection::options(OperationContext& context)
01066 {
01067 addHeader("Allow","POST, M-POST, OPTIONS, TRACE");
01068 #ifdef OW_HAVE_ZLIB_H
01069 if (m_options.enableDeflate)
01070 {
01071 addHeader("Accept-Encoding", "deflate");
01072 }
01073 #endif
01074 String hp = HTTPUtils::getCounterStr();
01075 CIMFeatures cf;
01076
01077 m_requestHandler = m_options.env->getRequestHandler("application/xml");
01078 if (!m_requestHandler)
01079 {
01080 OW_HTTP_THROW(HTTPException, "OPTIONS is only implemented for XML requests", SC_NOT_IMPLEMENTED);
01081 }
01082 m_requestHandler->setEnvironment(m_options.env);
01083
01084 m_requestHandler->options(cf, context);
01085
01086 addHeader("Opt", cf.extURL + " ; ns=" + hp);
01087 hp += "-";
01088 addHeader(hp + "CIMProtocolVersion", cf.protocolVersion);
01089 String headerKey;
01090 switch (cf.cimProduct)
01091 {
01092 case CIMFeatures::SERVER:
01093 if (cf.supportsBatch)
01094 {
01095 addHeader(hp + "CIMSupportsMultipleOperations", "");
01096 }
01097 headerKey = hp + "CIMSupportedFunctionalGroups";
01098 break;
01099 case CIMFeatures::LISTENER:
01100 if (cf.supportsBatch)
01101 {
01102 addHeader(hp + "CIMSupportsMultipleExports", "");
01103 }
01104 headerKey = hp + "CIMSupportedExportGroups";
01105 break;
01106 default:
01107 OW_ASSERT( "Attempting OPTIONS on a CIMProductIFC "
01108 "that is not a LISTENER or SERVER" == 0);
01109 }
01110 String headerVal;
01111 for (size_t i = 0; i < cf.supportedGroups.size(); i++)
01112 {
01113 headerVal += cf.supportedGroups[i];
01114 if (i < cf.supportedGroups.size() - 1)
01115 {
01116 headerVal += ", ";
01117 }
01118 }
01119 addHeader(headerKey, headerVal);
01120 if (!cf.cimom.empty())
01121 {
01122 addHeader(hp + "CIMOM", cf.cimom);
01123 }
01124 if (!cf.validation.empty())
01125 {
01126 addHeader(hp + "CIMValidation", cf.validation);
01127 }
01128 if (cf.supportedQueryLanguages.size() > 0)
01129 {
01130 headerVal.erase();
01131 for (size_t i = 0; i < cf.supportedQueryLanguages.size(); i++)
01132 {
01133 headerVal += cf.supportedQueryLanguages[i];
01134 if (i < cf.supportedQueryLanguages.size() - 1)
01135 {
01136 headerVal += ", ";
01137 }
01138 }
01139 addHeader(hp + "CIMSupportedQueryLanguages", headerVal);
01140 }
01141 sendHeaders(m_resCode);
01142 }
01144 void
01145 HTTPSvrConnection::sendError(int resCode)
01146 {
01147 if (!m_ostr)
01148 {
01149
01150 return;
01151 }
01152 if (m_socket.receiveTimeOutExpired())
01153 {
01154 resCode = SC_REQUEST_TIMEOUT;
01155 m_errDetails = "Timeout waiting for request.";
01156 }
01157 else if (m_shutdown)
01158 {
01159 resCode = SC_SERVICE_UNAVAILABLE;
01160 m_errDetails = "The server is shutting down. Please try "
01161 "again later.";
01162 }
01163 String resMessage = HTTPUtils::status2String(resCode) +
01164 ": " + m_errDetails;
01165 String reqProtocol;
01166 if (m_httpVersion == HTTP_VER_11)
01167 {
01168 reqProtocol = "HTTP/1.1";
01169 }
01170 else
01171 {
01172 reqProtocol = "HTTP/1.0";
01173 }
01174 m_ostr << reqProtocol << " " << resCode << " " << resMessage << "\r\n";
01175
01176 addHeader("Connection", "close");
01177 addHeader("Content-Length", "0");
01178
01179
01180
01181 for (size_t i = 0; i < m_responseHeaders.size(); i++)
01182 {
01183 m_ostr << m_responseHeaders[i] << "\r\n";
01184 }
01185 m_ostr << "\r\n";
01186 m_ostr.flush();
01187 }
01189 int
01190 HTTPSvrConnection::performAuthentication(const String& info, OperationContext& context)
01191 {
01192 if (m_pHTTPServer->authenticate(this, m_userName, info, context, m_socket))
01193 {
01194 return SC_OK;
01195 }
01196 else
01197 {
01198 return SC_UNAUTHORIZED;
01199 }
01200 }
01202 void
01203 HTTPSvrConnection::sendHeaders(int sc, int len)
01204 {
01205 if (len >= 0)
01206 {
01207 addHeader("Content-Length",
01208 String(len));
01209 }
01210 m_ostr << "HTTP/1.1 " << sc << " " << HTTPUtils::status2String(sc) <<
01211 "\r\n";
01212 for (size_t i = 0; i < m_responseHeaders.size(); i++)
01213 {
01214 m_ostr << m_responseHeaders[i] << "\r\n";
01215 }
01216 m_ostr << "\r\n";
01217 }
01219 String
01220 HTTPSvrConnection::getHostName()
01221 {
01222
01223 return SocketAddress::getAnyLocalHost().getName();
01224 }
01226 CIMProtocolIStreamIFCRef
01227 HTTPSvrConnection::convertToFiniteStream(istream& istr)
01228 {
01229 CIMProtocolIStreamIFCRef rval(0);
01230 if (m_chunkedIn)
01231 {
01232 rval = new HTTPChunkedIStream(istr);
01233 }
01234 else if (m_contentLength > 0)
01235 {
01236 rval = new HTTPLenLimitIStream(istr, UInt64(m_contentLength));
01237 }
01238 else
01239 {
01240 return rval;
01241 }
01242 if (m_deflateCompressionIn)
01243 {
01244
01245
01246
01247
01248 OW_THROW(HTTPException, "Attempting to deflate request, but "
01249 "we're not linked with zlib! (shouldn't happen)");
01250
01251 }
01252 return rval;
01253 }
01255 String
01256 HTTPSvrConnection::getContentLanguage(OperationContext& context,
01257 bool& setByProvider, bool& clientSpecified)
01258 {
01259 setByProvider = false;
01260 clientSpecified = false;
01261 String contentLang = m_options.defaultContentLanguage;
01262
01263 OperationContext::DataRef dataref = context.getData(
01264 OperationContext::SESSION_LANGUAGE_KEY);
01265 if (!dataref)
01266 {
01267 return contentLang;
01268 }
01269
01270 SessionLanguageRef slref = dataref.cast_to<SessionLanguage>();
01271 if (!slref)
01272 {
01273 return contentLang;
01274 }
01275
01276 if (slref->langCount() > 0)
01277 {
01278 clientSpecified = true;
01279 }
01280 String pcl = slref->getContentLanguage();
01281 if (pcl.length())
01282 {
01283 contentLang = pcl;
01284 setByProvider = true;
01285 }
01286
01287 return contentLang;
01288 }
01289
01291 void
01292 HTTPSvrConnection::doCooperativeCancel()
01293 {
01294 m_shutdown = true;
01295 m_socket.disconnect();
01296 }
01297
01298 }
01299