// // AjaxIME HTTP Server // // Copyright(C) 2005-2007 Taku Kudo // #include #include #include #include #include "httpd.h" namespace tiny_http_server { static const char *kLogFile = "ime.log"; static const int kPort = 10522; static const int kPreForkNum = 4; static const int kTimeout = 7; static const size_t kNumCand = 500; class AjaxIMEHTTPWorker: public HTTPWorker { private: MeCab::Tagger *ime_tagger_; MeCab::Tagger *katakana_tagger_; MeCab::Tagger *alpha_tagger_; void handle_request() { std::string action = cgi_param("action"); if (action == "conv") { std::string query = cgi_param("query"); std::string to = cgi_param("to"); std::string func = cgi_param("func"); if (func.empty()) func = "ImeRequestCallback"; size_t maxsize = 0; MeCab::Tagger *tagger = ime_tagger_; if (to == "alpha") { tagger = alpha_tagger_; maxsize = 10; } else if (to == "katakana") { tagger = katakana_tagger_; maxsize = 2; } else { tagger = ime_tagger_; maxsize = 10; } if (!tagger) return bad_request(); tagger->parseNBestInit(query.c_str()); std::set candhash; std::vector cand; for (size_t n = 0; n < kNumCand; ++n) { const char *result = tagger->next(); if (!result) break; if (candhash.find(result) == candhash.end()) { cand.push_back(result); candhash.insert(result); if (cand.size() == maxsize) break; } } output_body() << func << "(["; for (size_t i = 0; i < cand.size(); ++i) { if (i != 0) output_body() << ','; output_body() << '\''; std::string &str = cand[i]; for (size_t k = 0; k < str.size(); ++k) { if (str[k] == '\'') output_body() << '\\'; output_body() << str[k]; } output_body() << '\''; } output_body() << "]);\n"; output_header() << "Content-Language: ja\r\n"; output_header() << "Content-Type: text/javascript; charset=\"UTF-8\";\r\n"; send_request("200 OK"); } else if (action == "log") { output_header() << "Content-Type: text/plain\r\n"; send_request("200 OK"); time_t t = time(0); char *date_local = ctime(&t); date_local[strlen(date_local)-1] = '\0'; std::string addr = input_header("X-Forwarded-For:"); if (addr.empty()) addr = client_address(); std::ofstream ofs(kLogFile, std::ios::app); ofs << addr << " " << "[" << date_local << "] " << cgi_param("query") << '\t' << cgi_param("result") << '\t' << cgi_param("sel") << '\t' << cgi_param("id") << '\t' << input_header("Referer:") << std::endl; ofs.close(); } else { bad_request(); } return; } const char *server_name() const { return "AjaxIMEServer/1.1"; } public: AjaxIMEHTTPWorker(): ime_tagger_(0), katakana_tagger_(0), alpha_tagger_(0) { static const char *ime_arg = "-l1 -d./dic/imedic"; static const char *katakana_arg = "-l1 -d./dic/katakana"; static const char *alpha_arg = "-l1 -d./dic/alpha"; ime_tagger_ = MeCab::createTagger(ime_arg); if (!ime_tagger_) { std::cerr << MeCab::getTaggerError() << std::endl; std::exit(-1); } katakana_tagger_ = MeCab::createTagger(katakana_arg); if (!katakana_tagger_) { std::cerr << MeCab::getTaggerError() << std::endl; std::exit(-1); } alpha_tagger_ = MeCab::createTagger(alpha_arg); if (!alpha_tagger_) { std::cerr << MeCab::getTaggerError() << std::endl; std::exit(-1); } } virtual ~AjaxIMEHTTPWorker() { delete ime_tagger_; delete katakana_tagger_; delete alpha_tagger_; } }; } #define OPT " -p port -t prefork_num [-h]" int main(int argc, char **argv) { extern char *optarg; unsigned short port = tiny_http_server::kPort; size_t prefork_num = tiny_http_server::kPreForkNum; std::string dir; int opt; while ((opt = getopt(argc, argv, "t:p:hc:")) != -1) { switch (opt) { case 't': prefork_num = atoi(optarg); break; case 'p': port = atoi(optarg); break; case 'c': dir = std::string(optarg); break; case 'h': default: std::cout << "Usage: " << argv[0] << OPT << std::endl; return -1; } } if (!dir.empty()) chdir(dir.c_str()); tiny_http_server::HTTPWorkerCreatorTempl creator; tiny_http_server::PreForkHTPPServer server(&creator); // main loop return server.run(port, prefork_num); }