#include "main.h" #include "helpers.h" #include "callback.h" ///////////////////////////////////////////////////////////////////////////// static void _SetCORSResponseHeaders(struct _u_response * response, bool bAllowCredentials = true); ///////////////////////////////////////////////////////////////////////////// #define _SIG_BLOCK(s) pthread_sigmask(SIG_BLOCK, (s), NULL) #define _SIG_UNBLOCK(s) pthread_sigmask(SIG_UNBLOCK, (s), NULL) ///////////////////////////////////////////////////////////////////////////// // FileBodyResponseCallback (serves static files) int FileBodyResponseCallback(const struct _u_request * request, struct _u_response * response, void * user_data) { UNUSED(request); LPFILEREQUEST pfr = (LPFILEREQUEST)user_data; if(pfr) { FILE *pf = fopen(pfr->strFilename.c_str(), "rb"); if(pf) { size_t nSize = GetFileSize(pf); char *pszContent = (char*)malloc(nSize + 1); nSize = fread(pszContent, 1, nSize, pf); fclose(pf); pszContent[nSize] = '\0'; _SetCORSResponseHeaders(response); ulfius_add_header_to_response(response, "Content-Type", pfr->strContentType.c_str()); ulfius_set_binary_body_response(response, 200, pszContent, nSize); free(pszContent); return U_CALLBACK_CONTINUE; } else { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 404); } } else { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); } return U_CALLBACK_CONTINUE; } ///////////////////////////////////////////////////////////////////////////// // GetShmPostResponseCallback_M - getshm - POST Request, returns a linear map int GetShmPostResponseCallback_M(const struct _u_request * request, struct _u_response * response, void * user_data) { LPCSHM_REQUEST_PARAMS psrp = (LPCSHM_REQUEST_PARAMS)user_data; if(!psrp || !psrp->pMap || !psrp->pszUuid) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); return U_CALLBACK_CONTINUE; } CRestVarTable &map = *psrp->pMap; json_error_t jErr; CJson_t jtRequ(ulfius_get_json_body_request(request, &jErr)); // new reference! CJson_t jtUuid(json_string(psrp->pszUuid)); // new reference! if(jtRequ.IsValid()) { CJson_t jtResponse(json_object()); // new reference! CJson_t jtArrValues(json_array()); // new reference! json_object_set(jtResponse, "uuid", jtUuid); if(jtRequ.IsArray()) { json_object_set(jtResponse, "request", jtRequ); size_t nIndex; json_t *pjtEle; json_array_foreach(jtRequ, nIndex, pjtEle) { CJson_t jtPath(json_object_get(pjtEle, "path"), false); // borrowed reference! if(!jtPath.IsValid()) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 400); return U_CALLBACK_CONTINUE; } const char *pszPath = json_string_value(jtPath); CRest *pRest = map.Find(pszPath); if(!pRest) { CJson_t jtStatus(CRest::CreateStatusObject((int)nIndex, -1, "Invalid path!", pszPath)); json_array_append(jtArrValues, jtStatus); } else { sigset_t sset; ::sigfillset(&sset); _SIG_BLOCK(&sset); pRest->GetValue((int)nIndex, jtArrValues); // new reference! _SIG_UNBLOCK(&sset); } } json_object_set(jtResponse, "response", jtArrValues); _SetCORSResponseHeaders(response); ulfius_set_json_body_response(response, 200, jtResponse); } else if(jtRequ.IsObject()) { CJson_t jtArrReq(json_array()); // new reference! json_array_append(jtArrReq, jtRequ); json_object_set(jtResponse, "request", jtArrReq); CJson_t jtPath(json_object_get(jtRequ, "path"), false); // borrowed reference! if(!jtPath.IsValid()) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 400); return U_CALLBACK_CONTINUE; } const char *pszPath = json_string_value(jtPath); CRest *pRest = map.Find(pszPath); if(!pRest) { CJson_t jtStatus(CRest::CreateStatusObject(0, -1, "Invalid path!", pszPath)); json_array_append(jtArrValues, jtStatus); } else { sigset_t sset; ::sigfillset(&sset); _SIG_BLOCK(&sset); pRest->GetValue(0, jtArrValues); // new reference! _SIG_UNBLOCK(&sset); } json_object_set(jtResponse, "response", jtArrValues); _SetCORSResponseHeaders(response); ulfius_set_json_body_response(response, 200, jtResponse); } else { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 400); return U_CALLBACK_CONTINUE; } } else { fprintf(stderr, "%s\n", jErr.text); _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); } return U_CALLBACK_CONTINUE; } ///////////////////////////////////////////////////////////////////////////// // GetShmPostResponseCallback_O - getshm - POST Request, returns a structured object int GetShmPostResponseCallback_O(const struct _u_request * request, struct _u_response * response, void * user_data) { LPCSHM_REQUEST_PARAMS psrp = (LPCSHM_REQUEST_PARAMS)user_data; if(!psrp || !psrp->pMap || !psrp->pszUuid) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); return U_CALLBACK_CONTINUE; } CRestVarTable &map = *psrp->pMap; json_error_t jErr; CJson_t jtRequ(ulfius_get_json_body_request(request, &jErr)); // new reference! CJson_t jtUuid(json_string(psrp->pszUuid)); // new reference! if(jtRequ) { CJson_t jtPath(json_object_get(jtRequ, "path"), false); // borrowed reference! if(!jtPath) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); return U_CALLBACK_CONTINUE; } const char *pszPath = json_string_value(jtPath); CRest *pRest = map.Find(pszPath); if(!pRest) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 404); return U_CALLBACK_CONTINUE; } sigset_t sset; ::sigfillset(&sset); _SIG_BLOCK(&sset); CJson_t jtVal(pRest->GetValue(0)); // new reference! _SIG_UNBLOCK(&sset); if(jtVal) { CJson_t jtObj(json_object()); // new reference! json_object_set(jtObj, "request", jtRequ); json_object_set(jtObj, "response", jtVal); json_object_set(jtObj, "uuid", jtUuid); _SetCORSResponseHeaders(response); ulfius_set_json_body_response(response, 200, jtObj); } else { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); } } else { fprintf(stderr, "%s\n", jErr.text); _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); } return U_CALLBACK_CONTINUE; } ///////////////////////////////////////////////////////////////////////////// // SetShmPostResponseCallback - setshm - POST Request int SetShmPostResponseCallback(const struct _u_request * request, struct _u_response * response, void * user_data) { LPCSHM_REQUEST_PARAMS psrp = (LPCSHM_REQUEST_PARAMS)user_data; if(!psrp || !psrp->pMap || !psrp->pszUuid) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); return U_CALLBACK_CONTINUE; } CRestVarTable &map = *psrp->pMap; json_error_t jErr; CJson_t jtRequ(ulfius_get_json_body_request(request, &jErr)); // new reference! CJson_t jtUuid(json_string(psrp->pszUuid)); // new reference! if(jtRequ.IsValid()) { CJson_t jtResponse(json_object()); // new reference! CJson_t jtArrStatus(json_array()); // new reference! json_object_set(jtResponse, "uuid", jtUuid); json_object_set(jtResponse, "response", jtArrStatus); if(jtRequ.IsArray()) { json_object_set(jtResponse, "request", jtRequ); size_t nIndex; json_t *pjtEle; json_array_foreach(jtRequ, nIndex, pjtEle) { CJson_t jtPath(json_object_get(pjtEle, "path"), false); // borrowed reference! CJson_t jtVal(json_object_get(pjtEle, "value"), false); // borrowed reference! if(!jtPath.IsValid() || !jtVal.IsValid()) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 400); return U_CALLBACK_CONTINUE; } const char *pszPath = json_string_value(jtPath); CRest *pRest = map.Find(pszPath); if(!pRest) { CJson_t jtStatus(CRest::CreateStatusObject((int)nIndex, -1, "Invalid path!", pszPath)); json_array_append(jtArrStatus, jtStatus); } else { sigset_t sset; ::sigfillset(&sset); _SIG_BLOCK(&sset); CJson_t jtStatus(pRest->SetValue((int)nIndex, jtVal)); // new reference! _SIG_UNBLOCK(&sset); json_array_append(jtArrStatus, jtStatus); } } _SetCORSResponseHeaders(response); ulfius_set_json_body_response(response, 200, jtResponse); } else if(jtRequ.IsObject()) { CJson_t jtArrReq(json_array()); // new reference! json_array_append(jtArrReq, jtRequ); json_object_set(jtResponse, "request", jtArrReq); CJson_t jtPath(json_object_get(jtRequ, "path"), false); // borrowed reference! CJson_t jtVal(json_object_get(jtRequ, "value"), false); // borrowed reference! if(!jtPath.IsValid() || !jtVal.IsValid()) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); return U_CALLBACK_CONTINUE; } const char *pszPath = json_string_value(jtPath); CRest *pRest = map.Find(pszPath); if(!pRest) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 404); return U_CALLBACK_CONTINUE; } sigset_t sset; ::sigfillset(&sset); _SIG_BLOCK(&sset); CJson_t jtStatus(pRest->SetValue(0, jtVal)); // new reference! _SIG_UNBLOCK(&sset); json_array_append(jtArrStatus, jtStatus); _SetCORSResponseHeaders(response); ulfius_set_json_body_response(response, 200, jtResponse); } else { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 400); return U_CALLBACK_CONTINUE; } } else { fprintf(stderr, "%s\n", jErr.text); _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); } return U_CALLBACK_CONTINUE; } ///////////////////////////////////////////////////////////////////////////// // GetShmGetResponseCallback - getshm - GET Request int GetShmGetResponseCallback(const struct _u_request * request, struct _u_response * response, void * user_data) { static size_t nPrefixLen = strlen(GET_SHM_PREFIX); LPCSHM_REQUEST_PARAMS psrp = (LPCSHM_REQUEST_PARAMS)user_data; if(!psrp || !psrp->pMap || !psrp->pszUuid) { _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); return U_CALLBACK_COMPLETE; } CJson_t jtUuid(json_string(psrp->pszUuid)); // new reference! const char *pszPath = request->http_url; CURL *hUrl = NULL; char *pszCUrl = NULL, *pszUrlParams = NULL; if(!pszPath || !*pszPath || strlen(pszPath) == nPrefixLen) pszPath = "/"; else { hUrl = curl_easy_init(); pszPath += nPrefixLen; pszCUrl = curl_easy_unescape(hUrl, pszPath, 0, NULL); pszPath = pszCUrl; pszUrlParams = strchr(pszCUrl, '?'); if(pszUrlParams) { *pszUrlParams++ = '\0'; /* char **ppRet; split_string(pszUrlParams, "&", &ppRet); free_string_array(ppRet);*/ } } CRestVarTable &map = *psrp->pMap; CRest *pRest = map.Find(pszPath); if(!pRest) { if(pszCUrl) curl_free(pszCUrl); if(hUrl) curl_easy_cleanup(hUrl); _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 404); return U_CALLBACK_COMPLETE; } sigset_t sset; ::sigfillset(&sset); _SIG_BLOCK(&sset); CJson_t jtVal(pRest->GetValue(0)); // new reference! _SIG_UNBLOCK(&sset); if(jtVal.IsValid()) { CJson_t jtRequ(json_object()); // new reference! CJson_t jtPath(json_string(pszPath)); json_object_set(jtRequ, "path", jtPath); CJson_t jtObj(json_object()); // new reference! json_object_set(jtObj, "request", jtRequ); json_object_set(jtObj, "response", jtVal); json_object_set(jtObj, "uuid", jtUuid); _SetCORSResponseHeaders(response); ulfius_add_header_to_response(response, "Content-Disposition", "attachment; filename=\"shm.json\""); ulfius_set_json_body_response(response, 200, jtObj); } else { if(pszCUrl) curl_free(pszCUrl); if(hUrl) curl_easy_cleanup(hUrl); _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 500); return U_CALLBACK_COMPLETE; } if(pszCUrl) curl_free(pszCUrl); if(hUrl) curl_easy_cleanup(hUrl); return U_CALLBACK_CONTINUE; } ///////////////////////////////////////////////////////////////////////////// // OptionsResponseCallback - OPTIONS Request (CORS preflight ...) int OptionsResponseCallback(const struct _u_request * request, struct _u_response * response, void * user_data) { UNUSED(user_data); const char *pszHeaders = u_map_get_case(request->map_header, "Access-Control-Request-Headers"); if(!pszHeaders) pszHeaders = "Content-Type"; ulfius_add_header_to_response(response, "Allow", "POST, GET, OPTIONS"); ulfius_add_header_to_response(response, "Access-Control-Allow-Methods", "POST, GET, OPTIONS"); ulfius_add_header_to_response(response, "Access-Control-Allow-Headers", pszHeaders); _SetCORSResponseHeaders(response); ulfius_set_empty_body_response(response, 200); // Ok return U_CALLBACK_COMPLETE; } ///////////////////////////////////////////////////////////////////////////// // NotAllowedResponseCallback int NotAllowedResponseCallback(const struct _u_request * request, struct _u_response * response, void * user_data) { UNUSED(request); UNUSED(user_data); ulfius_set_empty_body_response(response, 405); // Method Not Allowed return U_CALLBACK_COMPLETE; } ///////////////////////////////////////////////////////////////////////////// // NotImplementedResponseCallback int NotImplementedResponseCallback(const struct _u_request * request, struct _u_response * response, void * user_data) { UNUSED(request); UNUSED(user_data); ulfius_set_empty_body_response(response, 501); // Not Implemented return U_CALLBACK_COMPLETE; } ///////////////////////////////////////////////////////////////////////////// // _SetCORSResponseHeaders static void _SetCORSResponseHeaders(struct _u_response * response, bool bAllowCredentials) { ulfius_add_header_to_response(response, "Access-Control-Allow-Origin", "*"); if(bAllowCredentials) ulfius_add_header_to_response(response, "Access-Control-Allow-Credentials", "true"); }