/* * Copyright (c) 2023 Fancy Code. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "WebServer.h" #include "ILog.h" #include "goahead.h" #include "js.h" #include static int finished = 0; static HttpHandleCallback gHttpHandle = NULL; constexpr int UNKNOWN_LENGTH = -1; static void sigHandler(int signo) { LogInfo("Stop goahead web server.\n"); finished = 1; } static void CheckUploadDir(void) { const char *directory = GOAHEAD_UPLOAD_TMP_PATH; if (access(directory, F_OK) != 0) { int result = mkdir(directory, 0777); if (result == 0) { LogInfo("mkdir upload tmp path successfuly.\n"); } else { LogError("mkdir upload tmp path failed.\n"); } } const char *directory2 = GOAHEAD_UPLOAD_PATH; if (access(directory2, F_OK) != 0) { int result = mkdir(directory2, 0777); if (result == 0) { LogInfo("mkdir upload path successfuly.\n"); } else { LogError("mkdir upload path failed.\n"); } } } static void logHeader(void) { char home[ME_GOAHEAD_LIMIT_STRING]; char *result = getcwd(home, sizeof(home)); if (nullptr == result) { LogWarning("Can't get path.\n"); } logmsg(2, "Configuration for %s", ME_TITLE); logmsg(2, "---------------------------------------------"); logmsg(2, "Version: %s", ME_VERSION); logmsg(2, "BuildType: %s", ME_DEBUG ? "Debug" : "Release"); logmsg(2, "CPU: %s", ME_CPU); logmsg(2, "OS: %s", ME_OS); logmsg(2, "Host: %s", websGetServer()); logmsg(2, "Directory: %s", home); logmsg(2, "Documents: %s", websGetDocuments()); logmsg(2, "Configure: %s", ME_CONFIG_CMD); logmsg(2, "---------------------------------------------"); } void initPlatform(void) { signal(SIGINT, sigHandler); signal(SIGTERM, sigHandler); signal(SIGKILL, sigHandler); signal(SIGPIPE, SIG_IGN); } static void response_handle(const char *responseStr, void *context) { struct Webs *wp = (struct Webs *)context; if (NULL != responseStr) { websWrite(wp, "%s", responseStr); } } static void get_thumbnail_handle(const char *thumbnailUrl, void *context) { struct Webs *wp = (struct Webs *)context; if (nullptr == thumbnailUrl) { LogError("thumbnailUrl is nullptr.\n"); return; } FILE *file = nullptr; unsigned char *buffer = nullptr; size_t bytesRead = 0; long int fsize = 0; file = fopen(thumbnailUrl, "rb"); if (file == nullptr) { LogError("Open picture failed[%s].\n", thumbnailUrl); goto END; } fseek(file, 0, SEEK_END); fsize = ftell(file); rewind(file); buffer = (unsigned char *)malloc(fsize); if (!buffer) { LogError("malloc failed.\n"); goto END; } while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0) { websWriteBlock(wp, (cchar *)buffer, bytesRead); } END: if (buffer) { free(buffer); } if (file) { fclose(file); } } static bool AppRequestHandle(Webs *wp) { websSetStatus(wp, 200); websWriteHeaders(wp, UNKNOWN_LENGTH, 0); websWriteHeader(wp, "Content-Type", "text/plain"); websWriteEndHeaders(wp); gHttpHandle(wp->url, 0, response_handle, wp); websDone(wp); return 1; } static bool AppUploadHandle(Webs *wp) { WebsKey *s; WebsUpload *up; char *upfile = nullptr; websSetStatus(wp, 200); websWriteHeaders(wp, UNKNOWN_LENGTH, 0); websWriteHeader(wp, "Content-Type", "text/plain"); websWriteEndHeaders(wp); if (scaselessmatch(wp->method, "POST")) { for (s = hashFirst(wp->files); s; s = hashNext(wp->files, s)) { up = (WebsUpload *)s->content.value.symbol; // LogInfo("FILE: %s\r\n", s->name.value.string); // LogInfo("FILENAME=%s\r\n", up->filename); LogInfo("CLIENT=%s\r\n", up->clientFilename); // LogInfo("TYPE=%s\r\n", up->contentType); LogInfo("SIZE=%d\r\n", up->size); upfile = sfmt(GOAHEAD_UPLOAD_PATH "/%s", up->clientFilename); if (rename(up->filename, upfile) < 0) { error("Cannot rename uploaded file: %s to %s, errno %d", up->filename, upfile, errno); } LogInfo("Upload file:%s\n", upfile); wfree(upfile); upfile = nullptr; } gHttpHandle(wp->url, 0, response_handle, wp); } websDone(wp); return 1; } static bool AppGetThumbnail(Webs *wp) { LogInfo("AppGetThumbnail url = %s\n", wp->url); websSetStatus(wp, 200); websWriteHeaders(wp, UNKNOWN_LENGTH, 0); websWriteHeader(wp, "Content-Type", "image/jpeg"); websWriteEndHeaders(wp); gHttpHandle(wp->url, 0, get_thumbnail_handle, wp); websDone(wp); return 1; } StatusCode WebServerInit(const WebServerParam webParam) { CheckUploadDir(); websSetDebug(1); logSetPath("stdout:2"); const char *documents = GOAHEAD_DOCUMENTS_PATH; constexpr int BUF_LENGTH = 128; char routePath[BUF_LENGTH] = {0}; char authPath[BUF_LENGTH] = {0}; char listen[BUF_LENGTH] = {0}; snprintf(routePath, BUF_LENGTH, "%s/route.txt", GOAHEAD_CONFIG_FILE_PATH); snprintf(authPath, BUF_LENGTH, "%s/auth.txt", GOAHEAD_CONFIG_FILE_PATH); snprintf(listen, BUF_LENGTH, "%s:%d", webParam.mIp, webParam.mPort); LogInfo("GOAHEAD_CONFIG_FILE_PATH = %s\n", GOAHEAD_CONFIG_FILE_PATH); LogInfo("listen = %s\n", listen); initPlatform(); if (websOpen(documents, routePath) < 0) { LogError("Cannot initialize server. Exiting.\n"); return CreateStatusCode(STATUS_CODE_NOT_OK); } logHeader(); if (websLoad(authPath) < 0) { LogError("Cannot load %s", authPath); return CreateStatusCode(STATUS_CODE_NOT_OK); } if (websListen(listen) < 0) { return CreateStatusCode(STATUS_CODE_NOT_OK); } if (nullptr != webParam.mHttpRequestHandle) { gHttpHandle = webParam.mHttpRequestHandle; websDefineHandler("appRequestHandle", 0, AppRequestHandle, 0, 0); websAddRoute("/app", "appRequestHandle", 0); websDefineHandler("AppUploadHandle", 0, AppUploadHandle, 0, 0); websAddRoute("/upload", "AppUploadHandle", 0); websDefineHandler("AppGetThumbnail", 0, AppGetThumbnail, 0, 0); websAddRoute("/app/getthumbnail", "AppGetThumbnail", 0); } websServiceEvents(&finished); logmsg(1, "Instructed to exit\n"); websClose(); return CreateStatusCode(STATUS_CODE_OK); } StatusCode WebServerExit(void) { LogInfo("Stop goahead web server.\n"); finished = 1; return CreateStatusCode(STATUS_CODE_OK); } StatusCode WebServerUnInit(void) { LogInfo("WebServerUnInit.\n"); return CreateStatusCode(STATUS_CODE_OK); }