#include #include #include "helpers.h" #include "callback.h" #include "plugin.h" ///////////////////////////////////////////////////////////////////////////// // {75ed2211-0a25-4a55-962b-31d3b0e6123a} DEFINE_UUID(UUID_REST_PLUGIN, 0x75ed2211, 0x0a25, 0x4a55, 0x96, 0x2b, 0x31, 0xd3, 0xb0, 0xe6, 0x12, 0x3a); ///////////////////////////////////////////////////////////////////////////// typedef struct _PLUGIN { std::string sName; std::string sLibPath; void *hLib; }PLUGIN; typedef int (*PFN_REST_REQUEST_HANDLER)(const struct _u_request*, struct _u_response*, void*); ///////////////////////////////////////////////////////////////////////////// static std::vector g_afr; static std::vector g_aPlugins; ///////////////////////////////////////////////////////////////////////////// static bool _IsSharedLib(const char *pszFilename) { char *pSave = nullptr, szFilename[PATH_MAX], *pszTok; strcpy(szFilename, pszFilename); if((pszTok = strtok_r(szFilename, ".", &pSave))) { while((pszTok = strtok_r(nullptr, ".", &pSave))) { if(!strcmp(pszTok, "so")) return true; } } return false; } ///////////////////////////////////////////////////////////////////////////// int LoadPlugins(const char *pszRootDir, struct _u_instance *pInst, json_error_t &rJerr, PCREST_PLUGIN_REQUEST_CONTEXT prc) { DIR *d; int nLoaded = 0; struct dirent *dir; char szPluginDir[PATH_MAX + 32]; char szPluginLib[PATH_MAX + 32 + 256]; sprintf(szPluginDir, "%s/plugin", pszRootDir); if((d = opendir(szPluginDir))) { while((dir = readdir(d))) { if((dir->d_type == DT_REG) && _IsSharedLib(dir->d_name)) { sprintf(szPluginLib, "%s/plugin/%s", pszRootDir, dir->d_name); void *hLib = dlopen(szPluginLib, RTLD_NOW); if(hLib) { PFN_GETPLUGININFO GetPluginInfo = (PFN_GETPLUGININFO)dlsym(hLib, "GetPluginInfo"); if(GetPluginInfo) { const REST_PLUGIN_INFO *ppi = nullptr; if((ppi = GetPluginInfo())) { if(!_uuid_compare(&UUID_REST_PLUGIN, &ppi->signature)) { PLUGIN plugin; plugin.sName = ppi->pszPluginName; plugin.sLibPath = szPluginLib; plugin.hLib = hLib; g_aPlugins.push_back(plugin); for(size_t i = 0; i < ppi->nHandlerCnt; ++i) { const REST_REQUEST_HANDLER &rh = ppi->handler[i]; PFN_REST_REQUEST_HANDLER RequestHandler = (PFN_REST_REQUEST_HANDLER)dlsym(hLib, rh.pszFunctionName); if(RequestHandler) { if(ulfius_add_endpoint_by_val(pInst, rh.pszHttpMethod, rh.pszVirtPath, nullptr, 0, RequestHandler, (void*)prc) == U_OK) ++nLoaded; } } } else { dlclose(hLib); } } else { dlclose(hLib); } } else { dlclose(hLib); } } } } closedir(d); } return nLoaded; } ///////////////////////////////////////////////////////////////////////////// void UnloadPlugins(void) { for(PLUGIN &p : g_aPlugins) { if(p.hLib) dlclose(p.hLib); } g_aPlugins.clear(); } ///////////////////////////////////////////////////////////////////////////// int InitializeStaticFiles(const char *pszRootDir, struct _u_instance *pInst, json_error_t &rJerr) { int nRet = 0; char szFilename[PATH_MAX + 32]; sprintf(szFilename, "%s/staticfiles.json", pszRootDir); if(FileExist(szFilename)) { CJson_t jtRoot(json_load_file(szFilename, JSON_REJECT_DUPLICATES, &rJerr)); // new reference! if(jtRoot.IsValid()) { const char *pszVal; bool bVal; if(!jtRoot.IsArray()) { ETRACE("staticfiles.json contains no array!\n"); return -1; } for(size_t i = 0; i < json_array_size(jtRoot); i++) { FILEREQUEST fr; CJson_t jtArr(json_array_get(jtRoot, i), false); // borrowed reference! if(jtArr.IsValid()) { if(!jtArr.IsObject()) { ETRACE("staticfiles.json: element %zu is no object!\n", i); return -1; } json_t *pjtMethod = json_object_get(jtArr, "method"); pszVal = json_string_value(pjtMethod); fr.strMethod = pszVal; json_t *pjtUrl = json_object_get(jtArr, "URL"); pszVal = json_string_value(pjtUrl); fr.strURL = pszVal; json_t *pjtFilename = json_object_get(jtArr, "fileName"); pszVal = json_string_value(pjtFilename); sprintf(szFilename, "%s/%s", pszRootDir, pszVal); fr.strFilename = szFilename; json_t *pjtContentType = json_object_get(jtArr, "contentType"); pszVal = json_string_value(pjtContentType); fr.strContentType = pszVal; json_t *pjtIsString = json_object_get(jtArr, "isString"); bVal = json_boolean_value(pjtIsString); fr.bString = bVal; fr.pfnCallback = &FileBodyResponseCallback; g_afr.push_back(fr); } else { ETRACE("Error!\n"); return -1; } } } else { if(rJerr.column == -1 || rJerr.line == -1) { TRACE("staticfiles.json: no static files configured.\n"); return 0; } else { ETRACE("%s: line %d, column %d: %s.\n", szFilename, rJerr.line, rJerr.column, rJerr.text); return -1; } } } else { // TRACE("No static files found.\n"); return 0; } // Endpoint list declaration for(auto it = g_afr.begin(); it != g_afr.end(); it++) { FILEREQUEST &rfr = *it; if(ulfius_add_endpoint_by_val(pInst, rfr.strMethod.c_str(), rfr.strURL.c_str(), nullptr, 0, rfr.pfnCallback, &rfr) != U_OK) { ETRACE("Error adding endpoint for URL '%s'!\n", rfr.strURL.c_str()); return -1; } else { nRet++; } } return nRet; }