00001 #include <cstdio>
00002 #include <fstream>
00003 #include <boost/date_time/posix_time/posix_time.hpp>
00004 #include <boost/algorithm/string.hpp>
00005
00006 #include <fcgiapp.h>
00007
00008 #include <megatree/metadata.h>
00009 #include <megatree/tree_common.h>
00010 #include <megatree/node_file.h>
00011 #include <megatree/storage.h>
00012 #include <megatree/storage_factory.h>
00013
00014 typedef std::map<std::string, boost::shared_ptr<megatree::Storage> > StorageMap;
00015 StorageMap g_storage_map;
00016
00017
00018 void emitPong(FCGX_Stream *out)
00019 {
00020 FCGX_FPrintF(out,
00021 "Content-Type: text/html\r\n"
00022 "\r\n"
00023 "files pong");
00024 }
00025
00026 void emitTrees(FCGX_Stream *out, const std::vector<std::string>& trees)
00027 {
00028 std::string tree_string;
00029 for (unsigned i=0; i<trees.size(); i++){
00030 tree_string += trees[i];
00031 if (i < trees.size()-1)
00032 tree_string += ",";
00033 }
00034 FCGX_FPrintF(out,
00035 "Content-Type: text/html\r\n"
00036 "\r\n"
00037 "%s", tree_string.c_str());
00038 }
00039
00040
00041 #define NL "<br />\n"
00042
00043 #define DUMP_VAR(x) FCGX_FPrintF(out, "<tr><td>%s</td><td>%s</td></tr>\n", \
00044 #x, FCGX_GetParam(#x, envp) ? FCGX_GetParam(#x, envp) : "<null>")
00045 void emitDump(FCGX_Stream *out, char **envp)
00046 {
00047 FCGX_FPrintF(out, "Content-Type: text/html\r\n");
00048 FCGX_FPrintF(out, "\r\n");
00049 FCGX_FPrintF(out, "<html>\n");
00050 FCGX_FPrintF(out, "<head><title>Dump</title></head>");
00051 FCGX_FPrintF(out, "<body>");
00052 FCGX_FPrintF(out, "<h1>Dump</h1>\n");
00053
00054 FCGX_FPrintF(out, "<table>\n");
00055 FCGX_FPrintF(out, "<tr><td>Compiled</td><td>%s %s</td></tr>\n", __DATE__, __TIME__);
00056 FCGX_FPrintF(out, "<tr><td>Pid</td><td>%d</td></tr>\n", getpid());
00057
00058 FCGX_FPrintF(out, "<tr><td></td><td></td></tr>\n");
00059 FCGX_FPrintF(out, "<tr><td><b>Env</b></td><td></td></tr>\n");
00060 DUMP_VAR(DOCUMENT_ROOT);
00061 DUMP_VAR(CONTENT_LENGTH);
00062 DUMP_VAR(HTTP_REFERER);
00063 DUMP_VAR(HTTP_USER_AGENT);
00064 DUMP_VAR(PATH_INFO);
00065 DUMP_VAR(PATH_TRANSLATED);
00066 DUMP_VAR(QUERY_STRING);
00067 DUMP_VAR(REMOTE_ADDR);
00068 DUMP_VAR(REMOTE_HOST);
00069 DUMP_VAR(REQUEST_METHOD);
00070 DUMP_VAR(SCRIPT_NAME);
00071 DUMP_VAR(SERVER_NAME);
00072 DUMP_VAR(HTTP_COOKIE);
00073 DUMP_VAR(HTTP_HOST);
00074
00075 FCGX_FPrintF(out, "</table>\n");
00076 FCGX_FPrintF(out, "</body></html>\n");
00077 }
00078
00079 void emitBox(FCGX_Stream *out)
00080 {
00081 FCGX_FPrintF(out, "Content-Type: application/octet-stream\r\n");
00082 FCGX_FPrintF(out, "\r\n");
00083
00084
00085 uint8_t coords[] = {
00086 0,
00087 64, 64, 64, 255, 0, 0,
00088 192, 64, 64, 255, 255, 255,
00089 64, 192, 64, 255, 255, 255,
00090 192, 192, 64, 255, 255, 255,
00091 64, 64, 192, 255, 255, 255,
00092 192, 64, 192, 255, 255, 255,
00093 64, 192, 192, 255, 255, 255,
00094 192, 192, 192, 255, 255, 255
00095 };
00096
00097 FCGX_PutStr((char*)coords, 1 + 8 * 6 * sizeof(uint8_t), out);
00098 }
00099
00100
00101 void sendResult(boost::shared_ptr<FCGX_Request> req, const std::string &filename, const megatree::ByteVec& file_data)
00102 {
00103 if (file_data.empty()) {
00104 FCGX_FPrintF(req->out, "Status: 404 Not Found\r\n");
00105 FCGX_FPrintF(req->out, "Content-Type: text/html\r\n");
00106 FCGX_FPrintF(req->out, "\r\n");
00107 FCGX_FPrintF(req->out, "File not found: %s<br />\n", filename.c_str());
00108 }
00109 else{
00110 FCGX_FPrintF(req->out, "Content-Type: application/octet-stream\r\n");
00111
00112 FCGX_FPrintF(req->out, "\r\n");
00113 FCGX_PutStr((char*)&file_data[0], file_data.size(), req->out);
00114 }
00115
00116 FCGX_Finish_r(req.get());
00117 }
00118
00119 void emitFile(boost::shared_ptr<FCGX_Request> req, const std::string& tree, const std::string &filename)
00120 {
00121 StorageMap::iterator it = g_storage_map.find(tree);
00122 if (it == g_storage_map.end())
00123 fprintf(stderr, "Server does not support tree %s\n", tree.c_str());
00124 else
00125 it->second->getAsync(filename, boost::bind(&sendResult, req, filename, _1));
00126 }
00127
00128
00129
00130 std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
00131 std::stringstream ss(s);
00132 std::string item;
00133 while(std::getline(ss, item, delim)) {
00134 elems.push_back(item);
00135 }
00136 return elems;
00137 }
00138
00139
00140 std::vector<std::string> split(const std::string &s, char delim) {
00141 std::vector<std::string> elems;
00142 return split(s, delim, elems);
00143 }
00144
00145
00146 std::map<std::string, std::string> getParams(char* query_string)
00147 {
00148 std::map<std::string, std::string> params;
00149 std::vector<std::string> params_vec = split(std::string(query_string), '&');
00150 for (unsigned i=0; i<params_vec.size(); i++){
00151 std::vector<std::string> param_vec = split(params_vec[i], '=');
00152 if (param_vec.size() == 2)
00153 params[param_vec[0]] = param_vec[1].c_str();
00154 }
00155 return params;
00156 }
00157
00158
00159
00160 int main(int argc, char** argv)
00161 {
00162 using namespace boost::algorithm;
00163
00164 int ret = FCGX_Init();
00165 if (ret != 0) {
00166 fprintf(stderr, "Unable to initialize fcgi\n");
00167 return 1;
00168 }
00169
00170 std::vector<std::string> trees;
00171
00172
00173
00174
00175
00176
00177
00178 if (argc > 1)
00179 {
00180 std::string arg = argv[1];
00181 boost::replace_all(arg, "/", "$2f");
00182 trees.push_back(arg);
00183 }
00184
00185 for (unsigned i=0; i<trees.size(); i++)
00186 {
00187 std::string tree_path = trees[i];
00188 boost::replace_all(tree_path, "$2f", "/");
00189 printf("Path %s\n", tree_path.c_str());
00190 g_storage_map[trees[i]] = megatree::openStorage(tree_path, megatree::VIZ_FORMAT);
00191 }
00192
00193
00194 while (true)
00195 {
00196 boost::shared_ptr<FCGX_Request> req(new FCGX_Request);
00197 ret = FCGX_InitRequest(req.get(), 0, 0);
00198 assert(ret == 0);
00199 ret = FCGX_Accept_r(req.get());
00200 assert(ret == 0);
00201
00202 char* path_string = FCGX_GetParam("PATH_INFO", req->envp);
00203 if(path_string == NULL)
00204 {
00205 fprintf(stderr, "The path string is null!!!!\n");
00206 }
00207
00208
00209 std::string request_path(path_string ? path_string : "");
00210 if (request_path == "/ping") {
00211 emitPong(req->out);
00212 FCGX_Finish_r(req.get());
00213 }
00214 else if (request_path == "/box") {
00215 emitBox(req->out);
00216 FCGX_Finish_r(req.get());
00217 }
00218 else if (request_path == "/serve_new_tree") {
00219 char* query_string = FCGX_GetParam("QUERY_STRING", req->envp);
00220 std::map<std::string, std::string> params = getParams(query_string);
00221 if (params.find("new_tree_name") != params.end()){
00222 std::string new_tree_name = params["new_tree_name"];
00223 std::vector<std::string> name_split = split(new_tree_name, '_');
00224 if (name_split[0] == "proc" && name_split[1] == "tahoe"){
00225 trees.push_back(new_tree_name);
00226 g_storage_map[new_tree_name] = megatree::openStorage("hbase://wgsc3/" + new_tree_name, megatree::VIZ_FORMAT);
00227 printf("Now also serving tree %s\n", new_tree_name.c_str());
00228 FCGX_FPrintF(req->out,
00229 "Content-Type: text/html\r\n"
00230 "\r\n"
00231 "%s", new_tree_name.c_str());
00232 }
00233 else
00234 printf("Wrong tree name for serving new tree: %s\n", query_string);
00235 }
00236 else
00237 printf("Wrong parameters for serving new tree: %s\n", query_string);
00238 FCGX_Finish_r(req.get());
00239 }
00240 else if (request_path == "/supported_trees") {
00241 emitTrees(req->out, trees);
00242 FCGX_Finish_r(req.get());
00243 }
00244 else if (starts_with(request_path, "/")) {
00245 int slash = request_path.substr(1).find('/');
00246 std::string tree = request_path.substr(1, slash);
00247 std::string filename = request_path.substr(slash+2);
00248 printf("Received request for tree %s and file %s\n", tree.c_str(), filename.c_str());
00249 emitFile(req, tree, filename);
00250 }
00251 else {
00252 emitDump(req->out, req->envp);
00253 FCGX_Finish_r(req.get());
00254 }
00255 }
00256
00257 return 0;
00258 }