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