hewei.it hace 4 años
padre
commit
7e3e2267b2

+ 1 - 2
CMakeLists.txt

@@ -127,7 +127,6 @@ if(WIN32)
     endif()
 endif()
 
-
 if(ANDROID)
     set(LIBS ${LIBS} log)
 elseif(UNIX)
@@ -137,7 +136,6 @@ elseif(UNIX)
     endif()
 endif()
 
-
 if(APPLE)
     set(LIBS ${LIBS} "-framework CoreFoundation" "-framework Security")
 endif()
@@ -207,6 +205,7 @@ endif()
 
 if(BUILD_EXAMPLES)
     add_subdirectory(examples)
+    file(INSTALL etc DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
 endif()
 
 if(BUILD_UNITTEST)

+ 1 - 0
Makefile

@@ -172,6 +172,7 @@ unittest: prepare
 	$(CC)  -g -Wall -O0 -std=c99   -I. -Ibase            -o bin/connect_test      unittest/connect_test.c       base/hsocket.c base/htime.c
 	$(CC)  -g -Wall -O0 -std=c99   -I. -Ibase            -o bin/socketpair_test   unittest/socketpair_test.c    base/hsocket.c
 	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil  -o bin/hstring_test      unittest/hstring_test.cpp     cpputil/hstring.cpp
+	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil  -o bin/hpath_test        unittest/hpath_test.cpp       cpputil/hpath.cpp
 	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil  -o bin/ls                unittest/listdir_test.cpp     cpputil/hdir.cpp
 	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil  -o bin/ifconfig          unittest/ifconfig_test.cpp    cpputil/ifconfig.cpp
 	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil  -o bin/defer_test        unittest/defer_test.cpp

+ 1 - 0
Makefile.vars

@@ -37,6 +37,7 @@ UTIL_HEADERS =  util/base64.h\
 CPPUTIL_HEADERS = cpputil/hmap.h\
 				cpputil/hstring.h\
 				cpputil/hfile.h\
+				cpputil/hpath.h\
 				cpputil/hdir.h\
 				cpputil/hurl.h\
 				cpputil/hmain.h\

+ 1 - 0
README-CN.md

@@ -442,6 +442,7 @@ ab -c 100 -n 100000 http://127.0.0.1:8080/
 ```
 
 **libhv(port:8080) vs nginx(port:80)**
+
 ![libhv-vs-nginx.png](html/downloads/libhv-vs-nginx.png)
 
 以上测试结果可以在 [Github Actions](https://github.com/ithewei/libhv/actions/workflows/benchmark.yml) 中查看。

+ 1 - 0
README.md

@@ -437,6 +437,7 @@ ab -c 100 -n 100000 http://127.0.0.1:8080/
 ```
 
 **libhv(port:8080) vs nginx(port:80)**
+
 ![libhv-vs-nginx.png](html/downloads/libhv-vs-nginx.png)
 
 Above test results can be found on [Github Actions](https://github.com/ithewei/libhv/actions/workflows/benchmark.yml).

+ 20 - 0
base/hbase.c

@@ -240,6 +240,26 @@ int hv_rmdir_p(const char* dir) {
     return 0;
 }
 
+bool hv_exists(const char* path) {
+    return access(path, F_OK) == 0;
+}
+
+bool hv_isdir(const char* path) {
+    if (access(path, F_OK) != 0) return false;
+    struct stat st;
+    memset(&st, 0, sizeof(st));
+    stat(path, &st);
+    return S_ISDIR(st.st_mode);
+}
+
+bool hv_isfile(const char* path) {
+    if (access(path, F_OK) != 0) return false;
+    struct stat st;
+    memset(&st, 0, sizeof(st));
+    stat(path, &st);
+    return S_ISREG(st.st_mode);
+}
+
 bool getboolean(const char* str) {
     if (str == NULL) return false;
     int len = strlen(str);

+ 4 - 0
base/hbase.h

@@ -73,6 +73,10 @@ HV_EXPORT const char* hv_suffixname(const char* filename);
 HV_EXPORT int hv_mkdir_p(const char* dir);
 // rmdir -p
 HV_EXPORT int hv_rmdir_p(const char* dir);
+// path
+HV_EXPORT bool hv_exists(const char* path);
+HV_EXPORT bool hv_isdir(const char* path);
+HV_EXPORT bool hv_isfile(const char* path);
 
 // 1 y on yes true enable
 HV_EXPORT bool getboolean(const char* str);

+ 1 - 0
cmake/vars.cmake

@@ -38,6 +38,7 @@ set(CPPUTIL_HEADERS
     cpputil/hmap.h
     cpputil/hstring.h
     cpputil/hfile.h
+    cpputil/hpath.h
     cpputil/hdir.h
     cpputil/hurl.h
     cpputil/hmain.h

+ 4 - 0
cpputil/hfile.h

@@ -31,6 +31,10 @@ public:
         }
     }
 
+    bool isopen() {
+        return fp != NULL;
+    }
+
     size_t read(void* ptr, size_t len) {
         return fread(ptr, 1, len, fp);
     }

+ 98 - 0
cpputil/hpath.cpp

@@ -0,0 +1,98 @@
+#include "hpath.h"
+
+bool HPath::exists(const char* path) {
+    return access(path, F_OK) == 0;
+}
+
+bool HPath::isdir(const char* path) {
+    if (access(path, F_OK) != 0) return false;
+    struct stat st;
+    memset(&st, 0, sizeof(st));
+    stat(path, &st);
+    return S_ISDIR(st.st_mode);
+}
+
+bool HPath::isfile(const char* path) {
+    if (access(path, F_OK) != 0) return false;
+    struct stat st;
+    memset(&st, 0, sizeof(st));
+    stat(path, &st);
+    return S_ISREG(st.st_mode);
+}
+
+std::string HPath::basename(const std::string& filepath) {
+    std::string::size_type pos1 = filepath.find_last_not_of("/\\");
+    if (pos1 == std::string::npos) {
+        return "/";
+    }
+    std::string::size_type pos2 = filepath.find_last_of("/\\", pos1);
+    if (pos2 == std::string::npos) {
+        pos2 = 0;
+    } else {
+        pos2++;
+    }
+
+    return filepath.substr(pos2, pos1-pos2+1);
+}
+
+std::string HPath::dirname(const std::string& filepath) {
+    std::string::size_type pos1 = filepath.find_last_not_of("/\\");
+    if (pos1 == std::string::npos) {
+        return "/";
+    }
+    std::string::size_type pos2 = filepath.find_last_of("/\\", pos1);
+    if (pos2 == std::string::npos) {
+        return ".";
+    } else if (pos2 == 0) {
+        pos2 = 1;
+    }
+
+    return filepath.substr(0, pos2);
+}
+
+std::string HPath::filename(const std::string& filepath) {
+    std::string::size_type pos1 = filepath.find_last_of("/\\");
+    if (pos1 == std::string::npos) {
+        pos1 = 0;
+    } else {
+        pos1++;
+    }
+    std::string file = filepath.substr(pos1, -1);
+
+    std::string::size_type pos2 = file.find_last_of(".");
+    if (pos2 == std::string::npos) {
+        return file;
+    }
+    return file.substr(0, pos2);
+}
+
+std::string HPath::suffixname(const std::string& filepath) {
+    std::string::size_type pos1 = filepath.find_last_of("/\\");
+    if (pos1 == std::string::npos) {
+        pos1 = 0;
+    } else {
+        pos1++;
+    }
+    std::string file = filepath.substr(pos1, -1);
+
+    std::string::size_type pos2 = file.find_last_of(".");
+    if (pos2 == std::string::npos) {
+        return "";
+    }
+    return file.substr(pos2+1, -1);
+}
+
+std::string HPath::join(const std::string& dir, const std::string& filename) {
+    char separator = '/';
+#ifdef OS_WIN
+    if (dir.find_first_of("\\") != std::string::npos) {
+        separator = '\\';
+    }
+#endif
+    std::string filepath(dir);
+    if (dir[dir.length()-1] != separator) {
+        filepath += separator;
+    }
+    filepath += filename;
+    return filepath;
+}

+ 28 - 0
cpputil/hpath.h

@@ -0,0 +1,28 @@
+#ifndef HV_PATH_H_
+#define HV_PATH_H_
+
+#include <string> // for std::string
+
+#include "hexport.h"
+#include "hplatform.h" // for stat
+
+class HV_EXPORT HPath {
+public:
+    static bool exists(const char* path);
+    static bool isdir(const char* path);
+    static bool isfile(const char* path);
+
+    // filepath = /mnt/share/image/test.jpg
+    // basename = test.jpg
+    // dirname  = /mnt/share/image
+    // filename = test
+    // suffixname = jpg
+    static std::string basename(const std::string& str);
+    static std::string dirname(const std::string& str);
+    static std::string filename(const std::string& str);
+    static std::string suffixname(const std::string& str);
+
+    static std::string join(const std::string& dir, const std::string& filename);
+};
+
+#endif // HV_PATH_H_

+ 0 - 62
cpputil/hstring.cpp

@@ -133,65 +133,3 @@ string replace(const string& str, const string& find, const string& rep) {
     }
     return res;
 }
-
-string basename(const string& str) {
-    string::size_type pos1 = str.find_last_not_of("/\\");
-    if (pos1 == string::npos) {
-        return "/";
-    }
-    string::size_type pos2 = str.find_last_of("/\\", pos1);
-    if (pos2 == string::npos) {
-        pos2 = 0;
-    } else {
-        pos2++;
-    }
-
-    return str.substr(pos2, pos1-pos2+1);
-}
-
-string dirname(const string& str) {
-    string::size_type pos1 = str.find_last_not_of("/\\");
-    if (pos1 == string::npos) {
-        return "/";
-    }
-    string::size_type pos2 = str.find_last_of("/\\", pos1);
-    if (pos2 == string::npos) {
-        return ".";
-    } else if (pos2 == 0) {
-        pos2 = 1;
-    }
-
-    return str.substr(0, pos2);
-}
-
-string filename(const string& str) {
-    string::size_type pos1 = str.find_last_of("/\\");
-    if (pos1 == string::npos) {
-        pos1 = 0;
-    } else {
-        pos1++;
-    }
-    string file = str.substr(pos1, -1);
-
-    string::size_type pos2 = file.find_last_of(".");
-    if (pos2 == string::npos) {
-        return file;
-    }
-    return file.substr(0, pos2);
-}
-
-string suffixname(const string& str) {
-    string::size_type pos1 = str.find_last_of("/\\");
-    if (pos1 == string::npos) {
-        pos1 = 0;
-    } else {
-        pos1++;
-    }
-    string file = str.substr(pos1, -1);
-
-    string::size_type pos2 = file.find_last_of(".");
-    if (pos2 == string::npos) {
-        return "";
-    }
-    return file.substr(pos2+1, -1);
-}

+ 0 - 10
cpputil/hstring.h

@@ -52,14 +52,4 @@ HV_EXPORT string trimR(const string& str, const char* chars = SPACE_CHARS);
 HV_EXPORT string trim_pairs(const string& str, const char* pairs = PAIR_CHARS);
 HV_EXPORT string replace(const string& str, const string& find, const string& rep);
 
-// str=/mnt/share/image/test.jpg
-// basename=test.jpg
-// dirname=/mnt/share/image
-// filename=test
-// suffixname=jpg
-HV_EXPORT string basename(const string& str);
-HV_EXPORT string dirname(const string& str);
-HV_EXPORT string filename(const string& str);
-HV_EXPORT string suffixname(const string& str);
-
 #endif // HV_STRING_H_

+ 13 - 4
docs/API.md

@@ -114,6 +114,9 @@
 - hv_suffixname
 - hv_mkdir_p
 - hv_rmdir_p
+- hv_exists
+- hv_isdir
+- hv_isfile
 - getboolean
 - get_executable_path
 - get_executable_dir
@@ -257,16 +260,22 @@
 - split
 - splitKV
 - replace
-- basename
-- dirname
-- filename
-- suffixname
 - hv::to_string
 - hv::from_string
 
 ### hfile.h
 - class HFile
 
+### hpath.h
+- exists
+- isdir
+- isfile
+- basename
+- dirname
+- filename
+- suffixname
+- join
+
 ### hdir.h
 - listdir
 

+ 16 - 2
http/HttpMessage.h

@@ -35,6 +35,7 @@
 #include "hbase.h"
 #include "hstring.h"
 #include "hfile.h"
+#include "hpath.h"
 
 #include "httpdef.h"
 #include "http_content.h"
@@ -151,7 +152,7 @@ public:
         form[name] = FormData(NULL, filepath);
     }
 
-    int SaveFormFile(const char* name, const char* filepath) {
+    int SaveFormFile(const char* name, const char* path) {
         if (content_type != MULTIPART_FORM_DATA) {
             return HTTP_STATUS_BAD_REQUEST;
         }
@@ -159,8 +160,12 @@ public:
         if (formdata.content.empty()) {
             return HTTP_STATUS_BAD_REQUEST;
         }
+        std::string filepath(path);
+        if (HPath::isdir(path)) {
+            filepath = HPath::join(filepath, formdata.filename);
+        }
         HFile file;
-        if (file.open(filepath, "wb") != 0) {
+        if (file.open(filepath.c_str(), "wb") != 0) {
             return HTTP_STATUS_INTERNAL_SERVER_ERROR;
         }
         file.write(formdata.content.data(), formdata.content.size());
@@ -278,6 +283,15 @@ public:
         file.readall(body);
         return 200;
     }
+
+    int SaveFile(const char* filepath) {
+        HFile file;
+        if (file.open(filepath, "wb") != 0) {
+            return HTTP_STATUS_NOT_FOUND;
+        }
+        file.write(body.data(), body.size());
+        return 200;
+    }
 };
 
 #define DEFAULT_USER_AGENT "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"

+ 1 - 1
http/http_content.cpp

@@ -83,7 +83,7 @@ std::string dump_multipart(MultiPart& mp, const char* boundary) {
                     file.readall(form.content);
                 }
             }
-            snprintf(c_str, sizeof(c_str), "; filename=\"%s\"", basename(form.filename).c_str());
+            snprintf(c_str, sizeof(c_str), "; filename=\"%s\"", hv_basename(form.filename.c_str()));
             str += c_str;
             const char* suffix = strrchr(form.filename.c_str(), '.');
             if (suffix) {

+ 1 - 0
hv.h

@@ -33,6 +33,7 @@
 #include "hmap.h"       // <map>
 #include "hstring.h"    // <string>
 #include "hfile.h"
+#include "hpath.h"
 #include "hdir.h"
 #include "hurl.h"
 #include "hscope.h"

+ 1 - 0
scripts/test-coverage.sh

@@ -14,6 +14,7 @@ bin/rmdir_p 123/456
 
 bin/defer_test
 bin/hstring_test
+bin/hpath_test
 bin/hatomic_test
 bin/hatomic_cpp_test
 bin/hmutex_test

+ 1 - 0
scripts/unittest.sh

@@ -12,6 +12,7 @@ bin/rmdir_p 123/456
 
 bin/defer_test
 bin/hstring_test
+bin/hpath_test
 # bin/hatomic_test
 # bin/hatomic_cpp_test
 # bin/hthread_test

+ 4 - 0
unittest/CMakeLists.txt

@@ -32,6 +32,9 @@ target_include_directories(socketpair_test PRIVATE .. ../base)
 add_executable(hstring_test hstring_test.cpp ../cpputil/hstring.cpp)
 target_include_directories(hstring_test PRIVATE .. ../base ../cpputil)
 
+add_executable(hpath_test hpath_test.cpp ../cpputil/hpath.cpp)
+target_include_directories(hpath_test PRIVATE .. ../base ../cpputil)
+
 add_executable(ls listdir_test.cpp ../cpputil/hdir.cpp)
 target_include_directories(ls PRIVATE .. ../base ../cpputil)
 
@@ -81,6 +84,7 @@ add_custom_target(unittest DEPENDS
     connect_test
     socketpair_test
     hstring_test
+    hpath_test
     ls
     ifconfig
     defer_test

+ 15 - 0
unittest/hpath_test.cpp

@@ -0,0 +1,15 @@
+#include "hpath.h"
+
+int main(int argc, char** argv) {
+    std::string filepath = HPath::join("/mnt/share/image", "test.jpg");
+    std::string basename = HPath::basename(filepath);
+    std::string dirname = HPath::dirname(filepath);
+    std::string filename = HPath::filename(filepath);
+    std::string suffixname = HPath::suffixname(filepath);
+    printf("filepath = %s\n", filepath.c_str());
+    printf("basename = %s\n", basename.c_str());
+    printf("dirname  = %s\n", dirname.c_str());
+    printf("filename = %s\n", filename.c_str());
+    printf("suffixname = %s\n", suffixname.c_str());
+    return 0;
+}

+ 0 - 11
unittest/hstring_test.cpp

@@ -40,16 +40,5 @@ int main(int argc, char** argv) {
     std::string str11 = replace(str10, "{{title}}", "Home");
     printf("replace %s\n", str11.c_str());
 
-    std::string filepath("/mnt/share/image/test.jpg");
-    std::string base = basename(filepath);
-    std::string dir = dirname(filepath);
-    std::string file = filename(filepath);
-    std::string suffix = suffixname(filepath);
-    printf("filepath %s\n", filepath.c_str());
-    printf("basename %s\n", base.c_str());
-    printf("dirname %s\n", dir.c_str());
-    printf("filename %s\n", file.c_str());
-    printf("suffixname %s\n", suffix.c_str());
-
     return 0;
 }