/************************************************************************************************* * The CGI utility of the abstract database API * Copyright (C) 2006-2012 FAL Labs * This file is part of Tokyo Cabinet. * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of * the GNU Lesser General Public License as published by the Free Software Foundation; either * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * You should have received a copy of the GNU Lesser General Public License along with Tokyo * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA. *************************************************************************************************/ #include #include #include "myconf.h" #define MINIBNUM 31 // bucket number of map for trivial use #define OUTBUFSIZ (256*1024) // size of the output buffer #define UPLOADMAX (256*1024*1024) // maximum size of the upload data #define DEFSHOWNUM 30 // default number of show result #define FWMMAX 10000 // maximum number of forward matching #define VALWIDTH 80 // maximum width of shown value #define PAGETITLE "Abstract Database Manager" // page title #define DBNAME "casket" // name of the database #define XP(...) tcxstrprintf(obuf, __VA_ARGS__) // syntex sugar of output setting typedef struct { // type of structure of CGI parameters int action; // kind of the action const char *kbuf; // key buffer int ksiz; // key size const char *vbuf; // value buffer int vsiz; // value size int num; // number per page int page; // number of the page } PARAMS; enum { // enumeration for error codes ACTLIST, // list records ACTLISTVAL, // list records with values ACTPUT, // put a record ACTOUT, // remove a record ACTGET // get a record }; /* global variables */ const char *g_scriptname; // program name /* function prototypes */ int main(int argc, char **argv); static void readparameters(TCMAP *params); static void dolist(PARAMS *params, TCADB *db); static void doget(PARAMS *params, TCADB *db); static void doerror(int code, const char *msg); static void sethtmlheader(PARAMS *params, TCXSTR *obuf, TCADB *db); static void sethtmlfooter(PARAMS *params, TCXSTR *obuf, TCADB *db); static void sethtmlcomform(PARAMS *params, TCXSTR *obuf, TCADB *db); static void sethtmlrecval(const char *kbuf, int ksiz, TCXSTR *obuf, TCADB *db); /* main routine */ int main(int argc, char **argv){ g_scriptname = getenv("SCRIPT_NAME"); if(!g_scriptname) g_scriptname = argv[0]; const char *rp = strrchr(g_scriptname, '/'); if(rp) g_scriptname = rp + 1; TCMAP *pmap = tcmapnew2(MINIBNUM); readparameters(pmap); PARAMS params; params.action = ACTLIST; int size; const char *buf = tcmapget(pmap, "action", 6, &size); if(buf) params.action = tcatoix(buf); if(params.action < ACTLIST) params.action = ACTLIST; buf = tcmapget(pmap, "key", 3, &size); if(buf){ params.kbuf = buf; params.ksiz = size; } else { params.kbuf = ""; params.ksiz = 0; } buf = tcmapget(pmap, "value", 5, &size); if(buf){ params.vbuf = buf; params.vsiz = size; } else { params.vbuf = ""; params.vsiz = 0; } if(params.ksiz < 1){ buf = tcmapget(pmap, "value_filename", 14, &size); if(buf){ params.kbuf = buf; params.ksiz = size; } } params.num = 0; buf = tcmapget(pmap, "num", 3, &size); if(buf) params.num = tcatoix(buf); if(params.num < 1) params.num = DEFSHOWNUM; params.page = 1; buf = tcmapget(pmap, "page", 4, &size); if(buf) params.page = tcatoix(buf); if(params.page < 1) params.page = 1; bool wmode; switch(params.action){ case ACTPUT: case ACTOUT: wmode = true; break; default: wmode = false; break; } TCADB *db = tcadbnew(); char path[strlen(DBNAME)+16]; sprintf(path, "%s.tch#mode=%s", DBNAME, wmode ? "w" : "r"); if(!tcadbopen(db, path)){ sprintf(path, "%s.tcb#mode=%s", DBNAME, wmode ? "w" : "r"); if(!tcadbopen(db, path)){ sprintf(path, "%s.tcf#mode=%s", DBNAME, wmode ? "w" : "r"); tcadbopen(db, path); } } if(tcadbsize(db) > 0){ if(wmode) tcadbtranbegin(db); switch(params.action){ case ACTLIST: case ACTLISTVAL: case ACTPUT: case ACTOUT: dolist(¶ms, db); break; case ACTGET: doget(¶ms, db); break; default: doerror(400, "no such action"); break; } if(wmode) tcadbtrancommit(db); } else { doerror(500, "the database file could not be opened"); } tcadbdel(db); tcmapdel(pmap); return 0; } /* read CGI parameters */ static void readparameters(TCMAP *params){ int maxlen = UPLOADMAX; char *buf = NULL; int len = 0; const char *rp; if((rp = getenv("REQUEST_METHOD")) != NULL && !strcmp(rp, "POST") && (rp = getenv("CONTENT_LENGTH")) != NULL && (len = tcatoix(rp)) > 0){ if(len > maxlen) len = maxlen; buf = tccalloc(len + 1, 1); if(fread(buf, 1, len, stdin) != len){ tcfree(buf); buf = NULL; } } else if((rp = getenv("QUERY_STRING")) != NULL){ buf = tcstrdup(rp); len = strlen(buf); } if(buf && len > 0) tcwwwformdecode2(buf, len, getenv("CONTENT_TYPE"), params); tcfree(buf); } /* perform the list action */ static void dolist(PARAMS *params, TCADB *db){ printf("Content-Type: text/html\r\n"); printf("\r\n"); TCXSTR *obuf = tcxstrnew3(OUTBUFSIZ); sethtmlheader(params, obuf, db); if(params->action == ACTPUT){ XP("
\n"); if(params->ksiz < 1){ XP("

Error: the key should be specified.

\n"); } else if(tcadbput(db, params->kbuf, params->ksiz, params->vbuf, params->vsiz)){ XP("

Stored successfully!

\n"); } else { XP("

Error: unknown error.

\n"); } params->kbuf = ""; params->ksiz = 0; params->action = ACTLIST; } else if(params->action == ACTOUT){ XP("
\n"); if(params->ksiz < 1){ XP("

Error: the key should be specified.

\n"); } else if(tcadbout(db, params->kbuf, params->ksiz)){ XP("

Removed successfully!

\n"); } else if(tcadbvsiz(db, params->kbuf, params->ksiz) >= 0){ XP("

Error: unknown error.

\n"); } else { XP("

Error: no such record.

\n"); } params->kbuf = ""; params->ksiz = 0; params->action = ACTLIST; } sethtmlcomform(params, obuf, db); bool isnext = false; XP("
\n"); XP("
\n"); int num = params->num; bool sv = params->action == ACTLISTVAL; if(params->ksiz > 0){ TCLIST *keys = tcadbfwmkeys(db, params->kbuf, params->ksiz, FWMMAX); int knum = tclistnum(keys); int skip = params->num * (params->page - 1); int end = skip + params->num; for(int i = skip; i < knum && i < end; i++){ int ksiz; const char *kbuf = tclistval(keys, i, &ksiz); XP("
\n"); XP("%@", g_scriptname, ACTGET, kbuf, kbuf); if(sv) sethtmlrecval(kbuf, ksiz, obuf, db); XP("
\n"); } tclistdel(keys); isnext = knum > params->num * params->page; } else { tcadbiterinit(db); int ksiz; char *kbuf; int skip = params->num * (params->page - 1); for(int i = 0; i < skip && (kbuf = tcadbiternext(db, &ksiz)) != NULL; i++){ tcfree(kbuf); } for(int i = 0; i < num && (kbuf = tcadbiternext(db, &ksiz)) != NULL; i++){ XP("
\n"); XP("%@", g_scriptname, ACTGET, kbuf, kbuf); if(sv) sethtmlrecval(kbuf, ksiz, obuf, db); XP("
\n"); tcfree(kbuf); } isnext = tcadbrnum(db) > params->num * params->page; } XP("
\n"); XP("
\n"); XP("
\n", g_scriptname); XP("
\n"); if(params->page > 1){ XP("[PREV]\n", g_scriptname, params->action, params->kbuf, params->num, params->page - 1); } else { XP("[PREV]\n"); } if(isnext){ XP("[NEXT]\n", g_scriptname, params->action, params->kbuf, params->num, params->page + 1); } else { XP("[NEXT]\n"); } if(params->action == ACTLIST){ XP("[VALUE]\n", g_scriptname, ACTLISTVAL, params->kbuf, params->num, params->page); } else { XP("[NOVAL]\n", g_scriptname, ACTLIST, params->kbuf, params->num, params->page); } XP("\n"); XP("\n"); XP("
\n"); XP("
\n"); sethtmlfooter(params, obuf, db); fwrite(tcxstrptr(obuf), 1, tcxstrsize(obuf), stdout); tcxstrdel(obuf); } /* perform the get action */ static void doget(PARAMS *params, TCADB *db){ static char *types[] = { ".gz", "application/x-gzip", ".bz2", "application/x-bzip2", ".tar", "application/x-tar", ".zip", "application/zip", ".lzh", "application/octet-stream", ".pdf", "application/pdf", ".ps", "application/postscript", ".xml", "application/xml", ".html", "application/html", ".htm", "application/html", ".doc", "application/msword", ".xls", "application/vnd.ms-excel", ".ppt", "application/ms-powerpoint", ".swf", "application/x-shockwave-flash", ".png", "image/png", ".jpg", "image/jpeg", ".jpeg", "image/jpeg", ".gif", "image/gif", ".bmp", "image/bmp", ".tif", "image/tiff", ".tiff", "image/tiff", ".svg", "image/xml+svg", ".au", "audio/basic", ".snd", "audio/basic", ".mid", "audio/midi", ".midi", "audio/midi", ".mp3", "audio/mpeg", ".mp2", "audio/mpeg", ".wav", "audio/x-wav", ".tch", "application/x-tokyocabinet-hash", ".tcb", "application/x-tokyocabinet-btree", NULL }; int vsiz; char *vbuf = tcadbget(db, params->kbuf, params->ksiz, &vsiz); if(vbuf){ const char *type = "text/plain"; for(int i = 0; types[i]; i++){ if(tcstribwm(params->kbuf, types[i])){ type = types[i+1]; break; } } printf("Content-Type: %s\r\n", type); if(!strchr(params->kbuf, '\n') && !strchr(params->kbuf, '\r')){ if(!strchr(params->kbuf, ' ') && !strchr(params->kbuf, ';')){ printf("Content-Disposition: attachment; filename=%s\r\n", params->kbuf); } else { printf("Content-Disposition: attachment; filename=\"%s\"\r\n", params->kbuf); } } printf("\r\n"); fwrite(vbuf, 1, vsiz, stdout); tcfree(vbuf); } else { doerror(404, "no such record"); } } /* perform the error action */ static void doerror(int code, const char *msg){ printf("Status: %d %s\r\n", code, msg); printf("Content-Type: text/plain\r\n"); printf("\r\n"); printf("%d: %s\n", code, msg); } /* set the header of HTML */ static void sethtmlheader(PARAMS *params, TCXSTR *obuf, TCADB *db){ XP("\n"); XP("\n"); XP("\n"); XP("\n"); XP("\n"); XP("\n"); XP("\n"); XP("\n"); XP("\n"); XP("%@\n", PAGETITLE); XP("\n"); XP("\n"); XP("\n"); XP("\n"); XP("

%@

\n", g_scriptname, PAGETITLE); } /* set the footer of HTML */ static void sethtmlfooter(PARAMS *params, TCXSTR *obuf, TCADB *db){ XP("
\n"); XP("
record number: %lld
\n", (long long)tcadbrnum(db)); XP("
size: %lld
\n", (long long)tcadbsize(db)); XP("\n"); XP("\n"); XP("\n"); } /* set the common form of HTML */ static void sethtmlcomform(PARAMS *params, TCXSTR *obuf, TCADB *db){ XP("
\n"); XP("
\n", g_scriptname); XP("
\n"); XP("\n"); XP("\n"); XP("\n"); XP("\n", ACTPUT); XP("
\n"); XP("
\n"); XP("
\n"); XP("
\n", g_scriptname); XP("
\n"); XP("\n"); XP("\n"); XP("\n"); XP("\n", ACTPUT); XP("
\n"); XP("
\n"); XP("
\n"); XP("
\n", g_scriptname); XP("
\n"); XP("\n"); XP("\n"); XP("\n", ACTOUT); XP("
\n"); XP("
\n"); XP("
\n"); XP("
\n", g_scriptname); XP("
\n"); XP("\n", params->kbuf); XP("\n"); XP("\n", ACTGET); XP("
\n"); XP("
\n"); XP("
\n"); XP("
\n", g_scriptname); XP("
\n"); XP("\n", params->kbuf); XP("\n"); XP("\n", ACTLIST); XP("
\n"); XP("
\n"); } /* set the value of a record */ static void sethtmlrecval(const char *kbuf, int ksiz, TCXSTR *obuf, TCADB *db){ int vsiz; char *vbuf = tcadbget(db, kbuf, ksiz, &vsiz); if(!vbuf) return; XP(": "); bool hex = false; int width = VALWIDTH; for(int j = 0; j < vsiz; j++){ int c = ((unsigned char *)vbuf)[j]; if(c >= 0x20 && c <= 0x7e){ if(hex) tcxstrcat(obuf, " ", 1); switch(c){ case '<': tcxstrcat(obuf, "<", 4); break; case '>': tcxstrcat(obuf, ">", 4); break; case '&': tcxstrcat(obuf, "&", 5); break; default: tcxstrcat(obuf, vbuf + j, 1); break; } width--; hex = false; } else { XP(" %02X", c); width -= 2; hex = true; } if(width < 1){ XP(" ..."); break; } } XP(""); tcfree(vbuf); } // END OF FILE