#include // XXX: should there just be one uri test for all of these? // Right now, this could fail but it could still try to load _default.cs.. bool can_scaffold_static(char *uri) { if (!strncmp(uri, "/add/", 5) || !strncmp(uri, "/edit/", 6) || !strncmp(uri, "/", strlen(uri))) return true; return false; } bool scaffold_static(evapp_ctx *ctx, HDF **hdf, char **uri) { char dbname[32]; evapp_db *db; uint64_t id = 0; struct evhttp_request *request = evapp_request(ctx); assert(hdf); if (!strncmp(*uri, "/add/", 5)) { if (!get_database_from_uri(request->uri, dbname, sizeof(dbname))) { send_not_found(ctx, "no valid object type was found"); return false; } db = evapp_db_select(ctx, dbname); if (!db) { send_not_found(ctx, "no valid object type was found"); return false; } if (!db->hdf_template(ctx, hdf)) { send_not_found(ctx, "object type could not be templated"); return false; } // rewrite the uri for easy templating if (*uri) free(*uri); *uri = strdup("/add/"); return true; } else if (!strncmp(*uri, "/edit/", 6)) { if (!get_database_from_uri(request->uri, dbname, sizeof(dbname))) { send_not_found(ctx, "no valid object type was found"); return false; } if (!get_last_value_as_uint64(ctx, &id)) { send_not_found(ctx, "invalid object id"); return false; } db = evapp_db_select(ctx, dbname); if (!db) { send_not_found(ctx, "no valid object type was found"); return false; } // Load the existing data. if (!db->load || !db->load(ctx, id, hdf)) { send_not_found(ctx, "object does not exist"); return false; } // Cut off the dbname so that we can have one /add template if (*uri) free(*uri); *uri = strdup("/edit/"); return true; } else if (!strncmp(*uri, "/", strlen(*uri))) { struct evapp_dbq *dbs; char key[128]; size_t count = 0; dbs = evapp_db_head(ctx); if (!dbs) { send_not_found(ctx, "no databases registered"); return false; } hdf_init(hdf); if (!*hdf) { send_error(ctx, "memory is tight. ruh roh!"); return false; } for (db = dbs->tqh_first; db != NULL; db = db->entries.tqe_next) { if (db->hdf_template && db->load && db->save && db->del && db->name) { snprintf(key, sizeof(key), "Database.%zu.name", count); hdf_set_value(*hdf, key, db->name); count++; } } if (count == 0) { send_not_found(ctx, "no scaffold-able databases available"); return false; } return true; } return false; } // loads templates from the db and sets the xsrf token in the hdf void handle_static(evapp_ctx *ctx) { HDF *hdf = NULL; char *uri, *uri_end; bool scaffolded = false; struct evhttp_request *request = evapp_request(ctx); assert(ctx && request); // XXX: Add a generic request/ctx check function if (!request->uri) { send_error(ctx, "inconsistent request structure"); return; } uri = strdup(request->uri); if (!uri) { send_error(ctx, "memory is tight. ruh roh!"); return; } // Trim off the trailing bits if they are there. if ((uri_end = index(uri, '?')) != NULL) *uri_end = '\0'; else if ((uri_end = index(uri, '#')) != NULL) *uri_end = '\0'; // Check if we're scaffolding. If we are, // we should scaffold the /add/ forms for creating data. // XXX: move this out to a scaffold function. if (evapp_get_scaffold(ctx) && can_scaffold_static(uri)) { scaffolded = scaffold_static(ctx, &hdf, &uri); if (!scaffolded) { // Scaffolding should send a response on error for us. free(uri); return; } } if (!scaffolded) hdf_init(&hdf); if (!hdf) { send_error(ctx, "memory is tight. ruh roh!"); return; } // Set an XSRF protection token just in case if (evapp_get_xsrf_protection(ctx) && !set_xsrf_token(ctx, hdf)) { send_not_found(ctx, "xsrf token subsystem failure"); hdf_destroy(&hdf); return; } if (!template_render(ctx, hdf, uri, "")) send_not_found(ctx, "page not found"); if (uri) free(uri); hdf_destroy(&hdf); return; }