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 #ifndef ULXR_OMIT_TCP_STUFF
00037
00038 #define ULXR_NEED_EXPORTS
00039 #include <ulxmlrpcpp/ulxmlrpcpp.h>
00040
00041 #include <sys/stat.h>
00042 #include <csignal>
00043
00044 #include <fstream>
00045 #include <iostream>
00046 #include <cctype>
00047 #include <memory>
00048
00049 #include <ulxmlrpcpp/ulxr_http_server.h>
00050 #include <ulxmlrpcpp/ulxr_except.h>
00051 #include <ulxmlrpcpp/ulxr_dispatcher.h>
00052 #include <ulxmlrpcpp/ulxr_http_protocol.h>
00053 #include <ulxmlrpcpp/ulxr_callparse.h>
00054 #include <ulxmlrpcpp/ulxr_callparse_wb.h>
00055 #include <ulxmlrpcpp/ulxr_file_resource.h>
00056
00057 #ifdef __WIN32__
00058 #include <process.h>
00059 #include <Winsock2.h>
00060
00061 #endif
00062
00063 #ifdef __unix__
00064 #include <sys/socket.h>
00065 #endif
00066
00067 #ifdef ULXR_MULTITHREADED
00068
00069 #ifdef __unix__
00070 #include <pthread.h>
00071 #endif
00072
00073 #endif
00074
00075
00076 namespace ulxr {
00077
00078
00079 #ifdef ULXR_MULTITHREADED
00080
00081
00082
00083 class HttpServer::ThreadData
00084 {
00085 public:
00086
00087 #ifdef __unix__
00088 typedef pthread_t handle_t;
00089 #elif defined(__WIN32__)
00090 typedef HANDLE handle_t;
00091 #else
00092 #error unsupported platform here
00093 #endif
00094
00095
00096
00097
00098
00099 ThreadData (HttpServer *server, HttpProtocol *prot);
00100
00101
00102
00103
00104 bool shouldRun() const;
00105
00106
00107
00108 void requestTermination();
00109
00110
00111
00112
00113 handle_t getHandle() const;
00114
00115
00116
00117
00118 void setHandle(handle_t hd);
00119
00120
00121
00122
00123 HttpProtocol *getProtocol() const;
00124
00125
00126
00127 void incInvoked();
00128
00129
00130
00131
00132 unsigned numInvoked() const;
00133
00134
00135
00136
00137 HttpServer *getServer() const;
00138
00139 private:
00140
00141 bool run;
00142 handle_t handle;
00143 unsigned ctrInvoked;
00144 HttpProtocol *protocol;
00145 HttpServer *server;
00146 };
00147
00148 #endif // ULXR_MULTITHREADED
00149
00150
00151 ULXR_API_IMPL0 HttpServer::HttpServer (HttpProtocol* prot, bool wbxml)
00152 {
00153 init();
00154 wbxml_mode = wbxml;
00155 base_protocol = prot;
00156 base_protocol->setChunkedTransfer(false);
00157 }
00158
00159
00160 #ifdef ULXR_MULTITHREADED
00161
00162 ULXR_API_IMPL0 HttpServer::HttpServer (HttpProtocol* prot, unsigned num_threads, bool wbxml)
00163 {
00164 prot->setChunkedTransfer(false);
00165 init();
00166 wbxml_mode = wbxml;
00167 for (unsigned i = 0; i < num_threads; ++i)
00168 #ifdef _MSC_VER
00169 threads.push_back(new ThreadData(this, (HttpProtocol*)(prot->detach())));
00170 #else
00171 threads.push_back(new ThreadData(this, dynamic_cast<HttpProtocol*>(prot->detach())));
00172 #endif
00173 base_protocol = 0;
00174 }
00175
00176 #endif // ULXR_MULTITHREADED
00177
00178
00179 ULXR_API_IMPL(void) HttpServer::init()
00180 {
00181 http_root_dir = ULXR_GET_STRING(ULXR_DATADIR)
00182 + ULXR_DIRSEP
00183 + ULXR_GET_STRING(ULXR_PACKAGE)
00184 + ULXR_DIRSEP
00185 + ULXR_PCHAR("http");
00186
00187 rpc_resource_root = ULXR_PCHAR("/RPC2");
00188 rpc_dispatcher = 0;
00189 pico_shall_run = true;
00190 wbxml_mode = false;
00191 }
00192
00193
00194 ULXR_API_IMPL(void) HttpServer::releaseHandlers(std::vector<MethodHandler*> &handlers)
00195 {
00196 for (unsigned i = 0; i < handlers.size(); ++i)
00197 delete handlers[i];
00198 handlers.clear();
00199 }
00200
00201
00202 ULXR_API_IMPL0 HttpServer::~HttpServer ()
00203 {
00204 #ifdef ULXR_MULTITHREADED
00205
00206 waitAsync(true);
00207
00208
00209 releaseThreads();
00210
00211 #endif
00212
00213 for (unsigned i = 0; i < resources.size(); ++i)
00214 {
00215 resources[i]->close();
00216 delete resources[i];
00217 }
00218
00219 releaseHandlers(getHandlers);
00220 releaseHandlers(putHandlers);
00221 releaseHandlers(deleteHandlers);
00222 releaseHandlers(postHandlers);
00223 }
00224
00225
00226 ULXR_API_IMPL(void) HttpServer::setRpcDispatcher(Dispatcher *disp)
00227 {
00228 ULXR_TRACE(ULXR_PCHAR("setRpcDispatcher"));
00229 rpc_dispatcher = disp;
00230 rpc_dispatcher->setProtocol(0);
00231 }
00232
00233
00234 ULXR_API_IMPL(void) HttpServer::interpreteHttpHeader(
00235 HttpProtocol *protocol,
00236 CppString &head_resource,
00237 CppString &head_method,
00238 CppString &head_version)
00239 {
00240 ULXR_TRACE(ULXR_PCHAR("interpreteHttpHeader"));
00241 head_method = ULXR_PCHAR("");
00242 head_resource = ULXR_PCHAR("");
00243 head_version = ULXR_PCHAR("");
00244
00245 CppString s = ulxr::stripWS(protocol->getFirstHeaderLine());
00246 std::size_t pos = s.find(' ');
00247 if (pos != CppString::npos)
00248 {
00249 head_method = s.substr(0, pos);
00250 s.erase(0, pos+1);
00251 }
00252 else
00253 {
00254 head_method = s;
00255 s = ULXR_PCHAR("");
00256 }
00257 makeUpper(head_method);
00258
00259 s = stripWS(s);
00260 pos = s.find(' ');
00261 if (pos != CppString::npos)
00262 {
00263 head_resource = s.substr(0, pos);
00264 s.erase(0, pos+1);
00265 }
00266 else
00267 {
00268 head_resource = s;
00269 s = ULXR_PCHAR("");
00270 }
00271
00272 s = stripWS(s);
00273 head_version = s;
00274 pos = head_version.find('/');
00275 if (pos != CppString::npos)
00276 head_version.erase(0, pos+1);
00277
00278 protocol->setPersistent(!protocol->determineClosing(head_version));
00279 }
00280
00281
00282 ULXR_API_IMPL(void) HttpServer::setHttpRoot(const CppString &rt)
00283 {
00284 ULXR_TRACE(ULXR_PCHAR("setHttpRoot"));
00285 http_root_dir = rt;
00286 int rl = rt.length();
00287 if (rl != 0 && http_root_dir[rl-1] == ULXR_DIRSEP[0])
00288 http_root_dir.erase(rl-1);
00289 }
00290
00291
00292 ULXR_API_IMPL(void) HttpServer::checkValidPath(const CppString &resource)
00293 {
00294 ULXR_TRACE(ULXR_PCHAR("checkValidPath"));
00295 if (resource.find(ULXR_PCHAR("..")) != CppString::npos)
00296 throw ConnectionException(ApplicationError,
00297 ulxr_i18n(ULXR_PCHAR("Bad request to resource")), 400);
00298 }
00299
00300
00301 ULXR_API_IMPL(CppString) HttpServer::stripResource(const CppString &in_resource)
00302 {
00303 ULXR_TRACE(ULXR_PCHAR("stripResource ") << in_resource);
00304 CppString resource = in_resource;
00305 CppString s = ULXR_PCHAR("http:");
00306 if (resource.substr(0, s.length()) == s)
00307 resource.erase(0, s.length());
00308
00309 s = ULXR_PCHAR("https:");
00310 if (resource.substr(0, s.length()) == s)
00311 resource.erase(0, s.length());
00312
00313 s = ULXR_PCHAR("//");
00314 if (resource.substr(0, s.length()) == s)
00315 resource.erase(0, s.length());
00316
00317 #ifdef _MSC_VER
00318 size_t pos = 0;
00319 #else
00320 std::size_t pos = 0;
00321 #endif
00322 if ((pos = resource.find(ULXR_PCHAR("/"))) != CppString::npos)
00323 resource.erase(0, pos);
00324 else
00325 resource = ULXR_PCHAR("");
00326
00327 return resource;
00328 }
00329
00330
00331 ULXR_API_IMPL(void)
00332 HttpServer::executeHttpMethod(HttpProtocol *protocol,
00333 Cpp8BitString &conn_pending_data,
00334 const CppString& name,
00335 const CppString& in_resource)
00336 {
00337 ULXR_TRACE(ULXR_PCHAR("executeHttpMethod ") << ULXR_PCHAR(" ")
00338 << name << ULXR_PCHAR(" ") << in_resource);
00339 CppString resource = stripResource(in_resource);
00340 checkValidPath(resource);
00341 ULXR_TRACE(ULXR_PCHAR("executeHttpMethod resource: ") << resource);
00342
00343 if (name == ULXR_PCHAR("GET"))
00344 {
00345 for (unsigned int i = 0; i < getHandlers.size(); ++i)
00346 if (getHandlers[i]->handle(protocol, name, resource, conn_pending_data))
00347 return;
00348
00349 executeHttpGET(protocol, resource);
00350 }
00351
00352 else if (name == ULXR_PCHAR("POST"))
00353 {
00354 for (unsigned int i = 0; i < postHandlers.size(); ++i)
00355 if (postHandlers[i]->handle(protocol, name, resource, conn_pending_data))
00356 return;
00357
00358 executeHttpPOST(protocol, conn_pending_data, resource);
00359 }
00360
00361 else if (name == ULXR_PCHAR("PUT"))
00362 {
00363 for (unsigned int i = 0; i < putHandlers.size(); ++i)
00364 if (putHandlers[i]->handle(protocol, name, resource, conn_pending_data))
00365 return;
00366
00367 executeHttpPUT(protocol, conn_pending_data, resource);
00368 }
00369
00370 else if (name == ULXR_PCHAR("DELETE"))
00371 {
00372 for (unsigned int i = 0; i < deleteHandlers.size(); ++i)
00373 if (deleteHandlers[i]->handle(protocol, name, resource, conn_pending_data))
00374 return;
00375
00376 executeHttpDELETE(protocol, resource);
00377 }
00378
00379 else
00380 executeUnknownHttpMethod(protocol, conn_pending_data, name, resource);
00381
00382 return;
00383 }
00384
00385
00386 ULXR_API_IMPL(void)
00387 HttpServer::executeUnknownHttpMethod(HttpProtocol * ,
00388 Cpp8BitString & ,
00389 const CppString& name,
00390 const CppString& )
00391 {
00392 throw ConnectionException(NotConformingError,
00393 ulxr_i18n(ULXR_PCHAR("Unimplemented http method: "))+name, 501);
00394 }
00395
00396
00397 ULXR_API_IMPL(CppString) HttpServer::createLocalName(const CppString &resource)
00398 {
00399 ULXR_TRACE(ULXR_PCHAR("createLocalName ") << resource);
00400 ULXR_TRACE(ULXR_PCHAR(" http-root: ") << http_root_dir);
00401 CppString filename = http_root_dir;
00402 if (resource.length() == 0 || resource[0] != ULXR_DIRSEP[0])
00403 filename += ULXR_DIRSEP[0];
00404
00405 CppString fullname = filename + resource;
00406
00407 #ifndef __unix__
00408 std::size_t pos = fullname.find (ULXR_CHAR('/'));
00409 while (pos != CppString::npos)
00410 {
00411 fullname[pos] = ULXR_DIRSEP[0];
00412 pos = fullname.find (ULXR_CHAR('/'), pos+1);
00413 }
00414 #else
00415 std::size_t pos = fullname.find (ULXR_CHAR('\\'));
00416 while (pos != CppString::npos)
00417 {
00418 fullname[pos] = ULXR_DIRSEP[0];
00419 pos = fullname.find (ULXR_CHAR('\\'), pos+1);
00420 }
00421 #endif
00422
00423 return fullname;
00424 }
00425
00426
00427 CppString
00428 HttpServer::guessMimeType(const CppString &name) const
00429 {
00430
00431 std::size_t pos = name.rfind('.');
00432 const ulxr::Char *mime = ULXR_PCHAR("");
00433 if (pos != CppString::npos)
00434 {
00435 CppString ext = name.substr(pos+1);
00436 makeLower(ext);
00437 if ( ext == ULXR_PCHAR("html")
00438 || ext == ULXR_PCHAR("htm"))
00439 mime = ULXR_PCHAR("text/html");
00440
00441 else if (ext == ULXR_PCHAR("txt"))
00442 mime = ULXR_PCHAR("text/plain");
00443
00444 else if (ext == ULXR_PCHAR("xml"))
00445 mime = ULXR_PCHAR("text/xml");
00446
00447 else if ( ext == ULXR_PCHAR("jpeg")
00448 || ext == ULXR_PCHAR("jpg"))
00449 mime = ULXR_PCHAR("image/jpg");
00450
00451 else if (ext == ULXR_PCHAR("png"))
00452 mime = ULXR_PCHAR("image/png");
00453
00454 else if (ext == ULXR_PCHAR("gif"))
00455 mime = ULXR_PCHAR("image/gif");
00456 }
00457
00458 return (CppString) mime;
00459 }
00460
00461
00462 ULXR_API_IMPL(void) HttpServer::addResource(CachedResource *cache)
00463 {
00464 ULXR_TRACE(ULXR_PCHAR("addResource ") << (cache ? cache->getResourceName() : ULXR_PCHAR("")));
00465 if (0 == getResource(cache->getResourceName()))
00466 resources.push_back(cache);
00467 }
00468
00469
00470 ULXR_API_IMPL(CachedResource *) HttpServer::getResource(const CppString& resource)
00471 {
00472 ULXR_TRACE(ULXR_PCHAR("getResource ") << resource);
00473 for (unsigned i = 0; i < resources.size(); ++i)
00474 if (resources[i]->getResourceName() == resource)
00475 {
00476 ULXR_TRACE(ULXR_PCHAR("getResource: true"));
00477 return resources[i];
00478 }
00479
00480 ULXR_TRACE(ULXR_PCHAR("getResource: false"));
00481 return 0;
00482 }
00483
00484
00485 ULXR_API_IMPL(void) HttpServer::executeHttpGET(HttpProtocol *protocol,
00486 const CppString& in_resource)
00487 {
00488 ULXR_TRACE(ULXR_PCHAR("executeHttpGET"));
00489
00490 CppString filename;
00491 CppString resource = in_resource;
00492 if (resource == ULXR_PCHAR("/"))
00493 {
00494 filename = createLocalName(ULXR_DIRSEP ULXR_PCHAR("index.html"));
00495 resource = ULXR_PCHAR("index.html");
00496 }
00497 else
00498 filename = createLocalName(resource);
00499
00500 CachedResource *cache = getResource(resource);
00501 if (cache == 0)
00502 {
00503 cache = new FileResource(resource, filename);
00504 addResource(cache);
00505 cache->open();
00506 }
00507 else
00508 cache->reset();
00509
00510 if (!cache->good())
00511 throw ConnectionException(SystemError,
00512 ulxr_i18n(ULXR_PCHAR("Cannot open local input resource: "))+resource, 500);
00513
00514 std::string s = cache->data();
00515 ULXR_TRACE(ULXR_PCHAR("executeHttpGET cachesize ") << s.length());
00516 protocol->sendResponseHeader(200, ULXR_PCHAR("OK"), guessMimeType(filename), s.length());
00517 protocol->writeBody(s.data(), s.length());
00518 }
00519
00520
00521 ULXR_API_IMPL(void) HttpServer::executeHttpRPC(HttpProtocol *protocol,
00522 Cpp8BitString &conn_pending_data)
00523 {
00524 ULXR_TRACE(ULXR_PCHAR("executeHttpRPC"));
00525
00526 #ifdef ULXR_ENFORCE_NON_PERSISTENT
00527 protocol->setPersistent(false);
00528 #endif
00529
00530 if (!protocol->hasHttpProperty(ULXR_PCHAR("content-length")))
00531 {
00532 #ifdef ULXR_SHOW_READ
00533 char buffer [ULXR_RECV_BUFFER_SIZE];
00534 unsigned readed;
00535 Cpp8BitString super_data;
00536 while ((readed = protocol->readRaw(buffer, sizeof(buffer))) > 0)
00537 super_data.append(buffer, readed);
00538 ULXR_DOUT_READ(ULXR_PCHAR("superdata 2 start:\n")
00539 << ULXR_GET_STRING(super_data)
00540 << ULXR_PCHAR("superdata 2 end:\n"));
00541 #endif
00542 throw ConnectionException(NotConformingError,
00543 ulxr_i18n(ULXR_PCHAR("Content-Length of message not available")), 411);
00544 }
00545
00546 else if ( !protocol->hasHttpProperty(ULXR_PCHAR("content-type"))
00547 || ( (protocol->getHttpProperty(ULXR_PCHAR("content-type")).find(ULXR_PCHAR("text/xml")) == CppString::npos)
00548 && (protocol->getHttpProperty(ULXR_PCHAR("content-type")).find(ULXR_PCHAR("wbxml")) == CppString::npos)
00549 )
00550 )
00551 throw ConnectionException(NotConformingError,
00552 ulxr_i18n(ULXR_PCHAR("Bad request, mime type not 'text/xml'")), 400);
00553
00554 Cpp8BitString xml_data = conn_pending_data;
00555
00556 char conn_buffer [ULXR_RECV_BUFFER_SIZE];
00557 long conn_readed;
00558 bool done = false;
00560 while (!done && ((conn_readed = protocol->readRaw(conn_buffer, sizeof(conn_buffer))) > 0) )
00561 {
00562 if (!protocol->hasBytesToRead())
00563 done = true;
00564 xml_data.append(conn_buffer, conn_readed);
00565 }
00566
00567 std::auto_ptr<XmlParserBase> parser;
00568 MethodCallParserBase *cpb = 0;
00569 if (wbxml_mode)
00570 {
00571 ULXR_TRACE(ULXR_PCHAR("waitForResponse in WBXML"));
00572 MethodCallParserWb *cp = new MethodCallParserWb();
00573 cpb = cp;
00574 #ifdef _MSC_VER
00575 std::auto_ptr<XmlParserBase> temp(cp);
00576 parser = temp;
00577 #else
00578 parser.reset(cp);
00579 #endif
00580 }
00581 else
00582 {
00583 ULXR_TRACE(ULXR_PCHAR("waitForResponse in XML"));
00584 MethodCallParser *cp = new MethodCallParser();
00585 cpb = cp;
00586 #ifdef _MSC_VER
00587 std::auto_ptr<XmlParserBase> temp(cp);
00588 parser = temp;
00589 #else
00590 parser.reset(cp);
00591 #endif
00592 }
00593
00594 ULXR_DOUT_XML(ULXR_GET_STRING(std::string(xml_data.data(), xml_data.length())));
00595 if (!parser->parse(xml_data.data(), xml_data.length(), true))
00596 {
00597 throw XmlException(parser->mapToFaultCode(parser->getErrorCode()),
00598 ulxr_i18n(ULXR_PCHAR("Problem while parsing xml request")),
00599 parser->getCurrentLineNumber(),
00600 ULXR_GET_STRING(parser->getErrorString(parser->getErrorCode())));
00601 }
00602 MethodCall call = cpb->getMethodCall();
00603 MethodResponse resp = rpc_dispatcher->dispatchCall(call);
00604 if (!protocol->isTransmitOnly())
00605 protocol->sendRpcResponse(resp, wbxml_mode);
00606 }
00607
00608
00609 ULXR_API_IMPL(void)
00610 HttpServer::executeHttpPOST(HttpProtocol *protocol,
00611 Cpp8BitString &conn_pending_data,
00612 const CppString& resource)
00613 {
00614 ULXR_TRACE(ULXR_PCHAR("executeHttpPOST"));
00615
00616 if (resource == rpc_resource_root && rpc_dispatcher != 0)
00617 executeHttpRPC(protocol, conn_pending_data);
00618 else
00619 {
00620 if (rpc_dispatcher == 0)
00621 throw ConnectionException(ApplicationError,
00622 ulxr_i18n(ULXR_PCHAR("No RPC-Dispatcher set")), 500);
00623 else
00624 throw ConnectionException(ApplicationError,
00625 ulxr_i18n(ULXR_PCHAR("Method POST not allowed for this resource (Bad RPC-Request to \""))
00626 + rpc_resource_root + ULXR_PCHAR("\" ?): ")+resource, 501);
00627 }
00628
00629
00630 }
00631
00632
00633 ULXR_API_IMPL(void) HttpServer::executeHttpPUT(HttpProtocol *protocol,
00634 Cpp8BitString &conn_pending_data,
00635 const CppString& in_resource)
00636 {
00637 ULXR_TRACE(ULXR_PCHAR("executeHttpPUT"));
00638
00639 CppString filename;
00640 CppString resource = in_resource;
00641 if (resource == ULXR_PCHAR("/"))
00642 {
00643 filename = createLocalName(ULXR_DIRSEP ULXR_PCHAR("index.html"));
00644 resource = ULXR_PCHAR("index.html");
00645 }
00646 else
00647 filename = createLocalName(resource);
00648
00649 CachedResource *cache = getResource(resource);
00650 if (cache == 0)
00651 {
00652 cache = new FileResource(resource, filename, false);
00653 addResource(cache);
00654 }
00655 cache->clear();
00656
00657
00658
00659
00660
00661
00662 if (!cache->good() )
00663 throw ConnectionException(SystemError,
00664 ulxr_i18n(ULXR_PCHAR("Cannot create local resource: "))+resource, 500);
00665
00666 #ifdef ULXR_USE_WXSTRING
00667 cache->write(conn_pending_data.c_str(), conn_pending_data.length());
00668 #else
00669 cache->write(conn_pending_data.data(), conn_pending_data.length());
00670 #endif
00671
00672 char conn_buffer [ULXR_RECV_BUFFER_SIZE];
00673 long conn_readed;
00674 bool done = false;
00676 while (!done && ((conn_readed = protocol->readRaw(conn_buffer, sizeof(conn_buffer))) > 0) )
00677 {
00678 if (!protocol->hasBytesToRead())
00679 done = true;
00680 cache->write(conn_buffer, conn_readed);
00681 }
00682
00683 if (!cache->good() )
00684 throw ConnectionException(SystemError,
00685 ulxr_i18n(ULXR_PCHAR("Cannot write to local resource: "))+resource, 500);
00686
00687 protocol->sendResponseHeader(200, ULXR_PCHAR("OK"), ULXR_PCHAR(""), 0);
00688 return;
00689 }
00690
00691
00692 ULXR_API_IMPL(void)
00693 HttpServer::executeHttpDELETE(HttpProtocol *protocol,
00694 const CppString& in_resource)
00695 {
00696 ULXR_TRACE(ULXR_PCHAR("executeHttpDELETE"));
00697 CppString filename;
00698 CppString resource = in_resource;
00699 if (resource == ULXR_PCHAR("/"))
00700 {
00701 filename = createLocalName(ULXR_DIRSEP ULXR_PCHAR("index.html"));
00702 resource = ULXR_PCHAR("index.html");
00703 }
00704 else
00705 filename = createLocalName(resource);
00706
00707 CachedResource *cache = getResource(resource);
00708 if (cache == 0)
00709 {
00710 cache = new FileResource(resource, filename, false);
00711 addResource(cache);
00712 }
00713 cache->clear();
00714
00715 if (!cache->good())
00716 throw ConnectionException(SystemError,
00717 ulxr_i18n(ULXR_PCHAR("Cannot remove local resource: "))+resource, 500);
00718
00719 protocol->sendResponseHeader(200, ULXR_PCHAR("OK"), ULXR_PCHAR(""), 0);
00720 }
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753 ULXR_API_IMPL(void) HttpServer::requestTermination()
00754 {
00755 pico_shall_run = false;
00756 }
00757
00758
00759 ULXR_API_IMPL(std::size_t) HttpServer::runPicoHttpd()
00760 {
00761 ULXR_TRACE(ULXR_PCHAR("runPicoHttpd"));
00762 #ifdef ULXR_MULTITHREADED
00763 if (threads.size() != 0)
00764 return dispatchAsync();
00765 else
00766 #endif
00767 return runPicoHttpd(base_protocol, 0);
00768 }
00769
00770
00771 ULXR_API_IMPL(void) HttpServer::beforeHttpTransaction()
00772 {
00773 }
00774
00775
00776 ULXR_API_IMPL(void) HttpServer::afterHttpTransaction()
00777 {
00778 }
00779
00780
00781 ULXR_API_IMPL(std::size_t)
00782 HttpServer::runPicoHttpd(HttpProtocol *protocol,
00783 #ifdef ULXR_MULTITHREADED
00784 ThreadData *td)
00785 #else
00786 ThreadData *)
00787 #endif
00788 {
00789 ULXR_TRACE(ULXR_PCHAR("runPicoHttpd(HttpProtocol) ")
00790 << std::hex << (void*) protocol
00791 << std::dec);
00792
00793 pico_shall_run = true;
00794
00795
00796 rpc_dispatcher->setProtocol(0);
00797
00798 while (pico_shall_run
00799 #ifdef ULXR_MULTITHREADED
00800 && td->shouldRun()
00801 #endif
00802 )
00803 {
00804 ULXR_TRACE(ULXR_PCHAR("runPicoHttpd 0"));
00805 try
00806 {
00807
00808 #ifdef ULXR_MULTITHREADED
00809 if (td != 0)
00810 td->incInvoked();
00811 #endif // ULXR_MULTITHREADED
00812
00813 beforeHttpTransaction();
00814 ULXR_TRACE(ULXR_PCHAR("runPicoHttpd 1"));
00815 performHttpTransaction(protocol);
00816 ULXR_TRACE(ULXR_PCHAR("runPicoHttpd 2"));
00817 afterHttpTransaction();
00818 }
00819
00820 catch(ConnectionException &ex)
00821 {
00822 forwardThreadedError(ex);
00823 try
00824 {
00825 if (protocol->isOpen())
00826 protocol->sendNegativeResponse(ex.getStatusCode(), ex.why());
00827 protocol->close();
00828 }
00829 catch(...)
00830 {
00831 ULXR_TRACE(ULXR_PCHAR("nested exception"));
00832 protocol->close();
00833 }
00834 ULXR_TRACE(ULXR_PCHAR("Transportation error occured: ") << ULXR_GET_STRING(ex.why()));
00835 }
00836
00837 catch(Exception &ex)
00838 {
00839 forwardThreadedError(ex);
00840
00841 try
00842 {
00843 if (protocol->isOpen())
00844 protocol->sendNegativeResponse(500, ex.why());
00845 protocol->close();
00846 }
00847 catch(...)
00848 {
00849 ULXR_TRACE(ULXR_PCHAR("nested exception"));
00850 protocol->close();
00851 }
00852 ULXR_TRACE(ULXR_PCHAR("Error occured: ") << ULXR_GET_STRING(ex.why()));
00853 }
00854
00855 catch(std::exception &ex)
00856 {
00857 forwardThreadedError(Exception(ApplicationError, ULXR_GET_STRING(ex.what())));
00858
00859 try
00860 {
00861 if (protocol->isOpen())
00862 protocol->sendNegativeResponse(500, ULXR_GET_STRING(ex.what()));
00863 protocol->close();
00864 }
00865 catch(...)
00866 {
00867 ULXR_TRACE(ULXR_PCHAR("nested exception"));
00868 protocol->close();
00869 }
00870 ULXR_TRACE(ULXR_PCHAR("Error occured: ") << ULXR_GET_STRING(ex.what()));
00871 }
00872
00873 catch(...)
00874 {
00875 ULXR_TRACE(ULXR_PCHAR("runPicoHttpd unknown exception"));
00876 RuntimeException ex (SystemError, ULXR_PCHAR("Unknown error occured"));
00877 forwardThreadedError(ex);
00878
00879 try
00880 {
00881 if (protocol->isOpen())
00882 protocol->sendNegativeResponse(500, ex.why());
00883 protocol->close();
00884 }
00885 catch(...)
00886 {
00887 ULXR_TRACE(ULXR_PCHAR("runPicoHttpd nested exception"));
00888 protocol->close();
00889 }
00890 ULXR_TRACE(ULXR_PCHAR("Error occured: ") << ULXR_GET_STRING(ex.why()));
00891 }
00892 }
00893 ULXR_TRACE(ULXR_PCHAR("runPicoHttpd return 0, remaining Threads: ") << numThreads());
00894 return 0;
00895 }
00896
00897
00898 #ifdef ULXR_SHOW_TRACE
00899 ULXR_API_IMPL(void) HttpServer::forwardThreadedError(const Exception &ex) const
00900 #else
00901 ULXR_API_IMPL(void) HttpServer::forwardThreadedError(const Exception &) const
00902 #endif
00903 {
00904 ULXR_TRACE(ULXR_CHAR("Threaded error occured: ") << ex.why());
00905 }
00906
00907
00908 ULXR_API_IMPL(void) HttpServer::performHttpTransaction(HttpProtocol *protocol)
00909 {
00910 ULXR_TRACE(ULXR_PCHAR("performHttpTransaction ")
00911 << std::hex << (void*) protocol
00912 << std::dec);
00913 if (!protocol->isOpen())
00914 {
00915 if (!protocol->accept())
00916 return;
00917 }
00918 else
00919 protocol->resetConnection();
00920
00921 CppString head_resource;
00922 CppString head_method;
00923 CppString head_version;
00924
00925 ULXR_TRACE(ULXR_PCHAR("pHT 1"));
00926 Cpp8BitString conn_pending_data;
00927 char conn_buffer [ULXR_RECV_BUFFER_SIZE];
00928 long conn_readed = 0;
00929 char *buff_ptr;
00930 bool done = false;
00931
00932 ULXR_TRACE(ULXR_PCHAR("pHT 2 ") << done << ULXR_PCHAR(" ") << conn_readed);
00933 while (!done && ((conn_readed = protocol->readRaw(conn_buffer, sizeof(conn_buffer))) > 0) )
00934 {
00935 buff_ptr = conn_buffer;
00936
00937 ULXR_TRACE(ULXR_PCHAR("pHT 3 ") << conn_readed);
00938 while (conn_readed > 0)
00939 {
00940 Protocol::State state = protocol->connectionMachine(buff_ptr, conn_readed);
00941 if (state == Protocol::ConnError)
00942 throw ConnectionException(TransportError,
00943 ulxr_i18n(ULXR_PCHAR("Network problem occured")), 500);
00944
00945
00946 else if ( state == Protocol::ConnSwitchToBody
00947 || state == Protocol::ConnBody)
00948 {
00949 interpreteHttpHeader(protocol, head_resource, head_method, head_version);
00950 ULXR_TRACE( ULXR_PCHAR("head_resource ") << head_resource << std::endl
00951 << ULXR_PCHAR("head_method ") << head_method << std::endl
00952 << ULXR_PCHAR("head_version ") << head_version);
00953 try
00954 {
00955 conn_pending_data.assign(buff_ptr, conn_readed);
00956 conn_readed = 0;
00957
00958 #ifdef ULXR_ENFORCE_NON_PERSISTENT
00959 protocol->setPersistent(false);
00960 #endif
00961
00962 CppString realm = getRealm(head_resource);
00963 if (protocol->checkAuthentication(realm))
00964 executeHttpMethod(protocol,
00965 conn_pending_data,
00966 head_method,
00967 head_resource);
00968 else
00969 protocol->rejectAuthentication(realm);
00970
00971 done = true;
00972 conn_readed = 0;
00973 if (protocol->isOpen() && !protocol->isPersistent())
00974 protocol->close();
00975 }
00976
00977 catch(ConnectionException &ex)
00978 {
00979 if (protocol->isOpen())
00980 protocol->sendNegativeResponse(500, ex.why());
00981 protocol->close();
00982 throw;
00983 }
00984 }
00985 }
00986 }
00987 }
00988
00989
00990 ULXR_API_IMPL(void)
00991 HttpServer::addHttpHandler(const CppString &in_name, MethodHandler *handler)
00992 {
00993 ULXR_TRACE(ULXR_PCHAR("addHttpHandler"));
00994 CppString name = in_name;
00995 makeUpper(name);
00996 if (name == ULXR_PCHAR("GET"))
00997 getHandlers.push_back(handler);
00998
00999 else if (name == ULXR_PCHAR("POST"))
01000 postHandlers.push_back(handler);
01001
01002 else if (name == ULXR_PCHAR("PUT"))
01003 putHandlers.push_back(handler);
01004
01005 else if (name == ULXR_PCHAR("DELETE"))
01006 deleteHandlers.push_back(handler);
01007
01008 else
01009 throw RuntimeException(ApplicationError,
01010 ULXR_PCHAR("Attempt to register a handler for")
01011 ULXR_PCHAR(" an unknown method"));
01012 }
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045 ULXR_API_IMPL(CppString) HttpServer::getRealm(const CppString &i_path) const
01046 {
01047 ULXR_TRACE(ULXR_PCHAR("getRealm ") << i_path);
01048
01049 if (i_path.length() == 0)
01050 return ULXR_PCHAR("");
01051
01052 std::map<CppString, CppString>::const_iterator it = realmXrefs.find(i_path);
01053 if (it != realmXrefs.end())
01054 return (*it).second;
01055
01056 ULXR_TRACE(ULXR_PCHAR("getRealm 1"));
01057 CppString rsrc;
01058 CppString longest_path;
01059 for (it = realmXrefs.begin(); it != realmXrefs.end(); ++it)
01060 {
01061 ULXR_TRACE(ULXR_PCHAR("find ") << (*it).first << ULXR_PCHAR(" ") << (*it).second);
01062 if (i_path.find((*it).first) != CppString::npos)
01063 if ((*it).first.length() > longest_path.length())
01064 {
01065 rsrc = (*it).second;
01066 longest_path = (*it).first;
01067 }
01068 }
01069
01070 if (rsrc.length() != 0)
01071 return rsrc;
01072
01073 ULXR_TRACE(ULXR_PCHAR("getRealm 3"));
01074
01075 CppString path2 = i_path + ULXR_PCHAR("/");
01076 for (it = realmXrefs.begin(); it != realmXrefs.end(); ++it)
01077 {
01078 ULXR_TRACE(ULXR_PCHAR("find ") << (*it).first << ULXR_PCHAR(" ") << (*it).second);
01079 if (path2.find((*it).first) != CppString::npos)
01080 if ((*it).first.length() > longest_path.length())
01081 {
01082 rsrc = (*it).second;
01083 longest_path = (*it).first;
01084 }
01085 }
01086
01087 if (rsrc.length() != 0)
01088 return rsrc;
01089
01090 ULXR_TRACE(ULXR_PCHAR("getRealm 4"));
01091 return ULXR_PCHAR("");
01092 }
01093
01094
01095 ULXR_API_IMPL(void) HttpServer::addRealm(const CppString &path, const CppString &realm)
01096 {
01097 ULXR_TRACE(ULXR_PCHAR("addRealm: ") + realm + ULXR_PCHAR(" at ") + path);
01098 realmXrefs[path] = realm;
01099 }
01100
01101
01102 ULXR_API_IMPL(void)
01103 HttpServer::addAuthentication(const CppString &user,
01104 const CppString &pass,
01105 const CppString &realm)
01106 {
01107 ULXR_TRACE(ULXR_PCHAR("addAuthentication"));
01108 #ifdef ULXR_MULTITHREADED
01109 for (unsigned i = 0; i < threads.size(); ++i)
01110 threads[i]->getProtocol()->addAuthentication(user, pass, realm);
01111 #endif
01112
01113 if (base_protocol != 0)
01114 base_protocol->addAuthentication(user, pass, realm);
01115 }
01116
01117
01118 #ifdef ULXR_MULTITHREADED
01119
01120 ULXR_API_IMPL(void *) HttpServer::startThread(ThreadData *td)
01121 {
01122 ULXR_TRACE(ULXR_PCHAR("startThread ")
01123 << std::hex << (void*) td
01124 << std::dec);
01125 void *ptr = (void*) (td->getServer())->runPicoHttpd(td->getProtocol(), td);
01126 ULXR_TRACE(ULXR_PCHAR("/startThread "));
01127
01128 return ptr;
01129 }
01130
01131
01132 ULXR_API_IMPL(unsigned) HttpServer::dispatchAsync()
01133 {
01134 ULXR_TRACE(ULXR_PCHAR("dispatchAsync()"));
01135 unsigned num_started = 0;
01136
01137 for (unsigned i = 0; i < threads.size(); ++i)
01138 {
01139 ThreadData::handle_t tdh;
01140 #ifdef __unix__
01141 typedef void* (*pthread_sig)(void*);
01142 int result = pthread_create(&tdh, 0, (pthread_sig)startThread, threads[i]);
01143 if (result == 0)
01144 ++num_started;
01145 #elif defined(__WIN32__)
01146 unsigned tid;
01147 typedef unsigned int (__stdcall *thread_sig)(void*);
01148 tdh = (HANDLE)_beginthreadex(0, 16*1024, (thread_sig)startThread,
01149 threads[i], CREATE_SUSPENDED,
01150 &tid );
01151 int resume = ResumeThread(tdh);
01152 if (tdh >= 0 && resume >= 0)
01153 ++num_started;
01154 #else
01155 #error unsupported platform here
01156 #endif
01157 threads[i]->setHandle(tdh);
01158 }
01159 ULXR_TRACE(ULXR_PCHAR("/dispatchAsync()"));
01160 return num_started;
01161 }
01162
01163
01164 ULXR_API_IMPL(unsigned) HttpServer::numThreads() const
01165 {
01166 return threads.size();
01167 }
01168
01169
01170 ULXR_API_IMPL(void) HttpServer::terminateAllThreads(unsigned )
01171 {
01172 ULXR_TRACE(ULXR_PCHAR("Request to terminate all threads."));
01173 requestTermination();
01174 for (unsigned i1 = 0; i1 < threads.size(); ++i1)
01175 {
01176 #ifdef ULXR_MULTITHREADED
01177 threads[i1]->requestTermination();
01178 #endif
01179 }
01180 }
01181
01182
01183 ULXR_API_IMPL(void) HttpServer::shutdownAllThreads(unsigned )
01184 {
01185 ULXR_TRACE(ULXR_PCHAR("Request to shutdown all threads."));
01186 requestTermination();
01187 for (unsigned i1 = 0; i1 < threads.size(); ++i1)
01188 {
01189 #ifdef ULXR_MULTITHREADED
01190 threads[i1]->requestTermination();
01191 try
01192 {
01193 #ifdef __WIN32__
01194 threads[i1]->getProtocol()->shutdown(SD_BOTH);
01195 #else
01196 threads[i1]->getProtocol()->shutdown(SHUT_RDWR);
01197 #endif
01198 }
01199 catch(...)
01200 {
01201 }
01202 #endif
01203 }
01204 }
01205
01206
01207 ULXR_API_IMPL(void) HttpServer::waitAsync(bool term, bool stat)
01208 {
01209 ULXR_TRACE(ULXR_PCHAR("waitAsync"));
01210
01211 if (threads.size() == 0)
01212 return;
01213
01214 if (term)
01215 terminateAllThreads(1000);
01216
01217 ULXR_TRACE(ULXR_PCHAR("waitAsync: join"));
01218 for (unsigned i = 0; i < threads.size(); ++i)
01219 {
01220 ULXR_TRACE(ULXR_PCHAR(" join " << i));
01221 #ifdef __unix__
01222 void *status;
01223 pthread_join(threads[i]->getHandle(), &status);
01224 #elif defined(__WIN32__)
01225 WaitForSingleObject(threads[i]->getHandle(), INFINITE);
01226 CloseHandle(threads[i]->getHandle());
01227 #else
01228 #error unsupported platform here
01229 #endif
01230 ULXR_TRACE(ULXR_PCHAR("waitAsync: joined ") << i);
01231
01232 }
01233
01234 if (stat)
01235 printStatistics();
01236
01237 releaseThreads();
01238 ULXR_TRACE(ULXR_PCHAR("/waitAsync"));
01239 }
01240
01241
01242 ULXR_API_IMPL(void) HttpServer::releaseThreads()
01243 {
01244 ULXR_TRACE(ULXR_PCHAR("releaseThreads()"));
01245 for (unsigned i = 0; i < threads.size(); ++i)
01246 {
01247 delete threads[i]->getProtocol();
01248 delete threads[i];
01249 }
01250
01251 threads.clear();
01252 }
01253
01254
01255 ULXR_API_IMPL(void) HttpServer::printStatistics() const
01256 {
01257 for (unsigned i = 0; i < threads.size(); ++i)
01258 ULXR_COUT << ULXR_PCHAR("Thread ")
01259 << std::dec << i
01260 << ULXR_PCHAR(" invoked ")
01261 << threads[i]->numInvoked()
01262 << ULXR_PCHAR(" times.\n");
01263 }
01264
01265
01266 #endif // ULXR_MULTITHREADED
01267
01268
01270
01271
01272 #ifdef ULXR_MULTITHREADED
01273
01274 HttpServer::ThreadData::ThreadData (HttpServer *serv, HttpProtocol *prot)
01275 {
01276 run = true;
01277 handle = 0;
01278 ctrInvoked = 0;
01279 protocol = prot;
01280 server = serv;
01281 }
01282
01283
01284 bool HttpServer::ThreadData::shouldRun() const
01285 {
01286 return run;
01287 }
01288
01289
01290 void HttpServer::ThreadData::requestTermination()
01291 {
01292 ULXR_TRACE(ULXR_PCHAR("Request to terminate a single thread."));
01293 run = false;
01294 }
01295
01296
01297 HttpServer::ThreadData::handle_t
01298 HttpServer::ThreadData::getHandle() const
01299 {
01300 ULXR_TRACE(ULXR_PCHAR("HttpServer::ThreadData::getHandle ") << handle);
01301 return handle;
01302 }
01303
01304
01305 void HttpServer::ThreadData::setHandle(handle_t hd)
01306 {
01307 ULXR_TRACE(ULXR_PCHAR("HttpServer::ThreadData::setHandle ") << hd);
01308 handle = hd;
01309 }
01310
01311
01312 HttpProtocol *HttpServer::ThreadData::getProtocol() const
01313 {
01314 return protocol;
01315 }
01316
01317
01318 HttpServer *HttpServer::ThreadData::getServer() const
01319 {
01320 return server;
01321 }
01322
01323
01324 void HttpServer::ThreadData::incInvoked()
01325 {
01326 ctrInvoked++;
01327 }
01328
01329
01330 unsigned HttpServer::ThreadData::numInvoked() const
01331 {
01332 return ctrInvoked;
01333 }
01334
01335 #endif // ULXR_MULTITHREADED
01336
01337
01339
01340
01341
01342 ULXR_API_IMPL0 MethodHandler::MethodHandler(hidden::StaticMethodHandler handler)
01343 : static_handler(handler),
01344 dynamic_handler(0)
01345 {
01346 }
01347
01348
01349 ULXR_API_IMPL0 MethodHandler::MethodHandler(hidden::DynamicMethodHandler handler)
01350 : static_handler(0),
01351 dynamic_handler(handler)
01352 {
01353 }
01354
01355
01356 ULXR_API_IMPL0 MethodHandler::~MethodHandler()
01357 {
01358 delete dynamic_handler;
01359 }
01360
01361
01362 ULXR_API_IMPL(bool) MethodHandler::handle(HttpProtocol *conn,
01363 const CppString &method,
01364 const CppString &resource,
01365 const Cpp8BitString &conn_data)
01366 {
01367 ULXR_TRACE(ULXR_PCHAR("MethodHandler::handle"));
01368
01369 if (0 != dynamic_handler)
01370 {
01371 return dynamic_handler->handle(conn, method, resource, conn_data);
01372 }
01373
01374 else if (0 != static_handler)
01375 {
01376 return static_handler(conn, method, resource, conn_data);
01377 }
01378
01379 return false;
01380 }
01381
01382
01383 }
01384
01385
01386 #endif // ULXR_OMIT_TCP_STUFF
01387