--- /dev/null
+//\r
+// HTTPDaemon.cpp\r
+//\r
+\r
+#define DBG_LEVEL 0\r
+#include <Raym/Log.h>\r
+#include <Raym/Raym.h>\r
+#include "net/HTTPDaemon.h"\r
+\r
+using namespace Raym;\r
+\r
+namespace NET\r
+{\r
+\r
+HTTPDaemon::HTTPDaemon()\r
+{\r
+ DebugLog2("HTTPDaemon::HTTPDaemon()");\r
+\r
+ _port = -1;\r
+ _backlog = -1;\r
+ _state = ST_IDLE;\r
+ _rootPath = NULL;\r
+ _delegate = NULL;\r
+ _sockets = NULL;\r
+\r
+}\r
+\r
+HTTPDaemon::~HTTPDaemon()\r
+{\r
+ stop();\r
+\r
+ RELEASE(_rootPath);\r
+ RELEASE(_sockets);\r
+\r
+ DebugLog2("HTTPDaemon::~HTTPDaemon()");\r
+}\r
+\r
+HTTPDaemon *HTTPDaemon::alloc()\r
+{\r
+ return new HTTPDaemon();\r
+}\r
+\r
+HTTPDaemon *HTTPDaemon::initWithPort(int port, int backlog)\r
+{\r
+ DebugLog2("HTTPDaemon::initWithPort()");\r
+\r
+ _port = port;\r
+ _backlog = backlog;\r
+ _sockets = Array::alloc()->initWithCapacity(0);\r
+ return this;\r
+}\r
+\r
+void HTTPDaemon::setDelegate(HTTPDaemonDelegate *delegate)\r
+{\r
+ DebugLog2("HTTPDaemon::setDelegate()");\r
+\r
+ EnterCriticalSection(&_cs);\r
+ _delegate = delegate;\r
+ LeaveCriticalSection(&_cs);\r
+}\r
+\r
+void HTTPDaemon::setRootPath(String *path)\r
+{\r
+ DebugLog2("HTTPDaemon::setRootPath()");\r
+\r
+ RELEASE(_rootPath);\r
+ if (path != NULL)\r
+ {\r
+ _rootPath = path;\r
+ _rootPath->retain();\r
+ }\r
+}\r
+\r
+String *HTTPDaemon::rootPath()\r
+{\r
+ return _rootPath;\r
+}\r
+\r
+HTTPResponse *HTTPDaemon::responseWithReason(String *reason, int status, String *version)\r
+{\r
+ DebugLog2("HTTPDaemon::responseWithReason()");\r
+\r
+ HTTPResponse *resp = HTTPResponse::alloc()->init();\r
+ resp->setVersion(version);\r
+ resp->setReason(reason);\r
+ resp->setStatus(status);\r
+\r
+ // header & body\r
+ InternetTextMessageHeader * header = NULL;\r
+ InternetTextMessageBody * body = NULL;\r
+ switch (status)\r
+ {\r
+ case HTTP_STATUS_NO_CONTENT:\r
+ {\r
+ header = InternetTextMessageHeader::alloc()->init();\r
+ header->setFieldBodyWithName(String::stringWithUTF8String("close"), String::stringWithUTF8String("Connection"));\r
+ }\r
+ break;\r
+\r
+ case HTTP_STATUS_INTERNAL_SERVER_ERROR:\r
+ {\r
+ // header\r
+ header = InternetTextMessageHeader::alloc()->init();\r
+ header->setFieldBodyWithName(String::stringWithUTF8String("close"), String::stringWithUTF8String("Connection"));\r
+\r
+ // body\r
+ char html[1024];\r
+ sprintf_s(html, 1024, "<html><head><title>%s</title></head><body>%s</body></html>", reason->cString(), reason->cString());\r
+ body = InternetTextMessageBody::alloc()->initWithString(String::stringWithUTF8String(html));\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ // Contet-Length\r
+ header->setFieldBodyWithName(String::stringWithFormat("%I64u", body->body()->length()), "Content-Length");\r
+\r
+ // message\r
+ InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);\r
+ RELEASE(header);\r
+ RELEASE(body);\r
+\r
+ resp->setMessage(message);\r
+ resp->autorelease();\r
+ RELEASE(message);\r
+\r
+ return resp;\r
+}\r
+\r
+HTTPResponse *HTTPDaemon::responseWithPath(String *path, HTTPRequest *request)\r
+{\r
+ DebugLog2("HTTPDaemon::responseWithPath()");\r
+\r
+ HTTPResponse *result = NULL;\r
+ if ((path != NULL) && (request != NULL))\r
+ {\r
+ Data *bodyData = Data::alloc()->initWithContentsOfFile(path);\r
+ if (bodyData != NULL)\r
+ {\r
+ // header\r
+ InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();\r
+ // Date\r
+ // Server\r
+ // Content-Encoding\r
+ // Last-Modified\r
+ // Content-Type\r
+ String *ext = path->pathExtension()->lowercaseString();\r
+ if (ext->isEqualToString("htm") || ext->isEqualToString("html"))\r
+ {\r
+ header->setFieldBodyWithName("text/html", "Content-Type");\r
+ }\r
+ else if (ext->isEqualToString("jpg"))\r
+ {\r
+ header->setFieldBodyWithName("image/jpeg", "Content-Type");\r
+ }\r
+ else if (ext->isEqualToString("png"))\r
+ {\r
+ header->setFieldBodyWithName("image/png", "Content-Type");\r
+ }\r
+ else if (ext->isEqualToString("gif"))\r
+ {\r
+ header->setFieldBodyWithName("image/gif", "Content-Type");\r
+ }\r
+ else if (ext->isEqualToString("js"))\r
+ {\r
+ header->setFieldBodyWithName("text/javascript", "Content-Type");\r
+ }\r
+ else if (ext->isEqualToString("css"))\r
+ {\r
+ header->setFieldBodyWithName("text/css", "Content-Type");\r
+ }\r
+ else if (ext->isEqualToString("log"))\r
+ {\r
+ header->setFieldBodyWithName("text/plane", "Content-Type");\r
+ }\r
+ else if (ext->isEqualToString("m3u8"))\r
+ {\r
+ header->setFieldBodyWithName("application/x-mpegURL", "Content-Type");\r
+ }\r
+ else\r
+ {\r
+ header->setFieldBodyWithName("application/octet-stream", "Content-Type");\r
+ }\r
+ // Connection\r
+ // Transfer-Encoding\r
+ // Content-Length\r
+ header->setFieldBodyWithName(String::stringWithFormat("%I64u", bodyData->length()), "Content-Length");\r
+\r
+ // body\r
+ InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithData(bodyData);\r
+ RELEASE(bodyData);\r
+\r
+ // message\r
+ InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);\r
+ RELEASE(header);\r
+ RELEASE(body);\r
+ if (message != NULL)\r
+ {\r
+// result = HTTPResponse::response();\r
+ result = HTTPResponse::alloc()->init();\r
+ result->setVersion(request->version());\r
+ result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));\r
+ result->setStatus(HTTP_STATUS_OK);\r
+ result->setMessage(message);\r
+ result->autorelease();\r
+ RELEASE(message);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ DebugLog3("HTTPDaemon::responseWithPath(): date read error.");\r
+ }\r
+ }\r
+ return result;\r
+}\r
+\r
+String *HTTPDaemon::reasonForStatus(int status)\r
+{\r
+ DebugLog2("HTTPDaemon::reasonForStatus()");\r
+\r
+ const char *result = NULL;\r
+ switch (status)\r
+ {\r
+ // Informational 1xx\r
+ case 100: result = "Continue"; break;\r
+ case 101: result = "Swithing Protocols"; break;\r
+ // Successful 2xx\r
+ case 200: result = "OK"; break;\r
+ case 201: result = "Created"; break;\r
+ case 202: result = "Accepted"; break;\r
+ case 203: result = "Non-Authoritative Information"; break;\r
+ case 204: result = "No Content"; break;\r
+ case 205: result = "Reset Content"; break;\r
+ case 206: result = "Partial Content"; break;\r
+ // Redirection 3xx\r
+ case 300: result = "Multiple Choices"; break;\r
+ case 301: result = "Moved Permanently"; break;\r
+ case 302: result = "Found"; break;\r
+ case 303: result = "See Other"; break;\r
+ case 304: result = "Not Modified"; break;\r
+ case 305: result = "Use Proxy"; break;\r
+ case 306: result = "(Unused)"; break;\r
+ case 307: result = "Temporary Redirect"; break;\r
+ // Client Error 4xx\r
+ case 400: result = "Bad Request"; break;\r
+ case 401: result = "Unauthorized"; break;\r
+ case 402: result = "Payment Required"; break;\r
+ case 403: result = "Forbidden"; break;\r
+ case 404: result = "Not Found"; break;\r
+ case 405: result = "Method Not Allowed"; break;\r
+ case 406: result = "Not Acceptable"; break;\r
+ case 407: result = "Proxy Authentication Required"; break;\r
+ case 408: result = "Request Timeout"; break;\r
+ case 409: result = "Conflict"; break;\r
+ case 410: result = "Gone"; break;\r
+ case 411: result = "Length Required"; break;\r
+ case 412: result = "Precondition Failed"; break;\r
+ case 413: result = "Request Entity Too Large"; break;\r
+ case 414: result = "Request-URI Too Long"; break;\r
+ case 415: result = "Unsupported Media Type"; break;\r
+ case 416: result = "Requested Range Not Satisfiable"; break;\r
+ case 417: result = "Expectation Failed"; break;\r
+ // Server Error 5xx\r
+ case 500: result = "Internal Server Error"; break;\r
+ case 501: result = "Not Implemented"; break;\r
+ case 502: result = "Bad Gateway"; break;\r
+ case 503: result = "Service Unavailable"; break;\r
+ case 504: result = "Gateway Timeout"; break;\r
+ case 505: result = "HTTP Version Not Supported"; break;\r
+ default: break;\r
+ }\r
+ return String::stringWithUTF8String(result);\r
+}\r
+\r
+unsigned __stdcall HTTPDaemon_session(void *arg)\r
+{\r
+ HTTPDaemonSessionArgs *session = (HTTPDaemonSessionArgs *)arg;\r
+ session->_daemon->session(session->_sock, &session->_client);\r
+ closesocket(session->_sock);\r
+ delete session;\r
+ return 0;\r
+}\r
+\r
+void HTTPDaemon::session(SOCKET sock, struct sockaddr_in *client)\r
+{\r
+ DebugLog2("HTTPDaemon::session()");\r
+\r
+ Number *num_sock = Number::alloc()->initWithInt((int)sock);\r
+\r
+ EnterCriticalSection(&_cs);\r
+ _sockets->addObject(num_sock);\r
+ LeaveCriticalSection(&_cs);\r
+\r
+ while (true)\r
+ {\r
+ AutoreleasePool *pool = AutoreleasePool::alloc()->init();\r
+ bool done;\r
+\r
+ HTTPResponse *response = NULL;\r
+ DebugLog3("before request()");\r
+ HTTPRequest *request = HTTPRequest::requestWithSocket(sock);\r
+ DebugLog3("after request()");\r
+ if (request != NULL)\r
+ {\r
+ if (_delegate != NULL)\r
+ {\r
+ response = _delegate->request(request, client);\r
+ }\r
+\r
+// if ((response == NULL) && request->method()->isEqualToString(String::stringWithUTF8String("GET")))\r
+ if ((response == NULL) && (request->method()->isEqualToString("GET") || request->method()->isEqualToString("HEAD")))\r
+ {\r
+ if (_rootPath != NULL)\r
+ {\r
+ String *path = _rootPath->stringByAppendingPathComponent(request->URI());\r
+ //path = path->stringByAbbreviatingWithTildeInPath();\r
+ //path = path->stringByStandardizingPath();\r
+ if (path->hasPrefix(_rootPath))\r
+ {\r
+ FileManager *fm = FileManager::defaultManager();\r
+ bool isDir = false;\r
+ if (fm->fileExistsAtPath(path, &isDir))\r
+ {\r
+ if ((!isDir) && !(request->URI()->hasSuffix("/")))\r
+ {\r
+ String *ext = path->pathExtension()->lowercaseString();\r
+ if (ext->isEqualToString("htm") ||\r
+ ext->isEqualToString("html") ||\r
+ ext->isEqualToString("jpg") ||\r
+ ext->isEqualToString("png") ||\r
+ ext->isEqualToString("gif") ||\r
+ ext->isEqualToString("js") ||\r
+ ext->isEqualToString("manifest") ||\r
+ ext->isEqualToString("gtpl") ||\r
+ ext->isEqualToString("css"))\r
+ {\r
+ response = responseWithPath(path, request);\r
+ if (response == NULL)\r
+ {\r
+ DebugLog2("error: %s\n", path->cString());\r
+ }\r
+ }\r
+ else\r
+ {\r
+ DebugLog2("unsupported type: %s\n", ext->cString());\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ DebugLog2("not exists: %s\n", path->cString());\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (response == NULL)\r
+ {\r
+ DebugLog3("response == NULL");\r
+ String *ver;\r
+ if (request == NULL)\r
+ {\r
+ ver = String::stringWithUTF8String("HTTP/1.1");\r
+ }\r
+ else\r
+ {\r
+ ver = request->version();\r
+ }\r
+\r
+ int status;\r
+ if (request == NULL)\r
+ {\r
+ DebugLog3("request == NULL");\r
+ }\r
+ else if (request->method() == NULL)\r
+ {\r
+ DebugLog3("method == NULL");\r
+ }\r
+ if (request->method()->isEqualToString("GET"))\r
+ {\r
+ status = HTTP_STATUS_INTERNAL_SERVER_ERROR;\r
+ }\r
+ else if (request->method()->isEqualToString("POST"))\r
+ {\r
+ status = HTTP_STATUS_NO_CONTENT;\r
+ }\r
+ response = responseWithReason(reasonForStatus(status), status, ver);\r
+ }\r
+\r
+ // status line\r
+ char statusLine[256];\r
+ sprintf_s(statusLine, sizeof(statusLine), "%s %03d %s\r\n", response->version()->cString(), response->status(), response->reason()->cString());\r
+ send(sock, statusLine, (int)strlen(statusLine), 0);\r
+\r
+ InternetTextMessage *message = response->message();\r
+ if (message != NULL)\r
+ {\r
+ // response header\r
+ InternetTextMessageHeader *header = message->header();\r
+ if (header != NULL)\r
+ {\r
+ Array *fieldNames = header->fieldNames();\r
+ for (uint i = 0; i < fieldNames->count(); ++i)\r
+ {\r
+ String *name = (String *)fieldNames->objectAtIndex(i);\r
+ char field[16384];\r
+ sprintf_s(field, sizeof(field), "%s: %s\r\n", name->cString(), header->fieldBodyForName(name)->cString());\r
+\r
+ DebugLog2("send response header");\r
+ send(sock, field, (int)strlen(field), 0);\r
+ }\r
+ }\r
+\r
+ send(sock, "\r\n", 2, 0);\r
+\r
+ if (!request->method()->isEqualToString("HEAD"))\r
+ {\r
+ // response entity\r
+ InternetTextMessageBody *body = message->body();\r
+ if (body != NULL)\r
+ {\r
+ const char *ptr = NULL;\r
+ UInteger length;\r
+ Data *data = body->data();\r
+ if (data != NULL)\r
+ {\r
+ ptr = (const char *)data->bytes();\r
+ length = data->length();\r
+ }\r
+ else if (body->body() != NULL)\r
+ {\r
+ String *str = body->body();\r
+ ptr = str->cString();\r
+ length = str->length();\r
+ }\r
+ if (ptr != NULL)\r
+ {\r
+ UInteger offset = 0;\r
+ while (offset < length)\r
+ {\r
+ int len = ((length - offset) > 16384) ? 16384 : (int)(length - offset);\r
+ DebugLog2("send response entity");\r
+ send(sock, &ptr[offset], len, 0);\r
+ offset += len;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if ((response->status() / 100) != 2)\r
+ {\r
+ DebugLog2("done. response is not OK.");\r
+ done = true;\r
+ }\r
+ else if (request != NULL)\r
+ {\r
+ if (message != NULL)\r
+ {\r
+ InternetTextMessageHeader *header = message->header();\r
+ if (header != NULL)\r
+ {\r
+ String *fieldBody = header->fieldBodyForName(String::stringWithUTF8String("Connection"));\r
+ if (fieldBody != NULL)\r
+ {\r
+ if (strstr(fieldBody->cString(), "close") != NULL)\r
+ {\r
+ DebugLog2("done. request connection is close.");\r
+ done = true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ DebugLog3("reauest is null");\r
+ done = true;\r
+ }\r
+\r
+ pool->release();\r
+ if (done)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ EnterCriticalSection(&_cs);\r
+ _sockets->removeObject(num_sock);\r
+ LeaveCriticalSection(&_cs);\r
+ num_sock->release();\r
+}\r
+\r
+unsigned __stdcall HTTPDaemon_run(void *arg)\r
+{\r
+ ((HTTPDaemon *)arg)->run();\r
+ return 0;\r
+}\r
+\r
+void HTTPDaemon::run()\r
+{\r
+ DebugLog2("%s()\n", __FUNCTION__);\r
+\r
+ AutoreleasePool *pool = AutoreleasePool::alloc()->init();\r
+\r
+ EnterCriticalSection(&_cs);\r
+\r
+ while (_state == ST_READY)\r
+ {\r
+/*\r
+使用側でコールしておくこと\r
+ WSADATA wsaData;\r
+ WSAStartup(MAKEWORD(2,0), &wsaData);\r
+*/\r
+ SOCKET httpd = INVALID_SOCKET;\r
+\r
+ // ready socket\r
+ httpd = socket(AF_INET, SOCK_STREAM, 0);\r
+ if (httpd == INVALID_SOCKET)\r
+ {\r
+ DebugLog3("error: socket() %d\n", WSAGetLastError());\r
+ break;\r
+ }\r
+\r
+ //\r
+ BOOL yes = 1;\r
+ setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(yes));\r
+\r
+ // bind\r
+ struct sockaddr_in own_addr;\r
+ own_addr.sin_family = AF_INET;\r
+ own_addr.sin_port = htons(_port);\r
+ own_addr.sin_addr.s_addr = htonl(INADDR_ANY);\r
+ if (bind(httpd, (struct sockaddr *)&own_addr, sizeof(own_addr)) != 0)\r
+ {\r
+ DebugLog3("error: bind() %d\n", WSAGetLastError());\r
+ closesocket(httpd);\r
+ break;\r
+ }\r
+\r
+ // listen\r
+ if (listen(httpd, _backlog) != 0)\r
+ {\r
+ DebugLog3("error: listen() %d\n", WSAGetLastError());\r
+ closesocket(httpd);\r
+ break;\r
+ }\r
+\r
+ // state change\r
+ _state = ST_RUN;\r
+\r
+ LeaveCriticalSection(&_cs);\r
+\r
+ bool done = false;\r
+ while (!done)\r
+ {\r
+ fd_set fdset;\r
+ FD_ZERO(&fdset);\r
+ FD_SET(httpd, &fdset);\r
+ struct timeval timeout = {1, 0};\r
+ \r
+ if (select(0, &fdset, NULL, NULL, &timeout) == SOCKET_ERROR)\r
+ {\r
+ int err = WSAGetLastError();\r
+ if (err != WSAEINTR)\r
+ {\r
+ DebugLog3("error: select() %d\n", err);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (FD_ISSET(httpd, &fdset))\r
+ {\r
+ // accept\r
+ struct sockaddr_in acc_addr;\r
+ int sock_len = sizeof(acc_addr);\r
+ SOCKET newsock;\r
+ if ((newsock = accept(httpd, (struct sockaddr *)&acc_addr, &sock_len)) != INVALID_SOCKET)\r
+ {\r
+ HTTPDaemonSessionArgs *args = new HTTPDaemonSessionArgs();\r
+ args->_daemon = this;\r
+ args->_sock = newsock;\r
+ memcpy(&args->_client, &acc_addr, sizeof(acc_addr));\r
+\r
+ HANDLE h;\r
+ unsigned int uiThreadId;\r
+ h = (HANDLE)_beginthreadex(NULL,\r
+ 0,\r
+ HTTPDaemon_session,\r
+ args,\r
+ 0,\r
+ &uiThreadId);\r
+ if (h == NULL)\r
+ {\r
+ DebugLog3("error: _beginthreades()\n");\r
+ closesocket(newsock);\r
+ delete args;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ DebugLog3("error: accept() %d\n", WSAGetLastError());\r
+ }\r
+ }\r
+\r
+ // state check\r
+ EnterCriticalSection(&_cs);\r
+ done = (_state == ST_DONE);\r
+ LeaveCriticalSection(&_cs);\r
+ }\r
+\r
+ // socket close\r
+ closesocket(httpd);\r
+\r
+// WSACleanup();\r
+\r
+ // state change\r
+ EnterCriticalSection(&_cs);\r
+ break;\r
+ }\r
+\r
+ DebugLog2("HTTPDaemon::run() loop done.");\r
+\r
+ // セッションの終了待ち\r
+ if (_sockets->count() > 0)\r
+ {\r
+ // 残存セッションを終了させる為、ソケットを閉じる\r
+ for (uint i = 0; i < _sockets->count(); ++i)\r
+ {\r
+ SOCKET s = (SOCKET)((Number *)_sockets->objectAtIndex(i))->intValue();\r
+ closesocket(s);\r
+ }\r
+ // セッションが終了して_socketからオブジェクトを削除するのを待つ\r
+ while (_sockets->count() > 0)\r
+ {\r
+ LeaveCriticalSection(&_cs);\r
+ Sleep(20);\r
+ EnterCriticalSection(&_cs);\r
+ }\r
+ }\r
+\r
+ DebugLog2("HTTPDaemon::run() session close done.");\r
+\r
+ _state = ST_IDLE;\r
+\r
+ LeaveCriticalSection(&_cs);\r
+\r
+ pool->release();\r
+\r
+ DebugLog2("%s() done.\n", __FUNCTION__);\r
+}\r
+\r
+bool HTTPDaemon::start()\r
+{\r
+ DebugLog2("%s()\n", __FUNCTION__);\r
+ \r
+ bool result = false;\r
+ \r
+ EnterCriticalSection(&_cs);\r
+ \r
+ if (_state == ST_IDLE)\r
+ {\r
+ HANDLE h;\r
+ unsigned int uiThreadId;\r
+ \r
+ h = (HANDLE)_beginthreadex(NULL,\r
+ 0,\r
+ HTTPDaemon_run,\r
+ this,\r
+ 0,\r
+ &uiThreadId);\r
+ if (h != NULL)\r
+ {\r
+ _state = ST_READY;\r
+\r
+ LeaveCriticalSection(&_cs);\r
+\r
+ bool done = false;\r
+ while (!done)\r
+ {\r
+ bool needSleep = false;\r
+\r
+ EnterCriticalSection(&_cs);\r
+\r
+ if (_state == ST_IDLE)\r
+ {\r
+ done = true;\r
+ }\r
+ else if (_state == ST_RUN)\r
+ {\r
+ done = true;\r
+ result = true;\r
+ }\r
+ else if (_state == ST_READY)\r
+ {\r
+ needSleep = true;\r
+ }\r
+ LeaveCriticalSection(&_cs);\r
+\r
+ if (needSleep)\r
+ {\r
+ ::Sleep(100); // 100 ms\r
+ }\r
+ }\r
+\r
+ EnterCriticalSection(&_cs);\r
+ }\r
+ }\r
+\r
+ LeaveCriticalSection(&_cs);\r
+\r
+ return result;\r
+}\r
+\r
+void HTTPDaemon::stop()\r
+{\r
+ DebugLog2("HTTPDaemon::stop()", __FUNCTION__);\r
+\r
+ EnterCriticalSection(&_cs);\r
+ if (_state == ST_RUN)\r
+ {\r
+ _state = ST_DONE;\r
+ }\r
+ LeaveCriticalSection(&_cs);\r
+\r
+ wait();\r
+}\r
+\r
+void HTTPDaemon::wait()\r
+{\r
+ bool done = false;\r
+ while (!done)\r
+ {\r
+ EnterCriticalSection(&_cs);\r
+ done = (_state == ST_IDLE);\r
+ LeaveCriticalSection(&_cs);\r
+ if (!done)\r
+ {\r
+ ::Sleep(100);\r
+ }\r
+ }\r
+}\r
+\r
+const char *HTTPDaemon::className()\r
+{\r
+ return "NET::HTTPDaemon";\r
+}\r
+\r
+} // NET\r
--- /dev/null
+//\r
+// HTTPDaemon.h\r
+//\r
+\r
+#pragma once\r
+\r
+#include <windows.h>\r
+#include <process.h>\r
+#include <stdlib.h>\r
+#include <winsock.h>\r
+\r
+#include "Raym/Raym.h"\r
+\r
+#include "net/HTTPRequest.h"\r
+#include "net/HTTPResponse.h"\r
+\r
+\r
+namespace NET\r
+{\r
+\r
+class HTTPDaemonDelegate\r
+{\r
+public:\r
+ virtual HTTPResponse *request(HTTPRequest *request, struct sockaddr_in *client) = 0;\r
+\r
+};\r
+\r
+class HTTPDaemon : public Raym::Object\r
+{\r
+private:\r
+ int _port;\r
+ int _backlog;\r
+ HTTPDaemonDelegate * _delegate;\r
+ Raym::String * _rootPath;\r
+ enum _state\r
+ {\r
+ ST_IDLE,\r
+ ST_READY,\r
+ ST_RUN,\r
+ ST_DONE\r
+ } _state;\r
+\r
+protected:\r
+ HTTPDaemon();\r
+ ~HTTPDaemon();\r
+\r
+public:\r
+ static HTTPDaemon *alloc();\r
+ HTTPDaemon *initWithPort(int port, int backlog);\r
+\r
+ void setDelegate(HTTPDaemonDelegate *delegate);\r
+ void setRootPath(Raym::String *path);\r
+ Raym::String *rootPath();\r
+ void run();\r
+ bool start();\r
+ void stop();\r
+ void wait();\r
+\r
+ HTTPResponse *responseWithReason(Raym::String *reason, int status, Raym::String *version);\r
+ HTTPResponse *responseWithPath(Raym::String *path, HTTPRequest *request);\r
+ static Raym::String *reasonForStatus(int status);\r
+\r
+ // for internal use\r
+ Raym::Array * _sockets;\r
+ void session(SOCKET sock, struct sockaddr_in *client);\r
+\r
+ virtual const char *className();\r
+};\r
+\r
+\r
+class HTTPDaemonSessionArgs\r
+{\r
+public:\r
+ HTTPDaemon * _daemon;\r
+ SOCKET _sock;\r
+ struct sockaddr_in _client;\r
+};\r
+\r
+} // NET\r
--- /dev/null
+//\r
+// HTTPRequest.cpp\r
+//\r
+\r
+#define DBG_LEVEL 0\r
+#include <Raym/Log.h>\r
+#include "net/HTTPRequest.h"\r
+\r
+using namespace Raym;\r
+\r
+namespace NET\r
+{\r
+\r
+const char *HTTPRequest::KEY_CGI = "CGI";\r
+const char *HTTPRequest::KEY_PARAMS = "PARAMS";\r
+\r
+HTTPRequest::HTTPRequest()\r
+{\r
+ _method = NULL;\r
+ _uri = NULL;\r
+ _version = NULL;\r
+ _message = NULL;\r
+}\r
+\r
+HTTPRequest::~HTTPRequest()\r
+{\r
+ RELEASE(_method);\r
+ RELEASE(_uri);\r
+ RELEASE(_version);\r
+ RELEASE(_message);\r
+}\r
+\r
+HTTPRequest *HTTPRequest::requestWithSocket(SOCKET sock)\r
+{\r
+ DebugLog2("%s\n", __FUNCTION__);\r
+\r
+ char buf[16384];\r
+ int offset = 0;\r
+ while (offset < sizeof(buf) - 1)\r
+ {\r
+ int len = recv(sock, &buf[offset], 1, 0);\r
+ if (len == 0)\r
+ {\r
+ break;\r
+ }\r
+ if (offset > 0)\r
+ {\r
+ if ((buf[offset - 1] == '\r') && (buf[offset] == '\n'))\r
+ {\r
+ ++offset;\r
+ break;\r
+ }\r
+ }\r
+ ++offset;\r
+ }\r
+ buf[offset] = '\0';\r
+\r
+ HTTPRequest *result = NULL;\r
+\r
+ String *method = NULL;\r
+ String *uri = NULL;\r
+ String *version = NULL;\r
+ if (strchr(buf, ' ') != NULL)\r
+ {\r
+ char *p = strchr(buf, ' ');\r
+ *p++ = '\0';\r
+ if ((buf[strlen(buf) - 2] == '\r') && (buf[strlen(buf) - 1] == '\n'))\r
+ {\r
+ buf[strlen(buf) - 2] = '\0';\r
+ }\r
+ method = String::alloc()->initWithUTF8String(&buf[0]);\r
+ while (*p == ' ')\r
+ {\r
+ ++p;\r
+ }\r
+ if (strchr(p, ' ') != NULL)\r
+ {\r
+ char *p2 = strchr(p, ' ');\r
+ *p2++ = '\0';\r
+ if ((p[strlen(p) - 2] == '\r') && (p[strlen(p) - 1] == '\n'))\r
+ {\r
+ p[strlen(p) - 2] = '\0';\r
+ }\r
+ uri = String::alloc()->initWithUTF8String(p);\r
+ while (*p2 == ' ')\r
+ {\r
+ ++p2;\r
+ }\r
+ if (strchr(p2, ' ') == NULL)\r
+ {\r
+ if ((p2[strlen(p2) - 2] == '\r') && (p2[strlen(p2) - 1] == '\n'))\r
+ {\r
+ p2[strlen(p2) - 2] = '\0';\r
+ }\r
+ version = String::alloc()->initWithUTF8String(p2);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (version != NULL)\r
+ {\r
+ if (version->isEqualToString(String::stringWithUTF8String("HTTP/1.0")) || version->isEqualToString(String::stringWithUTF8String("HTTP/1.1")))\r
+ {\r
+ InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->initWithSocket(sock);\r
+ if (header != NULL)\r
+ {\r
+ InternetTextMessageBody *body = NULL;\r
+ /*\r
+ if (header->fieldBodyForName("Transfer-Encoding") != NULL)\r
+ {\r
+ DebugLog3("has Transfer-Encoding\n");\r
+ abort();\r
+ }\r
+ else if (header->fieldBodyForName("Content-Length") != NULL)\r
+ {\r
+ DebugLog3("has Content-Length\n");\r
+ abort();\r
+ }\r
+ else if (header->fieldBodyForName("Content-Type") != NULL)\r
+ {\r
+ DebugLog3("has Content-Type\n");\r
+ abort();\r
+ }\r
+ */\r
+\r
+ InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);\r
+ RELEASE(header);\r
+ RELEASE(body);\r
+\r
+ result = new HTTPRequest();\r
+ result->setMethod(method);\r
+ result->setURI(uri);\r
+ result->setVersion(version);\r
+ result->setMessage(message);\r
+ result->autorelease();\r
+\r
+ RELEASE(message);\r
+ }\r
+ else\r
+ {\r
+ DebugLog3("error: InternetTextMessageHeader::headerWithSocket()\n");\r
+ }\r
+ }\r
+ }\r
+\r
+ RELEASE(method);\r
+ RELEASE(uri);\r
+ RELEASE(version);\r
+\r
+ return result;\r
+}\r
+\r
+void HTTPRequest::setMethod(String *method)\r
+{\r
+ SET_METHOD(_method, method);\r
+}\r
+\r
+String *HTTPRequest::method()\r
+{\r
+ return _method;\r
+}\r
+\r
+void HTTPRequest::setURI(String *uri)\r
+{\r
+ SET_METHOD(_uri, uri);\r
+}\r
+\r
+String *HTTPRequest::URI()\r
+{\r
+ return _uri;\r
+}\r
+\r
+void HTTPRequest::setVersion(String *version)\r
+{\r
+ SET_METHOD(_version, version);\r
+}\r
+\r
+String *HTTPRequest::version()\r
+{\r
+ return _version;\r
+}\r
+\r
+void HTTPRequest::setMessage(InternetTextMessage *message)\r
+{\r
+ SET_METHOD(_message, message);\r
+}\r
+\r
+InternetTextMessage *HTTPRequest::message()\r
+{\r
+ return _message;\r
+}\r
+\r
+Dictionary *HTTPRequest::parseAsCGI()\r
+{\r
+ DebugLog2("HTTPRequest::parseAsCGI()");\r
+\r
+ Dictionary *result = NULL;\r
+ if (_uri != NULL)\r
+ {\r
+ DebugLog3("_uri != NULL");\r
+ char *tmpstr = _strdup(_uri->cString());\r
+ if (tmpstr != NULL)\r
+ {\r
+ DebugLog3("tmpstr != NULL");\r
+ char *p1 = strchr(tmpstr, '?');\r
+ if (p1 != NULL)\r
+ {\r
+ DebugLog3("p1 != NULL");\r
+ *p1 = '\0';\r
+ DebugLog2("cgi: %s", tmpstr);\r
+ result = Dictionary::dictionaryWithCapacity(0);\r
+ result->setObject(String::stringWithUTF8String(tmpstr), KEY_CGI);\r
+\r
+ Array *params = Array::arrayWithCapacity(0);\r
+ result->setObject(params, KEY_PARAMS);\r
+\r
+ ++p1;\r
+ while (true)\r
+ {\r
+ char *p2 = strchr(p1, '&');\r
+ if (p2 != NULL)\r
+ {\r
+ *p2 = '\0';\r
+ }\r
+ char *p3 = strchr(p1, '=');\r
+ if (p3 != NULL)\r
+ {\r
+ *p3 = '\0';\r
+ String *para_name = String::stringWithUTF8String(p1);\r
+ ++p3;\r
+ String *para_val = String::stringWithUTF8String(p3);\r
+ DebugLog3("para_name: %s, para_val: %s", p1, p3);\r
+ Dictionary *para = Dictionary::dictionaryWithCapacity(0);\r
+ para->setObject(para_val, para_name);\r
+ params->addObject(para);\r
+ }\r
+\r
+ // 終端判定\r
+ if (p2 == NULL)\r
+ {\r
+ break;\r
+ }\r
+\r
+ // 次パラメータに設定\r
+ p1 = p2 + 1;\r
+ }\r
+ }\r
+\r
+ free(tmpstr);\r
+ }\r
+ }\r
+ return result;\r
+}\r
+\r
+const char *HTTPRequest::className()\r
+{\r
+ return "HTTPRequest";\r
+}\r
+\r
+} // NET\r
--- /dev/null
+//\r
+// HTTPRequest.h\r
+//\r
+\r
+#ifndef __NET_HTTPREQUEST_H__\r
+#define __NET_HTTPREQUEST_H__\r
+\r
+#include <Raym/Raym.h>\r
+\r
+#include "net/InternetTextMessage.h"\r
+\r
+namespace NET\r
+{\r
+\r
+class HTTPRequest : public Raym::Object\r
+{\r
+private:\r
+ Raym::String * _method;\r
+ Raym::String * _uri;\r
+ Raym::String * _version;\r
+ InternetTextMessage * _message;\r
+\r
+protected:\r
+ HTTPRequest();\r
+ ~HTTPRequest();\r
+\r
+public:\r
+ static HTTPRequest *requestWithSocket(SOCKET sock);\r
+\r
+ void setMethod(Raym::String *method);\r
+ Raym::String *method();\r
+ void setURI(Raym::String *uri);\r
+ Raym::String *URI();\r
+ void setVersion(Raym::String *version);\r
+ Raym::String *version();\r
+ void setMessage(InternetTextMessage *message);\r
+ InternetTextMessage *message();\r
+\r
+\r
+ // parse\r
+ static const char *KEY_CGI;\r
+ static const char *KEY_PARAMS;\r
+ Raym::Dictionary *parseAsCGI();\r
+\r
+ virtual const char *className();\r
+};\r
+\r
+} // NET\r
+\r
+#endif // __NET_HTTPREQUEST_H__\r
--- /dev/null
+//\r
+// HTTPResponse.cpp\r
+//\r
+\r
+#include "net/HTTPResponse.h"\r
+\r
+using namespace Raym;\r
+\r
+namespace NET\r
+{\r
+\r
+HTTPResponse::HTTPResponse()\r
+{\r
+ _version = NULL;\r
+ _status = 0;\r
+ _reason = NULL;\r
+ _message = NULL;\r
+}\r
+\r
+HTTPResponse::~HTTPResponse()\r
+{\r
+ RELEASE(_version);\r
+ RELEASE(_reason);\r
+ RELEASE(_message);\r
+}\r
+\r
+HTTPResponse *HTTPResponse::alloc()\r
+{\r
+#if 0\r
+ HTTPResponse *result;\r
+ result = new HTTPResponse();\r
+ result->init();\r
+ result->autorelease();\r
+ return result;\r
+#else\r
+ return new HTTPResponse();\r
+#endif\r
+}\r
+\r
+HTTPResponse *HTTPResponse::init()\r
+{\r
+ return this;\r
+}\r
+\r
+void HTTPResponse::setVersion(String *version)\r
+{\r
+ SET_METHOD(_version, version);\r
+}\r
+\r
+String *HTTPResponse::version()\r
+{\r
+ return _version;\r
+}\r
+\r
+void HTTPResponse::setStatus(int status)\r
+{\r
+ _status = status;\r
+}\r
+\r
+int HTTPResponse::status()\r
+{\r
+ return _status;\r
+}\r
+\r
+void HTTPResponse::setReason(String *reason)\r
+{\r
+ SET_METHOD(_reason, reason);\r
+}\r
+\r
+String *HTTPResponse::reason()\r
+{\r
+ return _reason;\r
+}\r
+\r
+void HTTPResponse::setMessage(InternetTextMessage *message)\r
+{\r
+ SET_METHOD(_message, message);\r
+}\r
+\r
+InternetTextMessage *HTTPResponse::message()\r
+{\r
+ return _message;\r
+}\r
+\r
+const char *HTTPResponse::className()\r
+{\r
+ return "HTTPResponse";\r
+}\r
+\r
+} // NET\r
--- /dev/null
+//\r
+// HTTPResponse.h\r
+//\r
+\r
+#pragma once\r
+\r
+#include <Raym/Raym.h>\r
+\r
+#include "net/InternetTextMessage.h"\r
+\r
+namespace NET\r
+{\r
+\r
+enum HTTP_STATUS\r
+{\r
+ // Informational 1xx\r
+ HTTP_STATUS_CONTINUE = 100,\r
+ HTTP_STATUS_SWITCHING_PROTOCOLS = 101,\r
+ // Successful 2xx\r
+ HTTP_STATUS_OK = 200,\r
+ HTTP_STATUS_CREATED = 201,\r
+ HTTP_STATUS_ACCEPTED = 202,\r
+ HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,\r
+ HTTP_STATUS_NO_CONTENT = 204,\r
+ HTTP_STATUS_RESET_CONTENT = 205,\r
+ HTTP_STATUS_PARTIAL_CONTENT = 206,\r
+ // Redirection 3xx\r
+ HTTP_STATUS_MULTIPLE_CHOICES = 300,\r
+ HTTP_STATUS_MOVED_PERMANENTLY = 301,\r
+ HTTP_STATUS_FOUND = 302,\r
+ HTTP_STATUS_SEE_OTHER = 303,\r
+ HTTP_STATUS_NOT_MODIFIED = 304,\r
+ HTTP_STATUS_USE_PROXY = 305,\r
+ HTTP_STATUS_UNUSED = 306,\r
+ HTTP_STATUS_TEMPORARY_REDIRECT = 307,\r
+ // Client Error 4xx\r
+ HTTP_STATUS_BAD_REQUEST = 400,\r
+ HTTP_STATUS_UNAUTHORIZED = 401,\r
+ HTTP_STATUS_PAYMENT_REQUIRED = 402,\r
+ HTTP_STATUS_FORBIDDEN = 403,\r
+ HTTP_STATUS_NOT_FOUND = 404,\r
+ HTTP_STATUS_METHOD_NOT_ALLOWED = 405,\r
+ HTTP_STATUS_NOT_ACCEPTABLE = 406,\r
+ HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,\r
+ HTTP_STATUS_REQUEST_TIMEOUT = 408,\r
+ HTTP_STATUS_CONFLICT = 409,\r
+ HTTP_STATUS_GONE = 410,\r
+ HTTP_STATUS_LENGTH_REQUIRED = 411,\r
+ HTTP_STATUS_PRECONDITION_FAILED = 412,\r
+ HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413,\r
+ HTTP_STATUS_REQUEST_URI_TOO_LONG = 414,\r
+ HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,\r
+ HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE = 416,\r
+ HTTP_STATUS_EXPECTATION_FAILED = 417,\r
+ // Server Error 5xx\r
+ HTTP_STATUS_INTERNAL_SERVER_ERROR = 500,\r
+ HTTP_STATUS_NOT_IMPLEMENTED = 501,\r
+ HTTP_STATUS_BAD_GATEWAY = 502,\r
+ HTTP_STATUS_SERVICE_UNAVAILABLE = 503,\r
+ HTTP_STATUS_GATEWAY_TIMEOUT = 504,\r
+ HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505\r
+};\r
+\r
+class HTTPResponse : public Raym::Object\r
+{\r
+private:\r
+ Raym::String * _version;\r
+ int _status;\r
+ Raym::String * _reason;\r
+ InternetTextMessage * _message;\r
+\r
+protected:\r
+ HTTPResponse();\r
+ ~HTTPResponse();\r
+\r
+public:\r
+ static HTTPResponse *alloc();\r
+ HTTPResponse *init();\r
+\r
+ void setVersion(Raym::String *version);\r
+ Raym::String *version();\r
+ void setStatus(int status);\r
+ int status();\r
+ void setReason(Raym::String *reason);\r
+ Raym::String *reason();\r
+ void setMessage(InternetTextMessage *message);\r
+ InternetTextMessage *message();\r
+\r
+ virtual const char *className();\r
+};\r
+\r
+} // NET\r
+\r
--- /dev/null
+//\r
+// InternetTextMessage.cpp\r
+//\r
+\r
+#include "net/InternetTextMessage.h"\r
+\r
+using namespace Raym;\r
+\r
+namespace NET\r
+{\r
+\r
+InternetTextMessage::InternetTextMessage()\r
+{\r
+ _header = NULL;\r
+ _body = NULL;\r
+}\r
+\r
+InternetTextMessage::~InternetTextMessage()\r
+{\r
+ if (_body != NULL)\r
+ {\r
+ _body->release();\r
+ _body = NULL;\r
+ }\r
+ if (_header != NULL)\r
+ {\r
+ _header->release();\r
+ _header = NULL;\r
+ }\r
+}\r
+\r
+InternetTextMessage *InternetTextMessage::alloc()\r
+{\r
+ return new InternetTextMessage();\r
+}\r
+\r
+InternetTextMessage *InternetTextMessage::initWithContentsOfFile(const char *path)\r
+{\r
+ /*\r
+ NSFileManager *fm = [NSFileManager defaultManager];\r
+ return [self initWithData:[fm contentsAtPath:path]];\r
+ */\r
+ release();\r
+ return NULL;\r
+}\r
+\r
+InternetTextMessage *InternetTextMessage::initWithData(Data *data)\r
+{\r
+ /*\r
+ if ((self = [super init]) != nil)\r
+ {\r
+ _header = nil;\r
+ _body = nil;\r
+\r
+ char *tmp = "\r\n\r\n";\r
+ Data *crlfcrlf = [Data dataWithBytes:tmp length:4];\r
+ NSRange r = {0, [data length]};\r
+ r = [data rangeOfData:crlfcrlf options:0 range:r];\r
+ if (r.location != NSNotFound)\r
+ {\r
+ NSRange rh = {0, r.location + 4};\r
+ Data *dh = [data subdataWithRange:rh];\r
+ _header = [[InternetTextMessageHeader alloc] initWithData:dh];\r
+ NSRange rb = {r.location + 4, ([data length] - (r.location + 4))};\r
+ Data *db = [data subdataWithRange:rb];\r
+ _body = [[InternetTextMessageBody alloc] initWithData:db];\r
+ }\r
+ else\r
+ {\r
+ [self release];\r
+ self = nil;\r
+ }\r
+ }\r
+ */\r
+ release();\r
+ return NULL;\r
+}\r
+\r
+InternetTextMessage *InternetTextMessage::initWithHeaderAndBody(InternetTextMessageHeader *header, InternetTextMessageBody *body)\r
+{\r
+ if (header != NULL)\r
+ {\r
+ _header = header->retain();\r
+ if (body != NULL)\r
+ {\r
+ _body = body->retain();\r
+ }\r
+ return this;\r
+ }\r
+\r
+ release();\r
+ return NULL;\r
+}\r
+\r
+InternetTextMessage *InternetTextMessage::retain()\r
+{\r
+ Object::retain();\r
+ return this;\r
+}\r
+\r
+InternetTextMessage *InternetTextMessage::autorelease()\r
+{\r
+ Object::autorelease();\r
+ return this;\r
+}\r
+\r
+InternetTextMessageHeader *InternetTextMessage::header()\r
+{\r
+ return _header;\r
+}\r
+\r
+InternetTextMessageBody *InternetTextMessage::body()\r
+{\r
+ return _body;\r
+}\r
+\r
+Data *InternetTextMessage::data()\r
+{\r
+ /*\r
+ NSMutableData *result = [NSMutableData dataWithData:[_header data]];\r
+ if ([_body data])\r
+ {\r
+ [result appendData:[_body data]];\r
+ }\r
+ else\r
+ {\r
+ [result appendData:[[_body body] dataUsingEncoding:[_header encoding]]];\r
+ }\r
+ */\r
+ return NULL;\r
+}\r
+\r
+const char *InternetTextMessage::className()\r
+{\r
+ return "NET::InternetTextMessage";\r
+}\r
+\r
+} // NET\r
--- /dev/null
+//\r
+// InternetTextMessage.h\r
+//\r
+\r
+#pragma once\r
+\r
+#include "net/InternetTextMessageHeader.h"\r
+#include "net/InternetTextMessageBody.h"\r
+\r
+namespace NET\r
+{\r
+\r
+class InternetTextMessage : public Raym::Object\r
+{\r
+private:\r
+ InternetTextMessageHeader * _header;\r
+ InternetTextMessageBody * _body;\r
+\r
+protected:\r
+ InternetTextMessage();\r
+ ~InternetTextMessage();\r
+\r
+public:\r
+ static InternetTextMessage *alloc();\r
+ InternetTextMessage *initWithContentsOfFile(const char *path);\r
+ InternetTextMessage *initWithData(Raym::Data *data);\r
+ InternetTextMessage *initWithHeaderAndBody(InternetTextMessageHeader *header, InternetTextMessageBody *body);\r
+ InternetTextMessage *retain();\r
+ InternetTextMessage *autorelease();\r
+\r
+ InternetTextMessageHeader *header();\r
+ InternetTextMessageBody *body();\r
+\r
+ Raym::Data *data();\r
+\r
+ virtual const char *className();\r
+};\r
+\r
+} // NET\r
+\r
--- /dev/null
+//\r
+// InternetTextMessageBody.cpp\r
+//\r
+\r
+#include <stdlib.h>\r
+\r
+#include "net/InternetTextMessageBody.h"\r
+\r
+using namespace Raym;\r
+\r
+namespace NET\r
+{\r
+\r
+InternetTextMessageBody::InternetTextMessageBody()\r
+{\r
+ _body = NULL;\r
+ _data = NULL;\r
+}\r
+\r
+InternetTextMessageBody::~InternetTextMessageBody()\r
+{\r
+ RELEASE(_body);\r
+ RELEASE(_data);\r
+}\r
+\r
+InternetTextMessageBody *InternetTextMessageBody::alloc()\r
+{\r
+ return new InternetTextMessageBody();\r
+}\r
+\r
+InternetTextMessageBody *InternetTextMessageBody::initWithString(String *string)\r
+{\r
+ if (string != NULL)\r
+ {\r
+ _body = string->retain();\r
+ return this;\r
+ }\r
+\r
+ release();\r
+ return NULL;\r
+}\r
+\r
+InternetTextMessageBody *InternetTextMessageBody::initWithData(Data *data)\r
+{\r
+\r
+ if (data != NULL)\r
+ {\r
+ _data = data->retain();\r
+ return this;\r
+ }\r
+\r
+ release();\r
+ return NULL;\r
+}\r
+\r
+InternetTextMessageBody *InternetTextMessageBody::retain()\r
+{\r
+ Object::retain();\r
+ return this;\r
+}\r
+\r
+InternetTextMessageBody *InternetTextMessageBody::autorelease()\r
+{\r
+ Object::autorelease();\r
+ return this;\r
+}\r
+\r
+String *InternetTextMessageBody::body()\r
+{\r
+ return _body;\r
+}\r
+\r
+Data *InternetTextMessageBody::data()\r
+{\r
+ return _data;\r
+}\r
+\r
+const char *InternetTextMessageBody::className()\r
+{\r
+ return "NET::InternetTextMessageBody";\r
+}\r
+\r
+} // NET\r
--- /dev/null
+//\r
+// InternetTextMessageBody.h\r
+//\r
+\r
+#pragma once\r
+\r
+#include <Raym/Raym.h>\r
+\r
+namespace NET\r
+{\r
+\r
+class InternetTextMessageBody : public Raym::Object\r
+{\r
+private:\r
+ Raym::String * _body;\r
+ Raym::Data * _data;\r
+\r
+protected:\r
+ InternetTextMessageBody();\r
+ ~InternetTextMessageBody();\r
+\r
+public:\r
+ static InternetTextMessageBody *alloc();\r
+ InternetTextMessageBody *initWithString(Raym::String *string);\r
+ InternetTextMessageBody *initWithData(Raym::Data *data);\r
+ InternetTextMessageBody *retain();\r
+ InternetTextMessageBody *autorelease();\r
+\r
+ Raym::String *body();\r
+ Raym::Data *data();\r
+\r
+ virtual const char *className();\r
+};\r
+\r
+} // NET\r
+\r
--- /dev/null
+//\r
+// InternetTextMessageHeader.h\r
+//\r
+\r
+#include <Raym/Log.h>\r
+#include "net/InternetTextMessageHeader.h"\r
+\r
+using namespace Raym;\r
+\r
+namespace NET\r
+{\r
+\r
+InternetTextMessageHeader::InternetTextMessageHeader()\r
+{\r
+ _encoding = ASCIIStringEncoding;\r
+ _fields = NULL;\r
+ _data = NULL;\r
+}\r
+\r
+InternetTextMessageHeader::~InternetTextMessageHeader()\r
+{\r
+ RELEASE(_fields);\r
+ RELEASE(_data);\r
+}\r
+\r
+InternetTextMessageHeader *InternetTextMessageHeader::alloc()\r
+{\r
+ return new InternetTextMessageHeader();\r
+}\r
+\r
+InternetTextMessageHeader *InternetTextMessageHeader::init()\r
+{\r
+ RELEASE(_fields);\r
+ RELEASE(_data);\r
+ _fields = Dictionary::alloc()->initWithCapacity(0);\r
+ return this;\r
+}\r
+\r
+InternetTextMessageHeader *InternetTextMessageHeader::initWithData(Data *data)\r
+{\r
+ DebugLog2("%s()\n", __FUNCTION__);\r
+\r
+ init();\r
+\r
+ if (data != NULL)\r
+ {\r
+ _data = data->retain();\r
+\r
+ char field[512];\r
+ const char *buffer = (const char *)data->bytes();\r
+\r
+ int index = 0;\r
+ uint offset = 0;\r
+ while (offset < data->length())\r
+ {\r
+ field[index++] = buffer[offset++];\r
+ if ((field[index - 2] == '\r') && (field[index - 1] == '\n'))\r
+ {\r
+ field[index - 2] = '\0';\r
+ char *value = strchr(field, ':');\r
+ if (value != NULL)\r
+ {\r
+ *value++ = '\0';\r
+ while (*value == ' ')\r
+ {\r
+ ++value;\r
+ }\r
+\r
+ String *body = String::stringWithUTF8String(value);\r
+ String *name = String::stringWithUTF8String(field);\r
+ setFieldBodyWithName(body, name);\r
+ }\r
+\r
+ index = 0;\r
+ }\r
+ }\r
+ }\r
+ return this;\r
+/*\r
+ char *tmp = (char *)malloc([data length] + 1);\r
+ [data getBytes:tmp length:[data length]];\r
+ tmp[[data length]] = '\0';\r
+ String *headStr = [String stringWithCString:tmp encoding:_encoding];\r
+ if ([headStr rangeOfString:@"content-type" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ if ([headStr rangeOfString:@"charset" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ if ([headStr rangeOfString:@"iso-2022-jp" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ _encoding = ISO2022JPStringEncoding;\r
+ }\r
+ else if ([headStr rangeOfString:@"shift_jis" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ _encoding = ShiftJISStringEncoding;\r
+ }\r
+ else if ([headStr rangeOfString:@"euc-jp" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ _encoding = JapaneseEUCStringEncoding;\r
+ }\r
+ else if ([headStr rangeOfString:@"utf-8" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ _encoding = UTF8StringEncoding;\r
+ }\r
+ }\r
+ }\r
+*/\r
+}\r
+\r
+InternetTextMessageHeader *InternetTextMessageHeader::initWithArray(Array *array)\r
+{\r
+ /*\r
+ if ((self = [super init]) != nil)\r
+ {\r
+ _dictionary = [[MutableDictionary alloc] initWithCapacity:0];\r
+ _encoding = ASCIIStringEncoding;\r
+ for (int i = 0; i < [array count]; ++i)\r
+ {\r
+ String *line = [array objectAtIndex:i];\r
+ Range r = [line rangeOfString:@":"];\r
+ if (r.location != NotFound)\r
+ {\r
+ String *fieldName = [line substringToIndex:r.location];\r
+ String *fieldBody = [[line substringFromIndex:(r.location + 1)] stringByTrimmingCharactersInSet:[CharacterSet whitespaceAndNewlineCharacterSet]];\r
+ [_dictionary setObject:fieldBody forKey:fieldName];\r
+ }\r
+ }\r
+ }\r
+ return self;\r
+ */\r
+ return this;\r
+}\r
+\r
+InternetTextMessageHeader *InternetTextMessageHeader::initWithSocket(SOCKET sock)\r
+{\r
+ DebugLog2("%s()\n", __FUNCTION__);\r
+\r
+ char *tmp = "\r\n\r\n";\r
+\r
+ int length = 0;\r
+ char buf[16384];\r
+\r
+ while (length < sizeof(buf))\r
+ {\r
+ char c;\r
+ if (recv(sock, &c, 1, 0) == 1)\r
+ {\r
+ buf[length++] = c;\r
+ if (length >= 4)\r
+ {\r
+ if (strncmp(&buf[length - 4], tmp, 4) == 0)\r
+ {\r
+ Data *data = Data::alloc()->initWithBytesAndLength(buf, length);\r
+ initWithData(data);\r
+ data->release();\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // EOF or error\r
+ break;\r
+ }\r
+ }\r
+ return this;\r
+}\r
+\r
+/*\r
+- (StringEncoding)encoding\r
+{\r
+ return _encoding;\r
+}\r
+*/\r
+\r
+InternetTextMessageHeader *InternetTextMessageHeader::retain()\r
+{\r
+ Object::retain();\r
+ return this;\r
+}\r
+\r
+InternetTextMessageHeader *InternetTextMessageHeader::autorelease()\r
+{\r
+ Object::autorelease();\r
+ return this;\r
+}\r
+\r
+Array *InternetTextMessageHeader::fieldNames()\r
+{\r
+ return _fields->allKeys();\r
+}\r
+\r
+String *InternetTextMessageHeader::fieldBodyForName(String *name)\r
+{\r
+ return (String *)_fields->objectForKey(name);\r
+}\r
+\r
+String *InternetTextMessageHeader::fieldBodyForName(const char *name)\r
+{\r
+ return (String *)_fields->objectForKey(name);\r
+}\r
+\r
+void InternetTextMessageHeader::setFieldBodyWithName(String *body, String *name)\r
+{\r
+ _fields->setObject(body, name);\r
+ /*\r
+ if ([[name lowercaseString] isEqualToString:@"content-type"])\r
+ {\r
+ if ([body rangeOfString:@"charset" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ if ([body rangeOfString:@"iso-2022-jp" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ _encoding = ISO2022JPStringEncoding;\r
+ }\r
+ else if ([body rangeOfString:@"shift_jis" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ _encoding = ShiftJISStringEncoding;\r
+ }\r
+ else if ([body rangeOfString:@"euc-jp" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ _encoding = JapaneseEUCStringEncoding;\r
+ }\r
+ else if ([body rangeOfString:@"utf-8" options:CaseInsensitiveSearch].location != NotFound)\r
+ {\r
+ _encoding = UTF8StringEncoding;\r
+ }\r
+ }\r
+ }\r
+ */\r
+}\r
+\r
+void InternetTextMessageHeader::setFieldBodyWithName(const char *body, String *name)\r
+{\r
+ setFieldBodyWithName(String::stringWithUTF8String(body), name);\r
+}\r
+\r
+void InternetTextMessageHeader::setFieldBodyWithName(String *body, const char *name)\r
+{\r
+ setFieldBodyWithName(body, String::stringWithUTF8String(name));\r
+}\r
+\r
+void InternetTextMessageHeader::setFieldBodyWithName(const char *body, const char *name)\r
+{\r
+ setFieldBodyWithName(String::stringWithUTF8String(body), String::stringWithUTF8String(name));\r
+}\r
+\r
+Data *InternetTextMessageHeader::data()\r
+{\r
+ /*\r
+ MutableString *headerString = [MutableString stringWithCapacity:0];\r
+ Array *fieldNames = [_dictionary allKeys];\r
+\r
+ // Content-type\r
+ for (int i = 0; i < [fieldNames count]; ++i)\r
+ {\r
+ String *fieldName = [fieldNames objectAtIndex:i];\r
+ if ([[fieldName lowercaseString] isEqualToString:@"content-type"])\r
+ {\r
+ [headerString appendFormat:@"Content-type: %@\r\n", [_dictionary objectForKey:fieldName]];\r
+ break;\r
+ }\r
+ }\r
+\r
+ // other\r
+ for (int i = 0; i < [fieldNames count]; ++i)\r
+ {\r
+ String *fieldName = [fieldNames objectAtIndex:i];\r
+ String *lowercase = [fieldName lowercaseString];\r
+ if (![lowercase isEqualToString:@"content-type"])\r
+ {\r
+ [headerString appendFormat:@"%@: %@\r\n", fieldName, [_dictionary objectForKey:fieldName]];\r
+ }\r
+ }\r
+\r
+ [headerString appendString:@"\r\n\r\n"];\r
+\r
+ return [Data dataWithBytes:[headerString cStringUsingEncoding:_encoding] length:[headerString lengthOfBytesUsingEncoding:_encoding]];\r
+ */\r
+ return NULL;\r
+}\r
+\r
+const char *InternetTextMessageHeader::className()\r
+{\r
+ return "NET::InternetTextMessageHeader";\r
+}\r
+\r
+} // NET\r
--- /dev/null
+//\r
+// InternetTextMessageHeader.h\r
+//\r
+\r
+#pragma once\r
+\r
+#include <stdio.h>\r
+\r
+#include <Raym/Raym.h>\r
+\r
+namespace NET\r
+{\r
+\r
+class InternetTextMessageHeader : public Raym::Object\r
+{\r
+private:\r
+ Raym::StringEncoding _encoding;\r
+ Raym::Dictionary * _fields;\r
+ Raym::Data * _data;\r
+\r
+protected:\r
+ InternetTextMessageHeader();\r
+ ~InternetTextMessageHeader();\r
+\r
+public:\r
+ static InternetTextMessageHeader *alloc();\r
+ InternetTextMessageHeader *init();\r
+ InternetTextMessageHeader *initWithData(Raym::Data *data);\r
+ InternetTextMessageHeader *initWithArray(Raym::Array *array);\r
+ InternetTextMessageHeader *initWithSocket(SOCKET sock);\r
+ InternetTextMessageHeader *retain();\r
+ InternetTextMessageHeader *autorelease();\r
+\r
+ Raym::StringEncoding encoding();\r
+\r
+ Raym::Array *fieldNames();\r
+ Raym::String *fieldBodyForName(Raym::String *name);\r
+ Raym::String *fieldBodyForName(const char *name);\r
+\r
+ void setFieldBodyWithName(Raym::String *body, Raym::String *name);\r
+ void setFieldBodyWithName(const char *body, Raym::String *name);\r
+ void setFieldBodyWithName(Raym::String *body, const char *name);\r
+ void setFieldBodyWithName(const char *body, const char *name);\r
+\r
+ Raym::Data *data();\r
+\r
+ virtual const char *className();\r
+};\r
+\r
+} // NET\r
+\r
--- /dev/null
+/**\r
+ * @file HTTPDaemon.cpp\r
+ *\r
+ */\r
+\r
+#include <time.h>\r
+\r
+#define DBG_LEVEL 3\r
+#include "Raym/Log.h"\r
+\r
+#include "keys.h"\r
+#include "ry0/iPTd/HTTPD.h"\r
+#include "ry0/iPTd/Controller.h"\r
+\r
+using namespace Raym;\r
+\r
+namespace ry0\r
+{\r
+namespace iPTd\r
+{\r
+\r
+HTTPDaemon::HTTPDaemon()\r
+{\r
+ _controller = NULL;\r
+ _httpd = NULL;\r
+ _port = -1;\r
+ _path = NULL;\r
+}\r
+\r
+HTTPDaemon::~HTTPDaemon()\r
+{\r
+ RELEASE(_httpd);\r
+ RELEASE(_path);\r
+\r
+ _controller = NULL;\r
+}\r
+\r
+HTTPDaemon *HTTPDaemon::alloc()\r
+{\r
+ return new HTTPDaemon();\r
+}\r
+\r
+HTTPDaemon *HTTPDaemon::initWithController(Controller *controller, int port, String *path)\r
+{\r
+ _controller = controller;\r
+ _port = port;\r
+ _path = path->retain();\r
+\r
+ return this;\r
+}\r
+\r
+bool HTTPDaemon::start()\r
+{\r
+ if (_httpd == NULL)\r
+ {\r
+ _httpd = NET::HTTPDaemon::alloc()->initWithPort(_port, 10);\r
+ _httpd->setRootPath(_path);\r
+ _httpd->setDelegate(this);\r
+ }\r
+ return _httpd->start();\r
+}\r
+\r
+void HTTPDaemon::stop()\r
+{\r
+ _httpd->stop();\r
+}\r
+\r
+NET::HTTPResponse *HTTPDaemon::request(NET::HTTPRequest *request, struct sockaddr_in *client)\r
+{\r
+ DebugLog2("%s\n", __FUNCTION__);\r
+\r
+ // 初期化チェック\r
+ bool flag = false;\r
+ EnterCriticalSection(&_cs);\r
+// flag = _initialized;\r
+ LeaveCriticalSection(&_cs);\r
+ if (!flag)\r
+ {\r
+// return NULL;\r
+ }\r
+\r
+ NET::HTTPResponse *response = NULL;\r
+\r
+ if (request->method()->isEqualToString("GET") ||\r
+ request->method()->isEqualToString("HEAD"))\r
+ {\r
+ // URI\r
+ String *uri = request->URI();\r
+ DebugLog0("request: %s\n", uri->cString());\r
+ }\r
+\r
+\r
+ return response;\r
+}\r
+\r
+} // iPTd\r
+} // ry0\r
--- /dev/null
+/**\r
+ * @file HTTPDaemon.h\r
+ *\r
+ */\r
+\r
+#pragma once\r
+\r
+#include "Raym/Raym.h"\r
+#include "net/HTTPDaemon.h"\r
+\r
+namespace ry0\r
+{\r
+namespace iPTd\r
+{\r
+\r
+class Controller;\r
+\r
+class HTTPDaemon : public Raym::Object,\r
+ public NET::HTTPDaemonDelegate\r
+{\r
+private:\r
+ Controller * _controller;\r
+ NET::HTTPDaemon * _httpd;\r
+ int _port;\r
+ Raym::String * _path;\r
+\r
+protected:\r
+ HTTPDaemon();\r
+ ~HTTPDaemon();\r
+\r
+public:\r
+ static HTTPDaemon *alloc();\r
+ HTTPDaemon *initWithController(Controller *controller, int port, Raym::String *path);\r
+\r
+ bool start();\r
+ void stop();\r
+\r
+ NET::HTTPResponse *request(NET::HTTPRequest *request, struct sockaddr_in *client);\r
+};\r
+\r
+\r
+} // iPTd\r
+} // ry0\r