//-< CGIBROWS.CXX >--------------------------------------------------*--------* // GOODS Version 1.0 (c) 1997 GARRET * ? * // (Generic Object Oriented Database System) * /\| * // * / \ * // Created: 30-Oct-97 K.A. Knizhnik * / [] \ * // Last update: 30-Oct-97 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* // CGI application for browsing database //-------------------------------------------------------------------*--------* #include "goods.h" #include "client.h" USE_GOODS_NAMESPACE class database_browser : public dbs_application { protected: dbs_storage** storage; char* database_name; int n_storages; dnm_buffer obj_buf; dnm_buffer cls_buf; virtual void disconnected(stid_t sid); virtual void login_refused(stid_t sid); virtual void invalidate(stid_t sid, opid_t opid); public: boolean open(const char* dbs_name); void close(); void dump_object(stid_t sid, opid_t opid); virtual~database_browser() {} }; class browser_console : public console { public: static void report(const char* msg) { printf("Content-type: text/html\n\n" "" "Database browser message" "

%s

", msg); } void output_data(output_type, const char* msg, va_list args) { char buf[1024]; vsprintf(buf, msg, args); report(buf); exit(0); } }; browser_console www_console; void database_browser::disconnected(stid_t sid) { browser_console::report("Server is disconnected"); } void database_browser::login_refused(stid_t sid) { browser_console::report("Authorization procedure fails at server"); } void database_browser::invalidate(stid_t, opid_t) { } boolean database_browser::open(const char* dbs_name) { char cfg_file_name[MAX_CFG_FILE_LINE_SIZE]; char cfg_buf[MAX_CFG_FILE_LINE_SIZE]; int len = strlen(dbs_name); database_name = new char[len+1]; strcpy(database_name, dbs_name); if (len < 4 || strcmp(dbs_name+len-4, ".cfg") != 0) { sprintf(cfg_file_name, "%s.cfg", dbs_name); } else { strcpy(cfg_file_name, dbs_name); } FILE* cfg = fopen(cfg_file_name, "r"); if (cfg == NULL) { browser_console::report("Failed to open database configuration file"); return False; } if (fgets(cfg_buf, sizeof cfg_buf, cfg) == NULL || sscanf(cfg_buf, "%d", &n_storages) != 1) { browser_console::report("Bad format of configuration file"); return False; } storage = new dbs_storage*[n_storages]; memset(storage, 0, n_storages*sizeof(obj_storage*)); while (fgets(cfg_buf, sizeof cfg_buf, cfg)) { int i; char hostname[MAX_CFG_FILE_LINE_SIZE]; if (sscanf(cfg_buf, "%d:%s", &i, hostname) == 2) { storage[i] = new dbs_client_storage(i, this); if (!storage[i]->open(hostname)) { delete storage[i]; storage[i] = NULL; } } } fclose(cfg); return True; } void database_browser::close() { delete[] database_name; for (int i = 0; i < n_storages; i++) { if (storage[i] != NULL) { storage[i]->close(); delete storage[i]; } } delete[] storage; } inline boolean is_ascii(char* s, int len) { while (--len >= 0) { int ch = *s++; if (ch != 0 && !isprint(ch & 0xFF)) { return False; } } return True; } static char* dump_raw_binary(char* bins) { nat4 len; bins = unpack4((char*)&len, bins); int i, n = len; for (i = 0; i < n && bins[i] > 0 && isprint(bins[i]); i++); if (i == n || (i == n-1 && bins[i] == '\0')) { printf("\"%.*s\"", n, bins); } else { char sep = '{'; for (i = 0; i < n; i++) { printf("%c0x%02x", sep, bins[i] & 0xFF); sep = ','; } if (sep == '{') { printf("{}"); } else { printf("}"); } } return bins + n; } static char* dump_imu_string(char* bins) { nat2 len; bins = unpack2((char*)&len, bins); if(len == 0xFFFF) { printf("null"); } else { printf("\""); while(len-- > 0) { nat2 ch; bins = unpack2((char*)&ch, bins); if((ch & 0xFF00) || !isprint(ch)) { printf("\\u%04X", ch); } else if (ch == '<') { printf("<"); } else if (ch == '>') { printf(">"); } else if (ch == '&') { printf("&"); } else if (ch == '"') { printf("""); } else { putchar((char)ch); } } printf("\""); } return bins; } void dump_fields(dbs_class_descriptor* cld, size_t obj_size, int field_no, int n_fields, char* prefix, int prefix_len, char* database_name, char* &refs, char* &bins) { if (n_fields == 0) { return; } nat2 sid; nat4 opid; int next_field = field_no + n_fields; do { dbs_field_descriptor* field = &cld->fields[field_no]; int len = prefix_len; prefix_len += sprintf(prefix+len, "%s", &cld->names[field->name]); int n = field->is_varying() ? cld->get_varying_length(obj_size) : field->n_items; if (field->size == 1 && is_ascii(bins, n)) { if (n == 1) { char ch = *bins++; if (ch == 0) { printf("%s0", prefix); } else { printf("%s'%c'(%X)", prefix, ch, nat1(ch)); } } else { printf("%s\"%.*s\"", prefix, n, bins); bins += n; } } else { long prev_val = 0; opid_t prev_opid = 0; stid_t prev_sid = 0; boolean etc = False; int len2 = prefix_len; for (int i = 0; i < n; i++) { if (n > 1) { prefix_len += sprintf(prefix+len2, "[%d]", i); } switch (field->type) { case fld_structure: prefix[prefix_len++] = '.'; prefix[prefix_len] = '\0'; dump_fields(cld, obj_size, field_no+1, field->next ? field->next - field_no - 1 : next_field - field_no - 1, prefix, prefix_len, database_name, refs, bins); break; case fld_reference: refs = unpackref(sid, opid, refs); if (i > 0 && prev_sid == sid && prev_opid == opid) { etc = True; } else { if (etc) { printf("......"); etc = False; } prev_opid = opid; prev_sid = sid; if (opid == 0) { printf("%sNIL", prefix); } else { printf("%s" "" "%x:%x", prefix, getenv("HTTP_HOST"), getenv("SCRIPT_NAME"), sid, opid, database_name, sid, opid); } } break; case fld_signed_integer: if (field->size == 1) { int1 val = *(int1*)bins++; if (i > 0 && prev_val == val) { etc = True; } else { if (etc) { printf("......"); etc = False; } prev_val = val; printf("%s%d", prefix, val); } } else if (field->size == 2) { int2 val; bins = unpack2((char*)&val, bins); if (i > 0 && prev_val == val) { etc = True; } else { if (etc) { printf("......"); etc = False; } prev_val = val; printf("%s%d", prefix, val); } } else if (field->size == 4) { int4 val; bins = unpack4((char*)&val, bins); if (i > 0 && prev_val == val) { etc = True; } else { if (etc) { printf("......"); etc = False; } prev_val = val; printf("%s%d", prefix, val); } } else { int8 val; bins = unpack8((char*)&val, bins); printf("%s%"INT8_FORMAT"d", prefix, val); } break; case fld_unsigned_integer: if (field->size == 1) { nat1 val = *(nat1*)bins++; if (i > 0 && nat1(prev_val) == val) { etc = True; } else { if (etc) { printf("......"); etc = False; } prev_val = val; printf("%s0x%x", prefix, val); } } else if (field->size == 2) { nat2 val; bins = unpack2((char*)&val, bins); if (i > 0 && nat2(prev_val) == val) { etc = True; } else { if (etc) { printf("......"); etc = False; } prev_val = val; printf("%s0x%x", prefix, val); } } else if (field->size == 4) { nat4 val; bins = unpack4((char*)&val, bins); if (i > 0 && nat4(prev_val) == val) { etc = True; } else { if (etc) { printf("......"); etc = False; } prev_val = val; printf("%s0x%x", prefix, val); } } else { nat8 val; bins = unpack8((char*)&val, bins); printf("%s%"INT8_FORMAT"x", prefix, val); } break; case fld_real: if (field->size == 4) { real4 val; bins = unpack4((char*)&val, bins); printf("%s%f", prefix, val); } else { real8 val; bins = unpack8((char*)&val, bins); printf("%s%f", prefix, val); } break; case fld_string: printf("%s", prefix); bins = dump_imu_string(bins); printf(""); break; case fld_raw_binary: printf("%s", prefix); bins = dump_raw_binary(bins); printf(""); break; } prefix_len = len2; } if (etc) { printf("%.*s[%d]...", prefix_len, prefix, n-1); } } prefix_len = len; field_no = field->next; } while (field_no != 0); } void database_browser::dump_object(stid_t sid, opid_t opid) { dbs_class_descriptor* cld; char buf[1024]; if (sid >= n_storages || storage[sid] == NULL) { browser_console::report("Storage is not in configuration file or not available"); return; } storage[sid]->load(opid, lof_none, obj_buf); dbs_object_header* hdr = (dbs_object_header*)&obj_buf; cpid_t cpid = hdr->get_cpid(); if (cpid == 0) { browser_console::report("Object is not in the database"); return; } else if (cpid == RAW_CPID) { browser_console::report("Abstract root object"); return; } storage[sid]->get_class(cpid, cls_buf); assert(cls_buf.size() != 0); cld = (dbs_class_descriptor*)&cls_buf; cld->unpack(); printf("Content-type: text/html\n\n"); printf(""); printf("Object \"%s\" %x:%x", cld->name(), sid, opid); printf("

%s %x:%x

", cld->name(), sid, opid); printf("" ""); size_t obj_size = hdr->get_size(); char* refs = hdr->body(); char* bins = refs + cld->get_number_of_references(obj_size)*sizeof(dbs_reference_t); dump_fields(cld, obj_size, 0, cld->n_fields, buf, 0, database_name, refs, bins); printf("
ComponentValue
"); } int main() { char* query_string = getenv("QUERY_STRING"); if (query_string != NULL) { task::initialize(task::huge_stack); database_browser db; int sid; int opid = ROOT_OPID; char dbs_name[64]; char* p = strchr(query_string, '&'); if (p != NULL) { // open form *p = '\0'; if (sscanf(query_string, "database=%s", dbs_name) != 1 || sscanf(p+1, "storage=%d", &sid) != 1) { browser_console::report("Invalid parameters are specified"); return 0; } } else { // go by reference if (sscanf(query_string, "%x:%x@%s", &sid, &opid, dbs_name) != 3) { browser_console::report("Invalid format of reference"); return 0; } } if (db.open(dbs_name)) { db.dump_object(sid, opid); db.close(); } } return 0; }