Эх сурвалжийг харах

Add error page & Fix project structure

xcbosa-itx 2 жил өмнө
parent
commit
08df05d41d

BIN
.DS_Store


+ 9 - 1
CMakeLists.txt

@@ -3,4 +3,12 @@ project(FRPCWebUI)
 
 set(CMAKE_CXX_STANDARD 17)
 
-add_executable(FRPCWebUI main.cpp httpserver/HTTPServer.cpp httpserver/HTTPServer.h webui.h httpserver/ClientConnection.cpp httpserver/ClientConnection.h utils/ResponseData.cpp utils/ResponseData.h utils/FileResponseData.cpp utils/FileResponseData.h utils/FileReader.cpp webuiconf.h)
+aux_source_directory(. DIR_SRCS)
+
+add_subdirectory(utils)
+add_subdirectory(httpserver)
+
+add_executable(FRPCWebUI ${DIR_SRCS})
+
+find_package(Threads)
+target_link_libraries(FRPCWebUI HttpServerUtils HttpServer ${CMAKE_THREAD_LIBS_INIT})

+ 2 - 2
data/html/error.html

@@ -2,10 +2,10 @@
 <html lang="en">
 <head>
     <meta charset="UTF-8">
-    <title>Error {{ERR_CODE}}</title>
+    <title>Error {{errorCode}}</title>
 </head>
 <body>
-    <p style="text-align: center">{{ERR_MSG}} <br>({{ERR_CODE}})<br/></p>
+    <p style="text-align: center">{{errorMessage}} ({{errorCode}})</p>
     <p style="text-align: center">FRPCWebUI / XCHttpServer 1.0</p>
 </body>
 </html>

+ 5 - 0
httpserver/CMakeLists.txt

@@ -0,0 +1,5 @@
+set(CMAKE_CXX_STANDARD 17)
+
+aux_source_directory(. DIR_SRC)
+
+add_library(HttpServer ${DIR_SRC} http-server.h)

+ 62 - 6
httpserver/ClientConnection.cpp

@@ -3,7 +3,8 @@
 //
 
 #include "ClientConnection.h"
-#include "../webui.h"
+
+using namespace std;
 
 namespace xc {
     namespace httpserver {
@@ -11,20 +12,75 @@ namespace xc {
         ClientConnection::ClientConnection(int sockFd, struct sockaddr_in address) {
             this->sockFd = sockFd;
             this->address = address;
+            this->clRead = nullptr;
+            this->clWrite = nullptr;
+            this->requestBuff = nullptr;
         }
 
         void ClientConnection::workAndDestroy() {
-            thread(workLoop);
+            thread(&ClientConnection::workLoop, this).detach();
         }
 
         void ClientConnection::workLoop() {
             ::FILE *clRead = fdopen(this->sockFd, "r");
             ::FILE *clWrite = fdopen(dup(this->sockFd), "w");
-            char smallBuf[smallBuffSize];
-            ::fgets(smallBuf, smallBuffSize, clRead);
-            if (::strstr(smallBuf, "HTTP/") == NULL) {
-                
+            this->clRead = clRead;
+            this->clWrite = clWrite;
+            char *requestBuff = (char *)::malloc(urlRequestBuffSize);
+            this->requestBuff = requestBuff;
+            ::fgets(requestBuff, urlRequestBuffSize, clRead);
+
+            if (::strstr(requestBuff, "HTTP/") == NULL) {
+                conf::errorPage400.writeTo(clWrite);
+                cleanUpAndDestroy();
+                return;
+            }
+
+            string method, url;
+
+            char *ptr, *p;
+            ptr = strtok_r(requestBuff, " ", &p);
+            if (ptr != nullptr) {
+                method = string(ptr);
+                ptr = strtok_r(NULL, " ", &p);
+                if (ptr != nullptr) {
+                    url = string(ptr);
+                }
+            }
+
+            if (method == "GET1") {
+
+            } else if (method == "POST1") {
+
+            } else {
+                conf::errorPage.applyReplacements(400, {
+                    Replacement("errorCode", "400"),
+                    Replacement("errorMessage", "未知的协议 " + method)
+                }).writeTo(clWrite);
+                cleanUpAndDestroy();
+                return;
+            }
+
+            ResponseData(200, string(requestBuff)).writeTo(clWrite);
+            cleanUpAndDestroy();
+            return;
+        }
+
+        void ClientConnection::cleanUpAndDestroy() {
+            if (this->clRead) {
+                ::fclose(this->clRead);
+                this->clRead = nullptr;
+            }
+            if (this->clWrite) {
+                ::fclose(this->clWrite);
+                this->clWrite = nullptr;
+            }
+            if (this->requestBuff) {
+                ::free(this->requestBuff);
+                this->requestBuff = nullptr;
             }
+            ::close(this->sockFd);
+            delete this;
         }
 
     } // xc

+ 8 - 8
httpserver/ClientConnection.h

@@ -2,13 +2,11 @@
 // Created by xcbosa on 2023/1/28.
 //
 
-#ifndef FRPCWEBUI_CLIENTCONNECTION_H
-#define FRPCWEBUI_CLIENTCONNECTION_H
+#pragma once
 
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <unistd.h>
+#include "httpserver-private.h"
+
+using namespace std;
 
 namespace xc {
     namespace httpserver {
@@ -20,10 +18,12 @@ namespace xc {
         private:
             int sockFd;
             struct sockaddr_in address;
+            ::FILE *clRead;
+            ::FILE *clWrite;
+            char *requestBuff;
             void workLoop();
+            void cleanUpAndDestroy();
         };
 
     } // xc
 } // httpserver
-
-#endif //FRPCWEBUI_CLIENTCONNECTION_H

+ 5 - 7
httpserver/HTTPServer.cpp

@@ -4,10 +4,8 @@
 
 #include "HTTPServer.h"
 #include "ClientConnection.h"
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <unistd.h>
+
+using namespace std;
 
 namespace xc {
     namespace httpserver {
@@ -25,14 +23,14 @@ namespace xc {
             serverAddress.sin_addr.s_addr = INADDR_ANY;
             bzero(&(serverAddress.sin_zero), 8);
             if (::bind(this->serverSocketFd, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr)) == -1) {
-                cerr << "Unable to bind port" << this->bindPort << endl;
+                cerr << "Unable to bind port " << this->bindPort << endl;
                 assertx(0, "");
             }
             if (listen(this->serverSocketFd, 5) == -1) {
-                cerr << "Unable to bind port" << this->bindPort << endl;
+                cerr << "Unable to bind port " << this->bindPort << endl;
                 assertx(0, "");
             }
-            cout << "Bind to" << this->bindPort << endl;
+            cout << "Bind to 0.0.0.0:" << this->bindPort << endl;
             while (true) {
                 struct sockaddr_in clientAddress;
                 socklen_t clientAddressSize = sizeof(clientAddress);

+ 4 - 5
httpserver/HTTPServer.h

@@ -2,10 +2,11 @@
 // Created by xcbosa on 2023/1/28.
 //
 
-#ifndef FRPCWEBUI_HTTPSERVER_H
-#define FRPCWEBUI_HTTPSERVER_H
+#pragma once
 
-#include "../webui.h"
+#include "httpserver-private.h"
+
+using namespace std;
 
 namespace xc {
     namespace httpserver {
@@ -21,5 +22,3 @@ namespace xc {
 
     } // xc
 } // httpserver
-
-#endif //FRPCWEBUI_HTTPSERVER_H

+ 8 - 0
httpserver/http-server.h

@@ -0,0 +1,8 @@
+//
+// Created by xcbosa on 2023/1/28.
+//
+
+#pragma once
+
+#include "HTTPServer.h"
+#include "ClientConnection.h"

+ 21 - 0
httpserver/httpserver-private.h

@@ -0,0 +1,21 @@
+//
+// Created by xcbosa on 2023/1/28.
+//
+
+#pragma once
+
+#include <vector>
+#include <map>
+#include <string>
+#include <iostream>
+#include <thread>
+#include <mutex>
+#include <sstream>
+#include <fstream>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include "../webui.h"
+
+using namespace std;

+ 12 - 0
main.cpp

@@ -1,6 +1,18 @@
 #include <iostream>
+#include "webui.h"
+
+#include "httpserver/http-server.h"
+#include "utils/utils.h"
+
+using namespace xc::httpserver;
 
 int main() {
     std::cout << "Hello, World!" << std::endl;
+    HTTPServer server(8192);
+    thread serverThread([&server] {
+        server.serverLoop();
+    });
+    serverThread.detach();
+    while (true) ;
     return 0;
 }

+ 5 - 0
utils/CMakeLists.txt

@@ -0,0 +1,5 @@
+set(CMAKE_CXX_STANDARD 17)
+
+aux_source_directory(. DIR_SRC)
+
+add_library(HttpServerUtils ${DIR_SRC})

+ 3 - 3
utils/FileReader.cpp

@@ -2,9 +2,9 @@
 // Created by xcbosa on 2023/1/28.
 //
 
-#include "../webui.h"
-#include <sstream>
-#include <fstream>
+#include "utils-private.h"
+
+using namespace std;
 
 namespace xc::utils {
     string contentsOfTextFile(string filePath) {

+ 30 - 4
utils/FileResponseData.cpp

@@ -4,6 +4,8 @@
 
 #include "FileResponseData.h"
 
+using namespace std;
+
 namespace xc {
     namespace utils {
         Replacement::Replacement(string replace, string with) {
@@ -31,19 +33,43 @@ namespace xc {
             this->setBody(contentsOfTextFile(filePath));
         }
 
+        string& replace_all(string& src, const string& old_value, const string& new_value) {
+            for (string::size_type pos(0); pos != string::npos; pos += new_value.length()) {
+                if ((pos = src.find(old_value, pos)) != string::npos) {
+                    src.replace(pos, old_value.length(), new_value);
+                }
+                else break;
+            }
+            return src;
+        }
+
         void FileResponseData::setFilePath(string filePath, vector<Replacement> replacements) {
             this->filePath = filePath;
             string str = contentsOfTextFile(filePath);
             for (auto replacement : replacements) {
                 string fullReplaceText = "{{" + replacement.replace + "}}";
-                string::size_type pos = 0;
-                while ((pos = str.find(fullReplaceText)) != string::npos) {
-                    str.replace(pos, fullReplaceText.length(), replacement.with);
-                }
+                replace_all(str, fullReplaceText, replacement.with);
             }
             this->setBody(str);
         }
 
+        IncompleteFileResponseData::IncompleteFileResponseData(FileResponseData holdData): holdData(holdData) { }
+
+        FileResponseData IncompleteFileResponseData::applyReplacements(vector<Replacement> replacements) const {
+            return applyReplacements(this->holdData.getStatusCode(), replacements);
+        }
+
+        FileResponseData IncompleteFileResponseData::applyReplacements(int statusCode, vector<Replacement> replacements) const {
+            FileResponseData responseData(this->holdData);
+            responseData.setStatusCode(statusCode);
+            string oriBody = responseData.getBody();
+            for (auto replacement : replacements) {
+                string fullReplaceText = "{{" + replacement.replace + "}}";
+                replace_all(oriBody, fullReplaceText, replacement.with);
+            }
+            responseData.setBody(oriBody);
+            return responseData;
+        }
 
     } // xc
 } // utils

+ 13 - 4
utils/FileResponseData.h

@@ -2,11 +2,13 @@
 // Created by xcbosa on 2023/1/28.
 //
 
-#ifndef FRPCWEBUI_FILERESPONSEDATA_H
-#define FRPCWEBUI_FILERESPONSEDATA_H
+#pragma once
 
+#include "utils-private.h"
 #include "ResponseData.h"
 
+using namespace std;
+
 namespace xc {
     namespace utils {
 
@@ -28,7 +30,14 @@ namespace xc {
             string filePath;
         };
 
+        class IncompleteFileResponseData {
+        public:
+            IncompleteFileResponseData(FileResponseData holdData);
+            FileResponseData applyReplacements(vector<Replacement> replacements) const;
+            FileResponseData applyReplacements(int statusCode, vector<Replacement> replacements) const;
+        private:
+            FileResponseData holdData;
+        };
+
     } // xc
 } // utils
-
-#endif //FRPCWEBUI_FILERESPONSEDATA_H

+ 4 - 2
utils/ResponseData.cpp

@@ -4,6 +4,8 @@
 
 #include "ResponseData.h"
 
+using namespace std;
+
 namespace xc {
     namespace utils {
         ResponseData::ResponseData(int statusCode, string body): headers() {
@@ -39,7 +41,7 @@ namespace xc {
             this->setHeader("Content-Type", mimeType);
         }
 
-        int ResponseData::getStatusCode() {
+        int ResponseData::getStatusCode() const {
             return this->statusCode;
         }
 
@@ -51,7 +53,7 @@ namespace xc {
             return this->body;
         }
 
-        void ResponseData::writeTo(::FILE *fp) {
+        void ResponseData::writeTo(::FILE *fp) const {
             ::fprintf(fp, "HTTP/1.0 %d FRPCWebUI\r\n", this->statusCode);
             for (auto item : this->headers) {
                 ::fprintf(fp, "%s: %s\r\n", item.first.c_str(), item.second.c_str());

+ 6 - 7
utils/ResponseData.h

@@ -2,10 +2,11 @@
 // Created by xcbosa on 2023/1/28.
 //
 
-#ifndef FRPCWEBUI_RESPONSEDATA_H
-#define FRPCWEBUI_RESPONSEDATA_H
+#pragma once
 
-#include "../webui.h"
+#include "utils-private.h"
+
+using namespace std;
 
 namespace xc {
     namespace utils {
@@ -19,10 +20,10 @@ namespace xc {
             string getHeader(string headerName);
             void setContentType(string mimeType);
             void setStatusCode(int statusCode);
-            int getStatusCode();
+            int getStatusCode() const;
             void setBody(string body);
             string getBody();
-            void writeTo(::FILE *fp);
+            void writeTo(::FILE *fp) const;
         private:
             int statusCode;
             map<string, string> headers;
@@ -31,5 +32,3 @@ namespace xc {
 
     } // xc
 } // utils
-
-#endif //FRPCWEBUI_RESPONSEDATA_H

+ 20 - 0
utils/utils-private.h

@@ -0,0 +1,20 @@
+//
+// Created by xcbosa on 2023/1/28.
+//
+
+#pragma once
+
+#include <vector>
+#include <map>
+#include <string>
+#include <iostream>
+#include <thread>
+#include <mutex>
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+
+namespace xc::utils {
+    string contentsOfTextFile(string filePath);
+}

+ 14 - 0
utils/utils.h

@@ -0,0 +1,14 @@
+//
+// Created by xcbosa on 2023/1/28.
+//
+
+#pragma once
+
+#include "ResponseData.h"
+#include "FileResponseData.h"
+
+using namespace std;
+
+namespace xc::utils {
+    string contentsOfTextFile(string filePath);
+}

+ 2 - 6
webui.h

@@ -2,8 +2,7 @@
 // Created by xcbosa on 2023/1/28.
 //
 
-#ifndef FRPCWEBUI_WEBUI_H
-#define FRPCWEBUI_WEBUI_H
+#pragma once
 
 #include <vector>
 #include <map>
@@ -19,12 +18,9 @@ using namespace std;
     if (!(expr)) { std::cerr << message << std::endl; exit(-1); }
 
 namespace xc {
-    constexpr int smallBuffSize = 32;
+    constexpr int urlRequestBuffSize = 65536;
 
     namespace utils {
         string contentsOfTextFile(string filePath);
     }
 }
-
-
-#endif //FRPCWEBUI_WEBUI_H

+ 13 - 15
webuiconf.h

@@ -2,31 +2,29 @@
 // Created by xcbosa on 2023/1/28.
 //
 
-#ifndef FRPCWEBUI_WEBUICONF_H
-#define FRPCWEBUI_WEBUICONF_H
+#pragma once
 
 #include <vector>
-#include "utils/FileResponseData.h"
+#include "utils/utils.h"
 
 using namespace std;
+using namespace xc::utils;
 
 namespace xc::conf {
-    using namespace utils;
+    const IncompleteFileResponseData errorPage(FileResponseData(500, "html/error.html", "text/html"));
 
-    const FileResponseData errorPage400(400, "html/error.html", "text/html", {
-        Replacement("{{ERR_MSG}}", "请求格式错误,无法解析请求"),
-        Replacement("{{ERR_CODE}}", "400")
+    const auto errorPage400 = errorPage.applyReplacements(400, {
+        Replacement("errorMessage", "请求格式错误,无法解析请求"),
+        Replacement("errorCode", "400")
     });
 
-    const FileResponseData errorPage404(404, "html/error.html", "text/html", {
-        Replacement("{{ERR_MSG}}", "不存在指定的资源"),
-        Replacement("{{ERR_CODE}}", "404")
+    const auto errorPage404 = errorPage.applyReplacements(404, {
+        Replacement("errorMessage", "不存在指定的资源"),
+        Replacement("errorCode", "404")
     });
 
-    const FileResponseData errorPage500(500, "html/error.html", "text/html", {
-        Replacement("{{ERR_MSG}}", "服务器内部错误,可能是服务器访问量过大,请稍后重试"),
-        Replacement("{{ERR_CODE}}", "500")
+    const auto errorPage500 = errorPage.applyReplacements(500, {
+        Replacement("errorMessage", "服务器内部错误,可能是服务器访问量过大,请稍后重试"),
+        Replacement("errorCode", "500")
     });
 }
-
-#endif //FRPCWEBUI_WEBUICONF_H