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
00031
00032
00033
00034
00035
00036
00037
00038 #define ULXR_NEED_EXPORTS
00039 #include <ulxmlrpcpp/ulxmlrpcpp.h>
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;
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
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
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")))
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
00322
00323
00324
00325
00326
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')
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 != ' ')
00362 {
00363 parseHeaderLine();
00364 setConnectionState(ConnHeaderLine);
00365 }
00366 else
00367 setConnectionState(ConnHeaderLine);
00368 break;
00369
00370 case ConnHeaderLine:
00371
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)
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;
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
00478
00479 case ConnBody:
00480 ULXR_TRACE(ULXR_PCHAR("ConnBody:"));
00481 return ConnBody;
00482
00483
00484 case ConnError:
00485 ULXR_TRACE(ULXR_PCHAR("ConnError:"));
00486 return ConnError;
00487
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);
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
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");
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");
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");
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);
00884
00885 #else
00886
00887 char buff[40];
00888 char * ct = ::ctime_r(&tm, buff);
00889 CppString s = ULXR_GET_STRING(ct);
00890
00891 #endif
00892
00893 s.erase(s.length()-1);
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
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
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);
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)
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;
01095 }
01096 else
01097 {
01098 return hasClosingProperty();
01099
01100
01101
01102
01103 }
01104
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
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 }
01390