#ifdef STANDALONE #include #include #include #include "web.h" #include "tokens.h" #ifdef _MHD_FLAGS_ENUM typedef enum MHD_Result HttpResult; #else typedef int HttpResult; #endif enum RouteType { GET, POST, }; struct Route { const char* path; Object routeAction; struct Environment* env; enum RouteType type; }; int requestDefinition = -1; int routeCount = 0; struct Route routes[10]; int addRoute(struct Route route) { routes[routeCount] = route; routeCount += 1; return 0; } int methodMatches(const char* method, struct Route* route) { switch (route->type) { case GET: return method[0] == 'G' || method[0] == 'g'; case POST: return (method[0] == 'P' || method[0] == 'p') && (method[1] == 'O' || method[1] == 'o'); default: return 0; } } static HttpResult add_query_param(void* queryParamsV, enum MHD_ValueKind kind, const char* key, const char* value) { (void) kind; /* Unused. Silent compiler warning. */ Object* queryParams = queryParamsV; Object pair = startList(nullTerminated(key)); Object parsed; if (isDigit(value[0])) { parsed = parseEval(value, NULL); } else { parsed = stringFromSlice(value, strlen(value)); } nf_addToList(&pair, parsed); nf_addToList(queryParams, pair); return MHD_YES; } static HttpResult answer_to_connection(void* cls, struct MHD_Connection* connection, const char* url, const char* method, const char* version, const char* upload_data, size_t* upload_data_size, void** con_cls) { (void) cls; /* Unused. Silence compiler warning. */ (void) upload_data_size; /* Unused. Silence compiler warning. */ (void) con_cls; /* Unused. Silence compiler warning. */ char* page = NULL; printf("%s :: %s URL: '%s'\n", method, version, url); if (upload_data) { printf("upload_data: %s\n", upload_data); } for (int i = 0; i < routeCount; i++) { if (methodMatches(method, &routes[i]) && strcmp(url, routes[i].path) == 0) { Object queryParams = listObject(); MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, add_query_param, &queryParams); char* password = NULL; char* username = MHD_basic_auth_get_username_password(connection, &password); Object usernameO = username ? nullTerminated(username) : stringFromSlice("", 0); Object passwordO = password ? nullTerminated(password) : stringFromSlice("", 0); MHD_free(username); MHD_free(password); Object res = structObject(requestDefinition); res.structObject->fields[0] = queryParams; res.structObject->fields[1] = usernameO; res.structObject->fields[2] = passwordO; Object route = cloneObject(routes[i].routeAction); Object result = listEvalLambda(&route, &res, 2, routes[i].env); cleanObject(&res); page = result.string; break; } } if (!page) { printf("no route found!\n"); page = "

404, Dumbass.

"; } struct MHD_Response* response = MHD_create_response_from_buffer( strlen(page), (void*) page, MHD_RESPMEM_PERSISTENT); HttpResult ret = MHD_queue_response(connection, MHD_HTTP_OK, response); MHD_destroy_response(response); return ret; } void initialize() { printf("Initializing...\n"); Object o = parseEval("(struct Request (queryParams username password))", global()); cleanObject(&o); requestDefinition = getStructIndex("Request"); } int start(int port) { static int initialized = 0; if (!initialized) { initialize(); initialized = 1; } struct MHD_Daemon* daemon = MHD_start_daemon( MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, port, NULL, NULL, &answer_to_connection, NULL, MHD_OPTION_END); if (NULL == daemon) { return 1; } return 0; } void addRouteO(Object path, Object textFunc, struct Environment* env, enum RouteType type) { char* p = malloc(sizeof(char) * strlen(path.string) + 1); strcpy(p, path.string); struct Route r; r.path = p; r.routeAction = cloneObject(textFunc); r.env = env; r.type = type; env->refs += 1; addRoute(r); } Object addGetRoute(Object* params, int length, struct Environment* env) { Object path = params[0]; Object textFunc = params[1]; addRouteO(path, textFunc, env, GET); return numberObject(1); } Object addPostRoute(Object* params, int length, struct Environment* env) { Object path = params[0]; Object textFunc = params[1]; addRouteO(path, textFunc, env, POST); return numberObject(1); } Object startServer(Object* params, int length, struct Environment* env) { Object portObject = params[0]; int port = 8888; if (length && portObject.type == TYPE_NUMBER) { port = portObject.number; } return numberObject(start(port)); } #endif // STANDALONE