ulxr_http_protocol.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                ulxr_http_protocol.cpp  -  http prootocol
00003                              -------------------
00004     begin                : Mon May 3 2004
00005     copyright            : (C) 2002-2007 by Ewald Arnold
00006     email                : ulxmlrpcpp@ewald-arnold.de
00007 
00008     $Id: ulxr_http_protocol.cpp 1062 2007-08-19 09:07:58Z ewald-arnold $
00009 
00010  ***************************************************************************/
00011 
00012 /**************************************************************************
00013  *
00014  * This program is free software; you can redistribute it and/or modify
00015  * it under the terms of the GNU Lesser General Public License as
00016  * published by the Free Software Foundation; either version 2 of the License,
00017  * or (at your option) any later version.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00027  *
00028  ***************************************************************************/
00029 
00030 // #define ULXR_SHOW_TRACE
00031 // #define ULXR_DEBUG_OUTPUT
00032 // #define ULXR_SHOW_HTTP
00033 // #define ULXR_SHOW_READ
00034 // #define ULXR_SHOW_WRITE
00035 // #define ULXR_SHOW_XML
00036 
00037 
00038 #define ULXR_NEED_EXPORTS
00039 #include <ulxmlrpcpp/ulxmlrpcpp.h> // always first
00040 
00041 #include <cstdio>
00042 #include <ctime>
00043 #include <sys/stat.h>
00044 
00045 #include <cstring>
00046 
00047 #if defined(__BORLANDC__) || defined (_MSC_VER)
00048 #include <utility>
00049 #endif
00050 
00051 #include <ulxmlrpcpp/ulxr_http_protocol.h>
00052 #include <ulxmlrpcpp/ulxr_tcpip_connection.h>
00053 #include <ulxmlrpcpp/ulxr_except.h>
00054 #include <ulxmlrpcpp/ulxr_response.h>
00055 #include <ulxmlrpcpp/ulxr_call.h>
00056 
00057 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR
00058 #include <ulxmlrpcpp/ulxr_mutex.h>
00059 #endif
00060 
00061 
00062 namespace ulxr
00063 {
00064 
00065 struct HttpProtocol::PImpl
00066 {
00067    CppString    proxy_user;
00068    CppString    proxy_pass;
00069    CppString    useragent;
00070    CppString    header_firstline;
00071    CppString    header_buffer;
00072    CppString    hostname;
00073    unsigned     hostport;
00074 
00075    bool         useconnect;
00076    bool         connected;
00077 
00078    ConnectorWrapperBase  *connector;
00079 
00080    bool            bChunkedEncoding;
00081    int             chunk_size;
00082    bool            chunk_terminated;
00083    bool            chunk_in_header;
00084    Cpp8BitString   chunk_data;
00085    unsigned        chunked_block;
00086    unsigned        chunk_body_skip;
00087 
00088    bool                              bAcceptcookies;
00089    std::map<CppString, CppString>    cookies;
00090    CppString                         serverCookie;
00091    CppString                         clientCookie;
00092    std::vector<CppString>            userTempFields;
00093    header_property                   headerprops;
00094 };
00095 
00096 
00097 ULXR_API_IMPL0 HttpProtocol::HttpProtocol(const HttpProtocol &prot)
00098   : Protocol(prot)
00099   , pimpl(new PImpl)
00100 {
00101   *pimpl = *prot.pimpl;
00102 }
00103 
00104 
00105 ULXR_API_IMPL0
00106   HttpProtocol::HttpProtocol(Connection *conn, const CppString &hn, unsigned hp)
00107   : Protocol (conn)
00108   , pimpl(new PImpl)
00109 {
00110     pimpl->hostname = hn;
00111     pimpl->hostport = hp;
00112     ULXR_TRACE(ULXR_PCHAR("HttpProtocol(conn, name, port)"));
00113     init();
00114 }
00115 
00116 
00117 ULXR_API_IMPL0
00118   HttpProtocol::HttpProtocol(TcpIpConnection *conn)
00119   : Protocol (conn)
00120   , pimpl(new PImpl)
00121 {
00122     pimpl->hostname = conn->getPeerName();
00123     pimpl->hostport = conn->getPort();
00124     ULXR_TRACE(ULXR_PCHAR("HttpProtocol(conn)"));
00125     init();
00126 }
00127 
00128 
00129 ULXR_API_IMPL0 HttpProtocol::~HttpProtocol()
00130 {
00131     ULXR_TRACE(ULXR_PCHAR("~HttpProtocol"));
00132     delete pimpl->connector;
00133     delete pimpl;
00134     pimpl = 0;
00135 }
00136 
00137 
00138 ULXR_API_IMPL(Protocol *) HttpProtocol::detach()
00139 {
00140     ULXR_TRACE(ULXR_PCHAR("HttpProtocol::detach()"));
00141     HttpProtocol *clone = new HttpProtocol(*this);
00142     clone->setConnection(getConnection()->detach());
00143     clone->pimpl->connector = new ConnectorWrapper<HttpProtocol>(clone, &HttpProtocol::doConnect);
00144     return clone;  // return previous and running connection
00145 }
00146 
00147 
00148 ULXR_API_IMPL(void) HttpProtocol::init()
00149 {
00150     ULXR_TRACE(ULXR_PCHAR("init"));
00151     pimpl->connector = new ConnectorWrapper<HttpProtocol>(this, &HttpProtocol::doConnect);
00152     getConnection()->setConnector(pimpl->connector);
00153     pimpl->useconnect = false;
00154     pimpl->connected = false;
00155     ULXR_TRACE(ULXR_PCHAR("init"));
00156     pimpl->headerprops.clear();
00157     pimpl->useragent = ULXR_GET_STRING(ULXR_PACKAGE) + ULXR_PCHAR("/") + ULXR_GET_STRING(ULXR_VERSION);
00158     pimpl->userTempFields.clear();
00159     pimpl->bAcceptcookies = false;
00160     pimpl->bChunkedEncoding = false;
00161     pimpl->chunk_data.clear();
00162     pimpl->chunk_size = 0;
00163     pimpl->chunk_body_skip = 0;
00164     setChunkedTransfer(false);
00165 }
00166 
00167 
00168 ULXR_API_IMPL(void) HttpProtocol::clearHttpInfo()
00169 {
00170     ULXR_TRACE(ULXR_PCHAR("clearHttpInfo"));
00171     pimpl->header_firstline = ULXR_PCHAR("");
00172     pimpl->header_buffer = ULXR_PCHAR("");
00173     pimpl->headerprops.clear();
00174     pimpl->cookies.clear();
00175     pimpl->bChunkedEncoding = false;
00176     pimpl->chunk_data.clear();
00177     pimpl->chunk_size = 0;
00178     pimpl->chunk_body_skip = 0;
00179     pimpl->chunk_terminated = false;
00180     pimpl->chunk_in_header = true;
00181 }
00182 
00183 
00184 ULXR_API_IMPL(void) HttpProtocol::resetConnection()
00185 {
00186     ULXR_TRACE(ULXR_PCHAR("resetConnection"));
00187     Protocol::resetConnection();
00188     clearHttpInfo();
00189     //loadCookie(peername);
00190 }
00191 
00192 
00193 ULXR_API_IMPL(void) HttpProtocol::close()
00194 {
00195     ULXR_TRACE(ULXR_PCHAR("close"));
00196     Protocol::close();
00197     pimpl->connected = false;
00198 //    storeCookie(peername);
00199 }
00200 
00201 
00202 ULXR_API_IMPL(void) HttpProtocol::shutdown(int mode)
00203 {
00204     ULXR_TRACE(ULXR_PCHAR("shutdown"));
00205     if (getConnection() != 0)
00206       getConnection()->shutdown(mode);
00207 }
00208 
00209 
00210 ULXR_API_IMPL(CppString) HttpProtocol::getHttpProperty(const CppString &in_name) const
00211 {
00212     ULXR_TRACE(ULXR_PCHAR("getHttpProperty ") << in_name);
00213     CppString name = in_name;
00214     makeLower(name);
00215     header_property::const_iterator it;
00216 
00217     if ((it = pimpl->headerprops.find(name)) == pimpl->headerprops.end() )
00218         throw ConnectionException(NotConformingError,
00219                                   ulxr_i18n(ULXR_PCHAR("Http property field not available: "))+name, 400);
00220 
00221     return (*it).second;
00222 }
00223 
00224 
00225 ULXR_API_IMPL(bool) HttpProtocol::hasHttpProperty(const CppString &in_name) const
00226 {
00227     CppString name = in_name;
00228     makeLower(name);
00229     bool b = pimpl->headerprops.find(name) != pimpl->headerprops.end();
00230     ULXR_TRACE(ULXR_PCHAR("hasHttpProperty: ") << in_name << ULXR_PCHAR(" ") << b);
00231     return b;
00232 }
00233 
00234 
00235 ULXR_API_IMPL(void) HttpProtocol::parseHeaderLine()
00236 {
00237     ULXR_TRACE(ULXR_PCHAR("parseHeaderLine"));
00238 
00239     if (pimpl->header_firstline.length() == 0)
00240     {
00241         pimpl->header_firstline = pimpl->header_buffer;
00242         ULXR_DOUT_HTTP(ULXR_PCHAR("firstline: <") << pimpl->header_firstline << ULXR_PCHAR(">"));
00243     }
00244     else
00245     {
00246         CppString nm, cont;
00247         std::size_t pos = pimpl->header_buffer.find(':');
00248         if (pos == CppString::npos)
00249         {
00250             nm = pimpl->header_buffer;
00251             cont = ULXR_PCHAR("");
00252         }
00253         else
00254         {
00255             nm = pimpl->header_buffer.substr(0, pos);
00256             cont = pimpl->header_buffer.substr(pos+1);
00257         }
00258 
00259         makeLower(nm);
00260         cont = stripWS(cont);
00261         nm = stripWS(nm);
00262         pimpl->headerprops.insert(std::make_pair(nm, cont));
00263 
00264         if (pimpl->bAcceptcookies && (nm == ULXR_PCHAR("set-cookie")))  // distinguish between cookie / set-cookie?
00265           setCookie(cont);
00266 
00267         else if (pimpl->bAcceptcookies && (nm == ULXR_PCHAR("cookie")))
00268           setCookie(cont);
00269 
00270         ULXR_DOUT_HTTP(ULXR_PCHAR("headerprop: <") << nm
00271                        << ULXR_PCHAR("> + <") << cont << ULXR_PCHAR("> "));
00272     }
00273     pimpl->header_buffer = ULXR_PCHAR("");
00274 }
00275 
00276 
00277 bool HttpProtocol::hasClosingProperty()
00278 {
00279   bool do_close = false;
00280   if (hasHttpProperty(ULXR_PCHAR("connection")))
00281   {
00282       CppString sConnect = getHttpProperty(ULXR_PCHAR("connection"));
00283       makeLower(sConnect);
00284       if (sConnect == CppString(ULXR_PCHAR("close")))
00285           do_close = true;
00286   }
00287 
00288   if (hasHttpProperty(ULXR_PCHAR("proxy-connection")))
00289   {
00290       CppString sConnect = getHttpProperty(ULXR_PCHAR("proxy-connection"));
00291       makeLower(sConnect);
00292       if (sConnect == CppString(ULXR_PCHAR("close")))
00293           do_close = true;
00294   }
00295   return do_close;
00296 }
00297 
00298 
00299 ULXR_API_IMPL(bool) HttpProtocol::checkContinue()
00300 {
00301     ULXR_TRACE(ULXR_PCHAR("checkContinue"));
00302     CppString head_version;
00303     unsigned head_status = 500;
00304     CppString head_phrase;
00305     splitHeaderLine(head_version, head_status, head_phrase);
00306     if (head_status == 100)
00307     {
00308       ULXR_TRACE(ULXR_PCHAR("Ignoring header 100-Continue"));
00309       setConnectionState(ConnStart);
00310       return true;
00311     }
00312     else
00313       return false;
00314 }
00315 
00316 
00317 ULXR_API_IMPL(Protocol::State)
00318 HttpProtocol::connectionMachine(char * &buffer, long &len)
00319 {
00320     /*
00321       Each invokation of this state machine tries to parse one single
00322       http header line of the buffer. If the content of the buffer is too small
00323       (no linefeed found) the content is cached in an internal string
00324       and used the next time.
00325       buffer points to the beginning of the next line at return if
00326       a linefeed has been found. In the message body nothing is done.
00327     */
00328     ULXR_TRACE(ULXR_PCHAR("connectionMachine with ") << len << ULXR_PCHAR(" bytes"));
00329     if (len == 0 || buffer == 0)
00330         return getConnectionState();
00331 
00332     char *chunk_cursor = buffer;
00333     char *chunk_start = buffer;
00334 
00335     while (len > 0)
00336     {
00337         switch (getConnectionState())
00338         {
00339         case ConnStart:
00340             setConnectionState(ConnHeaderLine);
00341             clearHttpInfo();
00342         break;
00343 
00344         case ConnPendingCR:
00345             if (*buffer == '\n') // CR+LF
00346             {
00347                 --len;
00348                 ++buffer;
00349             }
00350 
00351             if (pimpl->header_buffer.length() == 0)
00352                 setConnectionState(ConnSwitchToBody);
00353             else
00354                 setConnectionState(ConnPendingHeaderLine);
00355         break;
00356 
00357         case ConnPendingHeaderLine:
00358             if (pimpl->header_buffer.length() == 0)
00359                 setConnectionState(ConnSwitchToBody);
00360 
00361             else if (*buffer != ' ')  // continuation line of current header field?
00362             {
00363                 parseHeaderLine();
00364                 setConnectionState(ConnHeaderLine);
00365             }
00366             else
00367               setConnectionState(ConnHeaderLine);
00368         break;
00369 
00370         case ConnHeaderLine:
00371 //            ULXR_TRACE(ULXR_PCHAR("ConnHeaderLine:"));
00372 
00373             if (*buffer == '\r')
00374                 setConnectionState(ConnPendingCR);
00375 
00376             else if (*buffer == '\n')
00377             {
00378                 if (pimpl->header_buffer.length() == 0)
00379                     setConnectionState(ConnSwitchToBody);
00380                 else
00381                     setConnectionState(ConnPendingHeaderLine);
00382             }
00383 
00384             else
00385                 pimpl->header_buffer += *buffer;
00386 
00387             ++buffer;
00388             --len;
00389         break;
00390 
00391         case ConnSwitchToBody:
00392           machine_switchToBody(buffer, len, chunk_start, chunk_cursor);
00393         break;
00394 
00395         case ConnChunkHeader:
00396         {
00397           ULXR_TRACE(ULXR_PCHAR("ConnChunkHeader:"));
00398 
00399           char c = *buffer;
00400           if (c != '\n' && c != '\r')
00401             pimpl->chunk_data += c;
00402 
00403           ++buffer;
00404           --len;
00405 
00406           if (c == '\n')
00407           {
00408             char* pStop;
00409             pimpl->chunk_size = std::strtol(pimpl->chunk_data.c_str(), &pStop, 16);
00410             ULXR_TRACE(ULXR_PCHAR("chunk with ")
00411                        << pimpl->chunk_size
00412                        << ULXR_PCHAR(" bytes announced"));
00413 
00414             if (   *pStop != ' '
00415                 && *pStop != 0
00416                 && *pStop != ';')
00417             {
00418                 setConnectionState(ConnError);
00419                 throw ConnectionException(SystemError, ulxr_i18n(ULXR_PCHAR("chunk size is followed by a bad character: ")) + *pStop, 500);
00420             }
00421 
00422             if (getContentLength() > 0)
00423               setRemainingContentLength(getRemainingContentLength() - pimpl->chunk_size);
00424             else if(getContentLength() == 0)
00425               setRemainingContentLength(pimpl->chunk_size);
00426 
00427             if (pimpl->chunk_size < 1)  // chunk size == 0 terminates data block
00428             {
00429               pimpl->chunk_in_header = false;
00430               setConnectionState(State(ConnHeaderLine));
00431             }
00432             else
00433               setConnectionState(State(ConnChunkBody));
00434           }
00435 
00436           if (len <= 0)
00437           {
00438             len = chunk_cursor - chunk_start;
00439             buffer = chunk_start;
00440             if (len != 0)
00441               return ConnBody;  // fake regular body
00442             else
00443               return State(ConnChunkHeader);
00444           }
00445         }
00446         break;
00447 
00448         case ConnChunkBodySkip:
00449           buffer++;
00450           len--;
00451           if (--pimpl->chunk_body_skip <= 0)
00452           {
00453             pimpl->chunk_data.clear();
00454             setConnectionState(State(ConnChunkHeader));
00455           }
00456         break;
00457 
00458         case ConnChunkBody:
00459           ULXR_TRACE(ULXR_PCHAR("ConnChunkBody:"));
00460           while (pimpl->chunk_size > 0 && len > 0)
00461           {
00462             *chunk_cursor++ = *buffer++;
00463             --pimpl->chunk_size;
00464             --len;
00465           }
00466 
00467           if (pimpl->chunk_size <= 0)
00468           {
00469             pimpl->chunk_body_skip = 2;
00470             setConnectionState(State(ConnChunkBodySkip));
00471           }
00472         break;
00473 
00474         case ConnChunkTerminated:
00475             ULXR_TRACE(ULXR_PCHAR("ConnChunkTerminated:"));
00476             return State(ConnChunkTerminated);
00477         /*break; */
00478 
00479         case ConnBody:
00480             ULXR_TRACE(ULXR_PCHAR("ConnBody:"));
00481             return ConnBody;
00482         /*break; */
00483 
00484         case ConnError:
00485             ULXR_TRACE(ULXR_PCHAR("ConnError:"));
00486             return ConnError;
00487         /*break; */
00488 
00489         default:
00490             setConnectionState(ConnError);
00491             throw ConnectionException(SystemError, ulxr_i18n(ULXR_PCHAR("connectionMachine(): unknown state")), 500);
00492         }
00493     }
00494 
00495     if (getConnectionState() == ConnSwitchToBody)
00496       machine_switchToBody(buffer, len, chunk_start, chunk_cursor);
00497 
00498     ULXR_TRACE(ULXR_PCHAR("/connectionMachine"));
00499 
00500     if (pimpl->bChunkedEncoding)
00501     {
00502       len = chunk_cursor - chunk_start;
00503       buffer = chunk_start;
00504       if (len != 0)
00505         return ConnBody;
00506     }
00507 
00508     return getConnectionState();
00509 }
00510 
00511 
00512 void HttpProtocol::machine_switchToBody(char * &buffer,
00513                                         long   &len,
00514                                         char * &chunk_start,
00515                                         char * &chunk_cursor)
00516 {
00517   ULXR_TRACE(ULXR_PCHAR("ConnSwitchToBody:"));
00518   if (pimpl->chunk_in_header)
00519   {
00520     if (!checkContinue())
00521     {
00522       if (hasHttpProperty(ULXR_PCHAR("transfer-encoding")))
00523       {
00524           CppString sEncoding = getHttpProperty(ULXR_PCHAR("transfer-encoding"));
00525           if (sEncoding == ULXR_PCHAR("chunked"))
00526           {
00527               setRemainingContentLength(-1);
00528               setContentLength(-1);
00529               ULXR_TRACE(ULXR_PCHAR("have chunked transfer encoding"));
00530               pimpl->bChunkedEncoding = true;
00531               pimpl->chunk_size = 0;
00532               pimpl->chunk_data.clear();
00533           }
00534       }
00535 
00536       if (!pimpl->bChunkedEncoding)
00537       {
00538         if (hasHttpProperty(ULXR_PCHAR("content-length")))
00539         {
00540             determineContentLength();
00541 
00542             ULXR_TRACE(ULXR_PCHAR("content_length: ") << getContentLength());
00543             ULXR_TRACE(ULXR_PCHAR("len: ") << len);
00544 
00545             if (getContentLength() >= 0)
00546                 setRemainingContentLength(getContentLength() - len);
00547         }
00548         setConnectionState(ConnBody);
00549       }
00550       else
00551         setConnectionState(State(ConnChunkHeader));
00552     }
00553   }
00554   else
00555   {
00556     len = chunk_cursor - chunk_start;
00557     buffer = chunk_start;
00558     setConnectionState(State(ConnChunkTerminated));
00559     pimpl->chunk_terminated = true;
00560   }
00561 
00562   if (hasClosingProperty())
00563     setPersistent(false);
00564   else
00565     setPersistent(true);
00566 }
00567 
00568 
00569 ULXR_API_IMPL(bool) HttpProtocol::hasBytesToRead() const
00570 {
00571   bool b = false;
00572   if (pimpl->bChunkedEncoding)
00573     b = !pimpl->chunk_terminated;
00574   else
00575     b = getRemainingContentLength() != 0;
00576 
00577   ULXR_TRACE(ULXR_PCHAR("hasBytesToRead: " << b));
00578   return b;
00579 }
00580 
00581 
00582 ULXR_API_IMPL(void) HttpProtocol::determineContentLength()
00583 {
00584     ULXR_TRACE(ULXR_PCHAR("determineContentLength"));
00585 
00586     header_property::iterator it;
00587     if ((it = pimpl->headerprops.find(ULXR_PCHAR("content-length"))) != pimpl->headerprops.end() )
00588     {
00589         ULXR_TRACE(ULXR_PCHAR(" content-length: ") << (*it).second);
00590         setContentLength(ulxr_atoi(getLatin1((*it).second).c_str()));
00591         ULXR_TRACE(ULXR_PCHAR(" length: ") << getContentLength());
00592     }
00593     else
00594     {
00595       if (pimpl->bChunkedEncoding)
00596         setContentLength(0); // set with next chunk header
00597       else
00598         throw ConnectionException(NotConformingError,
00599                                   ulxr_i18n(ULXR_PCHAR("Content-Length of message not available")), 411);
00600 
00601     }
00602 
00603     setRemainingContentLength(getContentLength());
00604     ULXR_TRACE(ULXR_PCHAR(" content_length: ") << getContentLength());
00605 }
00606 
00607 
00608 ULXR_API_IMPL(void)
00609 HttpProtocol::sendResponseHeader(int code,
00610                                  const CppString &phrase,
00611                                  const CppString &type,
00612                                  unsigned long len,
00613                                  bool wbxml_mode)
00614 {
00615     // doConnect(); must already be pimpl->connected
00616 
00617     ULXR_TRACE(ULXR_PCHAR("sendResponseHeader"));
00618     char stat[40];
00619     ulxr_sprintf(stat, "%d", code );
00620 
00621     char contlen[40];
00622     ulxr_sprintf(contlen, "%ld", len );
00623 
00624     CppString ps = phrase;
00625 
00626     std::size_t pos = 0;
00627     while ((pos = ps.find('\n', pos)) != CppString::npos)
00628     {
00629         ps.replace(pos, 1, ULXR_PCHAR(" "));
00630         pos += 1;
00631     }
00632 
00633     pos = 0;
00634     while ((pos = ps.find(ULXR_CHAR('\r'), pos)) != CppString::npos)
00635     {
00636         ps.replace(pos, 1, ULXR_PCHAR(" "));
00637         pos += 1;
00638     }
00639 
00640     CppString http_str = (CppString) ULXR_PCHAR("HTTP/1.1 ")
00641                          + ULXR_GET_STRING(stat) + ULXR_PCHAR(" ") + ps
00642                          + ULXR_PCHAR("\r\n");
00643 
00644     if (!isPersistent())
00645         http_str += ULXR_PCHAR("Connection: Close\r\n");
00646     else
00647         http_str += ULXR_PCHAR("Proxy-Connection: Keep-Alive\r\n");
00648 
00649     if (len != 0 && type.length() != 0)
00650         http_str  += ULXR_PCHAR("Content-Type: ") + type + ULXR_PCHAR("\r\n");
00651 
00652     for (unsigned i = 0; i < pimpl->userTempFields.size(); ++i)
00653         http_str += pimpl->userTempFields[i] + ULXR_CHAR("\r\n");
00654     pimpl->userTempFields.clear();
00655 
00656     if (hasServerCookie())
00657       http_str += ULXR_PCHAR("Set-Cookie: ") + getServerCookie() + ULXR_PCHAR("\r\n");
00658 
00659     if (isChunkedTransfer())
00660     {
00661       http_str += ULXR_PCHAR("Transfer-Encoding: chunked\r\n");
00662 #ifdef ULXR_DEBUG_OUTPUT
00663       http_str += ULXR_PCHAR("X-Content-Length: ") + ULXR_GET_STRING(contlen) + ULXR_PCHAR("\r\n");
00664 #endif
00665     }
00666     else
00667       http_str += ULXR_PCHAR("Content-Length: ") + ULXR_GET_STRING(contlen) + ULXR_PCHAR("\r\n");
00668 
00669     if (!wbxml_mode)
00670     {
00671         http_str += ULXR_PCHAR("X-Powered-By: ") + getUserAgent() + ULXR_PCHAR("\r\n")
00672                     + ULXR_PCHAR("Server: ") + pimpl->hostname + ULXR_PCHAR("\r\n")
00673                     + ULXR_PCHAR("Date: ") + getDateStr() + ULXR_PCHAR("\r\n");
00674     }
00675 
00676     http_str += ULXR_PCHAR("\r\n");    // empty line at end of header
00677 
00678     ULXR_DOUT_HTTP(ULXR_PCHAR("resp: \n") << http_str.c_str());
00679 
00680 #ifdef ULXR_UNICODE
00681     Cpp8BitString utf = unicodeToUtf8(http_str);
00682     writeRaw(utf.data(), utf.length());
00683 #else
00684     writeRaw(http_str.data(), http_str.length());
00685 #endif
00686 }
00687 
00688 
00689 ULXR_API_IMPL(void) HttpProtocol::enableConnect(bool enable)
00690 {
00691   ULXR_TRACE(ULXR_PCHAR("enableConnect ") << enable);
00692   pimpl->useconnect = enable;
00693 }
00694 
00695 
00696 ULXR_API_IMPL(bool) HttpProtocol::isConnectEnabled() const
00697 {
00698   ULXR_TRACE(ULXR_PCHAR("isConnectEnabled ") << pimpl->useconnect);
00699   return pimpl->useconnect;
00700 }
00701 
00702 
00703 ULXR_API_IMPL(bool) HttpProtocol::isConnected() const
00704 {
00705   ULXR_TRACE(ULXR_PCHAR("ispimpl->connected ") << pimpl->connected);
00706   return pimpl->connected;
00707 }
00708 
00709 
00710 ULXR_API_IMPL(void) HttpProtocol::awaitConnect()
00711 {
00712     ULXR_TRACE(ULXR_PCHAR("awaitConnect"));
00713 
00714     char buffer[ULXR_RECV_BUFFER_SIZE];
00715     char *buff_ptr;
00716     bool done = false;
00717     long readed;
00718     while (!done && hasBytesToRead()
00719                 && ((readed = readRaw(buffer, sizeof(buffer))) > 0) )
00720     {
00721       buff_ptr = buffer;
00722       ULXR_TRACE(ULXR_PCHAR("loop"));
00723 
00724       if (readed > 0)
00725       {
00726         State state = connectionMachine(buff_ptr, readed);
00727         if (state == ConnError)
00728         {
00729           ULXR_TRACE(ULXR_PCHAR("ConnError"));
00730           done = true;
00731           throw ConnectionException(TransportError, ulxr_i18n(ULXR_PCHAR("network problem occured")), 400);
00732         }
00733 
00734         else if (state == ConnSwitchToBody)
00735         {
00736           ULXR_TRACE(ULXR_PCHAR("ConnSwitchToBody"));
00737           done = true;
00738         }
00739 
00740         else if (state == ConnBody)
00741         {
00742           ULXR_TRACE(ULXR_PCHAR("ConnBody"));
00743           done = true;
00744         }
00745       }
00746     }
00747 
00748     CppString head_version;
00749     unsigned head_status = 500;
00750     CppString head_phrase = ULXR_PCHAR("Internal error");
00751     splitHeaderLine(head_version, head_status, head_phrase);
00752 
00753     if (head_status != 200)
00754       throw ConnectionException(TransportError, head_phrase, head_status);
00755 
00756     pimpl->connected = true;
00757     ULXR_TRACE(ULXR_PCHAR("awaitConnect: pimpl->connected"));
00758 }
00759 
00760 
00761 ULXR_API_IMPL(void) HttpProtocol::tryConnect()
00762 {
00763     ULXR_TRACE(ULXR_PCHAR("performConnect"));
00764 
00765     char ports[40];
00766     ulxr_sprintf(ports, ":%d", pimpl->hostport);
00767     CppString resource = pimpl->hostname + ULXR_GET_STRING(ports);
00768     CppString http_str = ULXR_PCHAR("CONNECT ") + resource + ULXR_PCHAR(" HTTP/1.1\r\n");
00769 
00770     http_str += ULXR_PCHAR("User-Agent: ") + getUserAgent() + ULXR_PCHAR("\r\n");
00771     http_str += ULXR_PCHAR("Proxy-Connection: Keep-Alive\r\n");
00772     http_str += ULXR_PCHAR("Host: ") + pimpl->hostname + ULXR_PCHAR("\r\n");
00773 
00774     if (pimpl->proxy_user.length() + pimpl->proxy_pass.length() != 0)
00775        http_str += ULXR_PCHAR("Proxy-Authorization: Basic ")
00776                    + encodeBase64(pimpl->proxy_user + ULXR_PCHAR(":") + pimpl->proxy_pass);
00777 
00778     http_str += ULXR_PCHAR("\r\n");    // empty line at end of header
00779 
00780     ULXR_DOUT_HTTP(ULXR_PCHAR("connect: \n") << http_str.c_str());
00781 
00782 #ifdef ULXR_UNICODE
00783     Cpp8BitString utf = unicodeToUtf8(http_str);
00784     writeRaw(utf.data(), utf.length());
00785 #else
00786     writeRaw(http_str.data(), http_str.length());
00787 #endif
00788 }
00789 
00790 
00791 ULXR_API_IMPL(void) HttpProtocol::doConnect()
00792 {
00793     if (isConnectEnabled() && !isConnected())
00794     {
00795       resetConnection();
00796       tryConnect();
00797       awaitConnect();
00798       resetConnection();
00799     }
00800 }
00801 
00802 
00803 ULXR_API_IMPL(void)
00804 HttpProtocol::sendRequestHeader(const CppString &method,
00805                                 const CppString &in_resource,
00806                                 const CppString &type,
00807                                 unsigned long len,
00808                                 bool wbxml_mode)
00809 {
00810     doConnect();
00811     pimpl->bChunkedEncoding = false;
00812     ULXR_TRACE(ULXR_PCHAR("sendRequestHeader"));
00813     char contlen[40];
00814     ulxr_sprintf(contlen, "%ld", len );
00815 
00816     char ports[40];
00817     ulxr_sprintf(ports, "%d", pimpl->hostport);
00818     CppString resource = ULXR_PCHAR("http://") + pimpl->hostname + ULXR_PCHAR(":") + ULXR_GET_STRING(ports) + in_resource;
00819     CppString http_str = method + ULXR_PCHAR(" ") + resource + ULXR_PCHAR(" HTTP/1.1\r\n");
00820     http_str += ULXR_PCHAR("Host: ") + pimpl->hostname + ULXR_PCHAR("\r\n");
00821 
00822     if(!wbxml_mode)
00823         http_str += ULXR_PCHAR("User-Agent: ") + getUserAgent() + ULXR_PCHAR("\r\n");
00824 
00825     if (pimpl->proxy_user.length() + pimpl->proxy_pass.length() != 0)
00826        http_str += ULXR_PCHAR("Proxy-Authorization: Basic ")
00827                    + encodeBase64(pimpl->proxy_user + ULXR_PCHAR(":") + pimpl->proxy_pass);
00828 
00829     if (!isPersistent())
00830         http_str += ULXR_PCHAR("Connection: Close\r\n");
00831     else
00832         http_str += ULXR_PCHAR("Proxy-Connection: Keep-Alive\r\n");
00833 
00834     if (len != 0 && type.length() != 0)
00835         http_str += ULXR_PCHAR("Content-Type: ") + type + ULXR_PCHAR("\r\n");
00836 
00837     for (unsigned i = 0; i < pimpl->userTempFields.size(); ++i)
00838         http_str += pimpl->userTempFields[i] + ULXR_CHAR("\r\n");
00839     pimpl->userTempFields.clear();
00840 
00841     if(!wbxml_mode)
00842       http_str += ULXR_PCHAR("Date: ") + getDateStr() + ULXR_PCHAR("\r\n");
00843 
00844     if (isChunkedTransfer())
00845     {
00846       http_str += ULXR_PCHAR("Transfer-Encoding: chunked\r\n");
00847 #ifdef ULXR_DEBUG_OUTPUT
00848       http_str += ULXR_PCHAR("X-Content-Length: ") + ULXR_GET_STRING(contlen) + ULXR_PCHAR("\r\n");
00849 #endif
00850     }
00851     else
00852       http_str += ULXR_PCHAR("Content-Length: ") + ULXR_GET_STRING(contlen) + ULXR_PCHAR("\r\n");
00853 
00854     if (hasClientCookie())
00855       http_str += ULXR_PCHAR("Cookie: ") + getClientCookie() + ULXR_PCHAR("\r\n");
00856 
00857     http_str += ULXR_PCHAR("\r\n");    // empty line at end of header
00858 
00859     ULXR_DOUT_HTTP(ULXR_PCHAR("req: \n") << http_str.c_str());
00860 
00861 #ifdef ULXR_UNICODE
00862     Cpp8BitString utf = unicodeToUtf8(http_str);
00863     writeRaw(utf.data(), utf.length());
00864 #else
00865     writeRaw(http_str.data(), http_str.length());
00866 #endif
00867 };
00868 
00869 
00870 ULXR_API_IMPL(CppString) HttpProtocol::getDateStr()
00871 {
00872     ULXR_TRACE(ULXR_PCHAR("getDateStr"));
00873     time_t tm;
00874     time(&tm);
00875 
00876 #ifndef HAVE_CTIME_R
00877 
00878 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR   // todo: optionally replace with ctime_r
00879     Mutex::Locker lock(ctimeMutex);
00880 #endif
00881 
00882     char * ct = ulxr_ctime(&tm);
00883     CppString s = ULXR_GET_STRING(ct);  // "\n" already included!
00884 
00885 #else
00886 
00887     char buff[40];
00888     char * ct = ::ctime_r(&tm, buff);
00889     CppString s = ULXR_GET_STRING(ct);  // "\n" already included!
00890 
00891 #endif
00892 
00893     s.erase(s.length()-1);              // remove it
00894     return s;
00895 }
00896 
00897 
00898 ULXR_API_IMPL(void)
00899 HttpProtocol::sendNegativeResponse(int status,
00900                                    const CppString &phrase,
00901                                    const CppString &info)
00902 {
00903     ULXR_TRACE(ULXR_PCHAR("sendNegativeResponse"));
00904 
00905     // doConnect(); must already be pimpl->connected
00906 
00907     char stat[40];
00908     ulxr_sprintf(stat, "%d", status );
00909 
00910     CppString msg = ulxr_i18n(ULXR_PCHAR("<html>")
00911                          ULXR_PCHAR("<head><title>Error occured</title></head>")
00912                          ULXR_PCHAR("<body>")
00913                          ULXR_PCHAR("<b>Sorry, error occured: ")) + ULXR_GET_STRING(stat)
00914                     + ULXR_PCHAR(", ") + phrase;
00915 
00916     if (info.length() != 0)
00917         msg += ULXR_PCHAR("<br />") + info;
00918 
00919     msg += ulxr_i18n(ULXR_PCHAR("</b>")
00920                 ULXR_PCHAR("<hr /><p>")
00921                 ULXR_PCHAR("This cute little server is powered by")
00922                 ULXR_PCHAR(" <a href=\"http://ulxmlrpcpp.sourceforge.net\">"));
00923 
00924     msg += ULXR_GET_STRING(ULXR_PACKAGE)
00925            + ULXR_PCHAR("/v") + ULXR_GET_STRING(ULXR_VERSION)
00926            + ULXR_PCHAR("</a>")
00927            + ULXR_PCHAR("</p>")
00928            ULXR_PCHAR("</body>")
00929            ULXR_PCHAR("</html>");
00930 
00931     ULXR_DOUT_RESP(ULXR_PCHAR("msg:\n") << msg);
00932 
00933 #ifdef ULXR_UNICODE
00934     Cpp8BitString utf = unicodeToUtf8(msg);
00935     sendResponseHeader(status, phrase, ULXR_PCHAR("text/html"), utf.length());
00936     writeRaw(utf.data(), utf.length());
00937 #else
00938     sendResponseHeader(status, phrase, ULXR_PCHAR("text/html"), msg.length());
00939     writeRaw(msg.data(), msg.length());
00940 #endif
00941 }
00942 
00943 
00944 ULXR_API_IMPL(void) HttpProtocol::sendRpcResponse(const MethodResponse &resp, bool wbxml_mode)
00945 {
00946     ULXR_TRACE(ULXR_PCHAR("sendRpcResponse"));
00947 
00948     // doConnect(); must already be pimpl->connected
00949 
00950     if (wbxml_mode)
00951     {
00952         std::string xml = resp.getWbXml();
00953         ULXR_DOUT_XML(binaryDebugOutput(xml));
00954         sendResponseHeader(200, ULXR_PCHAR("OK"), ULXR_PCHAR("application/x-wbxml-ulxr"), xml.length(), wbxml_mode);
00955         writeBody(xml.data(), xml.length());
00956     }
00957     else
00958     {
00959         CppString xml = resp.getXml(0)+ULXR_PCHAR("\n");
00960         ULXR_DOUT_XML(xml);
00961 
00962 #ifdef ULXR_UNICODE
00963         Cpp8BitString utf = unicodeToUtf8(xml);
00964         sendResponseHeader(200, ULXR_PCHAR("OK"), ULXR_PCHAR("text/xml"), utf.length(), wbxml_mode);
00965         writeBody(utf.data(), utf.length());
00966 #else
00967         sendResponseHeader(200, ULXR_PCHAR("OK"), ULXR_PCHAR("text/xml"), xml.length(), wbxml_mode);
00968         writeBody(xml.data(), xml.length());
00969 #endif
00970 
00971     }
00972 }
00973 
00974 ULXR_API_IMPL(void) HttpProtocol::writeChunk(const char *data, unsigned long len)
00975 {
00976   if (!isChunkedTransfer())
00977     throw ConnectionException(NotConformingError,
00978                               ulxr_i18n(ULXR_PCHAR("Protocol is not prepared for chunked encoding: ")), 400);
00979 
00980   if (len != 0)
00981   {
00982     char stat[40];
00983     ulxr_sprintf(stat, "%lx", len);
00984     ULXR_TRACE(ULXR_PCHAR("HttpProtocol::writeChunk() chunk with 0x")
00985                << ULXR_GET_STRING(stat)
00986                << ULXR_PCHAR(" bytes"));
00987     writeRaw(stat, strlen(stat));
00988     writeRaw("\r\n", 2);
00989     writeRaw(data, len);
00990     writeRaw("\r\n", 2);
00991   }
00992   else
00993   {
00994     ULXR_TRACE(ULXR_PCHAR("HttpProtocol::writeChunk() last chunk with 0 bytes"));
00995     writeRaw("0\r\n\r\n", 5);  // terminator
00996   }
00997 }
00998 
00999 
01000 ULXR_API_IMPL(void) HttpProtocol::writeBody(const char *data, unsigned long len)
01001 {
01002   if (!isChunkedTransfer())
01003     writeRaw(data, len);
01004   else
01005   {
01006     writeChunk(data, len);
01007     writeChunk(data, 0);
01008   }
01009 }
01010 
01011 
01012 ULXR_API_IMPL(void) HttpProtocol::sendRpcCall(const MethodCall &call,
01013                                            const CppString &resource,
01014                                            bool wbxml_mode)
01015 {
01016     ULXR_TRACE(ULXR_PCHAR("sendRpcCall"));
01017     doConnect();
01018 
01019     if (wbxml_mode)
01020     {
01021         std::string xml = call.getWbXml();
01022         ULXR_DOUT_XML(binaryDebugOutput(xml));
01023         sendRequestHeader(ULXR_PCHAR("POST"), resource, ULXR_PCHAR("application/x-wbxml-ulxr"), xml.length(), wbxml_mode);
01024         writeBody(xml.data(), xml.length());
01025     }
01026     else
01027     {
01028         CppString xml = call.getXml(0)+ULXR_PCHAR("\n");
01029         ULXR_DOUT_XML(xml);
01030 
01031 #ifdef ULXR_UNICODE
01032         Cpp8BitString utf = unicodeToUtf8(xml);
01033         sendRequestHeader(ULXR_PCHAR("POST"), resource, ULXR_PCHAR("text/xml"), utf.length(), wbxml_mode);
01034         writeBody(utf.data(), utf.length());
01035 #else
01036         sendRequestHeader(ULXR_PCHAR("POST"), resource, ULXR_PCHAR("text/xml"), xml.length(), wbxml_mode);
01037         writeBody(xml.data(), xml.length());
01038 #endif
01039 
01040     }
01041 };
01042 
01043 
01044 ULXR_API_IMPL(bool) HttpProtocol::responseStatus(CppString &phrase) const
01045 {
01046     ULXR_TRACE(ULXR_PCHAR("responseStatus"));
01047 
01048     CppString s = stripWS(getFirstHeaderLine());
01049     if (s.length() == 0)
01050     {
01051         s = ulxr_i18n(ULXR_PCHAR("No connection status available"));
01052         return false;
01053     }
01054 
01055     std::size_t pos = s.find(' ');
01056     if (pos != CppString::npos)  // skip version
01057         s.erase(0, pos+1);
01058     else
01059         s = ULXR_PCHAR("");
01060 
01061     CppString stat;
01062     s = stripWS(s);
01063     pos = s.find(ULXR_CHAR(' '));
01064     if (pos != CppString::npos)
01065     {
01066         stat = s.substr(0, pos);
01067         s.erase(0, pos+1);
01068     }
01069     else
01070     {
01071         stat = s;
01072         s = ULXR_PCHAR("");
01073     }
01074 
01075     phrase = stripWS(s);
01076 
01077     return stat == ULXR_PCHAR("200");
01078 }
01079 
01080 
01081 ULXR_API_IMPL(bool) HttpProtocol::determineClosing(const CppString &http_ver)
01082 {
01083     ULXR_TRACE(ULXR_PCHAR("determineClosing"));
01084     if (   http_ver == ULXR_PCHAR("0.9")
01085             || http_ver == ULXR_PCHAR("1.0"))
01086     {
01087         if (hasHttpProperty(ULXR_PCHAR("connection")))
01088         {
01089             CppString s = getHttpProperty(ULXR_PCHAR("connection"));
01090             makeLower(s);
01091             return !(s == ULXR_PCHAR("keep-alive"));
01092         }
01093         ULXR_TRACE(ULXR_PCHAR("determineClosing: true"));
01094         return true;  // close by default
01095     }
01096     else  // 1.1 and later
01097     {
01098         return hasClosingProperty();
01099 /*
01100         ULXR_TRACE(ULXR_PCHAR("determineClosing: false"));
01101         return false;  // keep open by default
01102 */
01103     }
01104     /*return true; avoids warning */
01105 }
01106 
01107 
01108 ULXR_API_IMPL(bool) HttpProtocol::getUserPass(CppString &user,
01109         CppString &pass) const
01110 {
01111     ULXR_TRACE(ULXR_PCHAR("getUserPass"));
01112     user = ULXR_PCHAR("");
01113     pass = ULXR_PCHAR("");
01114 
01115     if (hasHttpProperty(ULXR_PCHAR("authorization")) )
01116     {
01117         CppString auth = getHttpProperty(ULXR_PCHAR("authorization"));
01118 
01119         ULXR_TRACE(ULXR_PCHAR("getUserPass: ") + auth);
01120         ULXR_TRACE(ULXR_PCHAR("getUserPass: basic?"));
01121 
01122         // only know basic auth
01123         CppString auth_id = auth.substr(0, 6);
01124         makeLower(auth_id);
01125         if (auth_id != ULXR_PCHAR("basic "))
01126             return false;
01127 
01128         auth.erase(0, 6);
01129         auth = decodeBase64(auth);
01130         ULXR_TRACE(ULXR_PCHAR("getUserPass: ':'? ")  + auth);
01131         std::size_t pos = auth.find(':');
01132         if (pos != CppString::npos)
01133         {
01134             user = stripWS(auth.substr(0, pos));
01135             pass = stripWS(auth.substr(pos+1));
01136             ULXR_TRACE(ULXR_PCHAR("getUserPass: user=") +user + ULXR_PCHAR(", pass=")+pass);
01137             return true;
01138         }
01139     }
01140 
01141     return false;
01142 }
01143 
01144 
01145 ULXR_API_IMPL(void) HttpProtocol::rejectAuthentication(const CppString &realm)
01146 {
01147     ULXR_TRACE(ULXR_PCHAR("rejectAuthentication: ") + realm);
01148     addOneTimeHttpField(ULXR_PCHAR("WWW-Authenticate"),
01149                         ULXR_PCHAR("Basic realm=\"") + realm +ULXR_PCHAR("\""));
01150     sendNegativeResponse(401, ULXR_PCHAR("Authentication required for realm \"")+ realm + ULXR_PCHAR("\""));
01151 }
01152 
01153 
01154 ULXR_API_IMPL(void) HttpProtocol::addOneTimeHttpField(const CppString &name, const CppString &value)
01155 {
01156     ULXR_TRACE(ULXR_PCHAR("addOneTimeHttpField: ") + name + ULXR_PCHAR(": ") + value);
01157     pimpl->userTempFields.push_back(stripWS(name) + ULXR_PCHAR(": ") + stripWS(value));
01158 }
01159 
01160 
01161 ULXR_API_IMPL(void) HttpProtocol::setMessageAuthentication(const CppString &user,
01162                                                         const CppString &pass)
01163 {
01164     ULXR_TRACE(ULXR_PCHAR("setMessageAuthentication"));
01165     CppString s = ULXR_PCHAR("Basic ");
01166     s += encodeBase64(user + ULXR_PCHAR(":") + pass);
01167     addOneTimeHttpField(ULXR_PCHAR("Authorization"), s);
01168 }
01169 
01170 
01171 ULXR_API_IMPL(void) HttpProtocol::setProxyAuthentication(const CppString &user,
01172                                                       const CppString &pass)
01173 {
01174     ULXR_TRACE(ULXR_PCHAR("setProxyAuthentication"));
01175     pimpl->proxy_user = user;
01176     pimpl->proxy_pass = pass;
01177 }
01178 
01179 
01180 ULXR_API_IMPL(void) HttpProtocol::setTransmitOnly()
01181 {
01182     ULXR_TRACE(ULXR_PCHAR("setTransmitOnly"));
01183     addOneTimeHttpField(ULXR_PCHAR("X-TransmitOnly"), ULXR_PCHAR("true"));
01184 }
01185 
01186 
01187 ULXR_API_IMPL(bool) HttpProtocol::isTransmitOnly()
01188 {
01189     ULXR_TRACE(ULXR_PCHAR("isTransmitOnly"));
01190     return hasHttpProperty(ULXR_PCHAR("X-TransmitOnly"))
01191            && (getHttpProperty(ULXR_PCHAR("X-TransmitOnly")) == ULXR_PCHAR("true"));
01192 }
01193 
01194 
01195 ULXR_API_IMPL(CppString) HttpProtocol::getProtocolName()
01196 {
01197     return ULXR_PCHAR("http");
01198 }
01199 
01200 
01201 bool HttpProtocol::hasCookie() const
01202 {
01203   bool b = !pimpl->cookies.empty();
01204   ULXR_TRACE(ULXR_PCHAR("hasCookie: ") << b);
01205   return b;
01206 }
01207 
01208 
01209 void HttpProtocol::setCookie(const CppString &in_cont)
01210 {
01211   ULXR_TRACE(ULXR_PCHAR("setCookie: ") << in_cont);
01212   CppString cont = in_cont;
01213   std::size_t uEnd = cont.find(';');
01214   while (uEnd != CppString::npos)
01215   {
01216     CppString sKV = cont.substr(0, uEnd);
01217     cont.erase(0, uEnd+1);
01218     std::size_t uEq = sKV.find('=');
01219     if (uEq != CppString::npos)
01220     {
01221         CppString sKey = stripWS(sKV.substr(0, uEq));
01222         CppString sVal = stripWS(sKV.substr(uEq+1));
01223         ULXR_TRACE(ULXR_PCHAR("setCookie: ") << sKey << ULXR_PCHAR(" ") << sVal);
01224         pimpl->cookies[sKey] = sVal;
01225     }
01226     uEnd = cont.find(';');
01227   }
01228 
01229   std::size_t uEq = cont.find('=');
01230   if (uEq != CppString::npos)
01231   {
01232       CppString sKey = stripWS(cont.substr(0, uEq));
01233       CppString sVal = stripWS(cont.substr(uEq+1));
01234       ULXR_TRACE(ULXR_PCHAR("setCookie: ") << sKey << ULXR_PCHAR(" ") << sVal);
01235       pimpl->cookies[sKey] = sVal;
01236   }
01237 }
01238 
01239 
01240 CppString HttpProtocol::getCookie() const
01241 {
01242   CppString ret;
01243   for (std::map<CppString, CppString>::const_iterator iCookie = pimpl->cookies.begin();
01244         iCookie != pimpl->cookies.end();
01245         ++iCookie)
01246   {
01247       if (iCookie != pimpl->cookies.begin())
01248           ret += ULXR_PCHAR("; ");
01249       ret += (*iCookie).first + ULXR_PCHAR("=") + (*iCookie).second;
01250   }
01251   ULXR_TRACE(ULXR_PCHAR("getCookie: ") << ret);
01252   return ret;
01253 }
01254 
01255 
01256 ULXR_API_IMPL(void) HttpProtocol::setAcceptCookies(bool bAccept)
01257 {
01258   ULXR_TRACE(ULXR_PCHAR("setAcceptCookies: ") << bAccept);
01259   pimpl->bAcceptcookies = bAccept;
01260 }
01261 
01262 
01263 ULXR_API_IMPL(bool) HttpProtocol::isAcceptCookies() const
01264 {
01265   ULXR_TRACE(ULXR_PCHAR("isAcceptCookies: ") << pimpl->bAcceptcookies);
01266   return pimpl->bAcceptcookies;
01267 }
01268 
01269 
01270 ULXR_API_IMPL(void) HttpProtocol::setServerCookie(const CppString &cookie)
01271 {
01272   ULXR_TRACE(ULXR_PCHAR("setServerCookie: ") << cookie);
01273   pimpl->serverCookie = cookie;
01274 }
01275 
01276 
01277 ULXR_API_IMPL(CppString) HttpProtocol::getServerCookie() const
01278 {
01279   ULXR_TRACE(ULXR_PCHAR("getServerCookie: ") << pimpl->serverCookie);
01280   return pimpl->serverCookie;
01281 }
01282 
01283 
01284 ULXR_API_IMPL(bool) HttpProtocol::hasServerCookie() const
01285 {
01286   bool b = pimpl->serverCookie.length() != 0;
01287   ULXR_TRACE(ULXR_PCHAR("hasServerCookie: ") << b);
01288   return b;
01289 }
01290 
01291 
01292 ULXR_API_IMPL(void) HttpProtocol::setClientCookie(const CppString &cookie)
01293 {
01294   ULXR_TRACE(ULXR_PCHAR("setClientCookie: ") << cookie);
01295   pimpl->clientCookie = cookie;
01296 }
01297 
01298 
01299 ULXR_API_IMPL(CppString) HttpProtocol::getClientCookie() const
01300 {
01301   ULXR_TRACE(ULXR_PCHAR("getClientCookie: ") << pimpl->clientCookie);
01302   return pimpl->clientCookie;
01303 }
01304 
01305 
01306 ULXR_API_IMPL(bool) HttpProtocol::hasClientCookie() const
01307 {
01308   bool b = pimpl->clientCookie.length() != 0;
01309   ULXR_TRACE(ULXR_PCHAR("hasClientCookie: ") << b);
01310   return b;
01311 }
01312 
01313 
01314 ULXR_API_IMPL(void) HttpProtocol::setUserAgent(const CppString &ua)
01315 {
01316   pimpl->useragent = ua;
01317 }
01318 
01319 
01320 ULXR_API_IMPL(CppString) HttpProtocol::getUserAgent() const
01321 {
01322   return pimpl->useragent;
01323 }
01324 
01325 
01326 ULXR_API_IMPL(CppString) HttpProtocol::getFirstHeaderLine() const
01327 {
01328   return pimpl->header_firstline;
01329 }
01330 
01331 
01332 ULXR_API_IMPL(void)
01333   HttpProtocol::splitHeaderLine(CppString &head_version, unsigned  &head_status, CppString &head_phrase)
01334 {
01335    head_version = ULXR_PCHAR("");
01336    head_status = 500;
01337    head_phrase = ULXR_PCHAR("Internal error");
01338 
01339    CppString s = stripWS(getFirstHeaderLine());
01340    std::size_t pos = s.find(' ');
01341    if (pos != CppString::npos)
01342    {
01343      head_version = s.substr(0, pos);
01344      s.erase(0, pos+1);
01345    }
01346    else
01347    {
01348      head_version = s;
01349      s = ULXR_PCHAR("");
01350    }
01351    pos = head_version.find('/');
01352    if (pos != CppString::npos)
01353      head_version.erase(0, pos+1);
01354 
01355    CppString stat;
01356    s = stripWS(s);
01357    pos = s.find(' ');
01358    if (pos != CppString::npos)
01359    {
01360      stat = s.substr(0, pos);
01361      s.erase(0, pos+1);
01362    }
01363    else
01364    {
01365      stat = s;
01366      s = ULXR_PCHAR("");
01367    }
01368    head_status = ulxr_atoi(getLatin1(stat).c_str());
01369 
01370    s = stripWS(s);
01371    head_phrase = s;
01372 }
01373 
01374 
01375 ULXR_API_IMPL(void) HttpProtocol::setChunkedTransfer(bool chunked)
01376 {
01377   ULXR_TRACE(ULXR_PCHAR("setChunkedTransfer() ") << chunked);
01378   pimpl->chunked_block = chunked;
01379 }
01380 
01381 
01382 ULXR_API_IMPL(bool) HttpProtocol::isChunkedTransfer() const
01383 {
01384   ULXR_TRACE(ULXR_PCHAR("isChunkedTransfer() ") << pimpl->chunked_block);
01385   return pimpl->chunked_block;
01386 }
01387 
01388 
01389 }  // namespace ulxr
01390 

Generated on Sun Aug 19 20:08:57 2007 for ulxmlrpcpp by  doxygen 1.5.1