ithewei 5 years ago
parent
commit
e756f90823

+ 2 - 1
README.md

@@ -100,7 +100,8 @@ bin/curl -v localhost:8080/v1/api/echo -d "hello,world!"
 bin/curl -v localhost:8080/v1/api/query?page_no=1\&page_size=10
 bin/curl -v localhost:8080/v1/api/kv   -H "Content-Type:application/x-www-form-urlencoded" -d 'user=admin&pswd=123456'
 bin/curl -v localhost:8080/v1/api/json -H "Content-Type:application/json" -d '{"user":"admin","pswd":"123456"}'
-bin/curl -v localhost:8080/v1/api/form -F "file=@LICENSE"
+bin/curl -v localhost:8080/v1/api/form -F "user=admin pswd=123456"
+bin/curl -v localhost:8080/v1/api/upload -F "file=@LICENSE"
 
 bin/curl -v localhost:8080/v1/api/test -H "Content-Type:application/x-www-form-urlencoded" -d 'bool=1&int=123&float=3.14&string=hello'
 bin/curl -v localhost:8080/v1/api/test -H "Content-Type:application/json" -d '{"bool":true,"int":123,"float":3.14,"string":"hello"}'

+ 26 - 24
base/hlog.c

@@ -47,6 +47,7 @@ struct logger_s {
     FILE*               fp_;
     char                cur_logfile[256];
     time_t              last_logfile_ts;
+    int                 can_write_cnt;
 
     hmutex_t            mutex_; // thread-safe
 };
@@ -65,6 +66,7 @@ static void logger_init(logger_t* logger) {
     logger->enable_fsync = 1;
     logger_set_file(logger, DEFAULT_LOG_FILE);
     logger->last_logfile_ts = 0;
+    logger->can_write_cnt = -1;
     hmutex_init(&logger->mutex_);
 }
 
@@ -149,7 +151,7 @@ static void ts_logfile(const char* filepath, time_t ts, char* buf, int len) {
 
 static FILE* shift_logfile(logger_t* logger) {
     time_t ts_now = time(NULL);
-    int interval_days = logger->last_logfile_ts == 0 ? 0 : (ts_now+s_gmtoff) / SECONDS_PER_DAY - (logger->last_logfile_ts+s_gmtoff) / SECONDS_PER_DAY;;
+    int interval_days = logger->last_logfile_ts == 0 ? 0 : (ts_now+s_gmtoff) / SECONDS_PER_DAY - (logger->last_logfile_ts+s_gmtoff) / SECONDS_PER_DAY;
     if (logger->fp_ == NULL || interval_days > 0) {
         // close old logfile
         if (logger->fp_) {
@@ -161,9 +163,9 @@ static FILE* shift_logfile(logger_t* logger) {
         }
 
         if (logger->remain_days >= 0) {
+            char rm_logfile[256] = {0};
             if (interval_days >= logger->remain_days) {
                 // remove [today-interval_days, today-remain_days] logfile
-                char rm_logfile[256] = {0};
                 for (int i = interval_days; i >= logger->remain_days; --i) {
                     time_t ts_rm  = ts_now - i * SECONDS_PER_DAY;
                     ts_logfile(logger->filepath, ts_rm, rm_logfile, sizeof(rm_logfile));
@@ -172,7 +174,6 @@ static FILE* shift_logfile(logger_t* logger) {
             }
             else {
                 // remove today-remain_days logfile
-                char rm_logfile[256] = {0};
                 time_t ts_rm  = ts_now - logger->remain_days * SECONDS_PER_DAY;
                 ts_logfile(logger->filepath, ts_rm, rm_logfile, sizeof(rm_logfile));
                 remove(rm_logfile);
@@ -187,15 +188,14 @@ static FILE* shift_logfile(logger_t* logger) {
         logger->last_logfile_ts = ts_now;
     }
 
-    // ftruncate
-    // NOTE; estimate can_write_cnt to avoid frequent fseek/ftell
-    static int s_can_write_cnt = 0;
-    if (logger->fp_ && --s_can_write_cnt < 0) {
+    // NOTE: estimate can_write_cnt to avoid frequent fseek/ftell
+    if (logger->fp_ && --logger->can_write_cnt < 0) {
         fseek(logger->fp_, 0, SEEK_END);
         long filesize = ftell(logger->fp_);
         if (filesize > logger->max_filesize) {
             fclose(logger->fp_);
             logger->fp_ = NULL;
+            // ftruncate
             logger->fp_ = fopen(logger->cur_logfile, "w");
             // reopen with O_APPEND for multi-processes
             if (logger->fp_) {
@@ -204,7 +204,7 @@ static FILE* shift_logfile(logger_t* logger) {
             }
         }
         else {
-            s_can_write_cnt = (logger->max_filesize - filesize) / logger->bufsize;
+            logger->can_write_cnt = (logger->max_filesize - filesize) / logger->bufsize;
         }
     }
 
@@ -215,21 +215,6 @@ int logger_print(logger_t* logger, int level, const char* fmt, ...) {
     if (level < logger->level)
         return -10;
 
-    const char* pcolor = "";
-    const char* plevel = "";
-#define XXX(id, str, clr) \
-    case id: plevel = str; pcolor = clr; break;
-
-    switch (level) {
-        LOG_LEVEL_MAP(XXX)
-    }
-#undef XXX
-
-    if (!logger->enable_color) {
-        pcolor = "";
-    }
-
-    // lock logger->buf
     int year,month,day,hour,min,sec,ms;
 #ifdef _WIN32
     SYSTEMTIME tm;
@@ -255,12 +240,29 @@ int logger_print(logger_t* logger, int level, const char* fmt, ...) {
     sec      = tm->tm_sec;
     ms       = tv.tv_usec/1000;
 #endif
+
+    const char* pcolor = "";
+    const char* plevel = "";
+#define XXX(id, str, clr) \
+    case id: plevel = str; pcolor = clr; break;
+
+    switch (level) {
+        LOG_LEVEL_MAP(XXX)
+    }
+#undef XXX
+
+    if (!logger->enable_color) {
+        pcolor = "";
+    }
+
+    // lock logger->buf
     hmutex_lock(&logger->mutex_);
     char* buf = logger->buf;
     int bufsize = logger->bufsize;
     int len = snprintf(buf, bufsize, "%s[%04d-%02d-%02d %02d:%02d:%02d.%03d][%s] ",
         pcolor,
-        year, month, day, hour, min, sec, ms, plevel);
+        year, month, day, hour, min, sec, ms,
+        plevel);
 
     va_list ap;
     va_start(ap, fmt);

+ 19 - 0
examples/httpd/http_api_test.h

@@ -11,6 +11,7 @@
     XXX("/kv",      POST,   http_api_kv)        \
     XXX("/json",    POST,   http_api_json)      \
     XXX("/form",    POST,   http_api_form)      \
+    XXX("/upload",  POST,   http_api_upload)    \
     XXX("/grpc",    POST,   http_api_grpc)      \
     \
     XXX("/test",    POST,   http_api_test)      \
@@ -86,6 +87,24 @@ inline int http_api_form(HttpRequest* req, HttpResponse* res) {
     return 0;
 }
 
+inline int http_api_upload(HttpRequest* req, HttpResponse* res) {
+    if (req->content_type != MULTIPART_FORM_DATA) {
+        res->status_code = HTTP_STATUS_BAD_REQUEST;
+        return 0;
+    }
+    FormData file = req->form["file"];
+    string filepath("html/uploads/");
+    filepath += file.filename;
+    FILE* fp = fopen(filepath.c_str(), "w");
+    if (fp) {
+        hlogi("Save as %s", filepath.c_str());
+        fwrite(file.content.data(), 1, file.content.size(), fp);
+        fclose(fp);
+    }
+    response_status(res, 0, "OK");
+    return 0;
+}
+
 inline int http_api_grpc(HttpRequest* req, HttpResponse* res) {
     if (req->content_type != APPLICATION_GRPC) {
         res->status_code = HTTP_STATUS_BAD_REQUEST;

+ 4 - 1
html/downloads/scripts/getting_started.sh

@@ -35,7 +35,10 @@ read -n1
 bin/curl -v localhost:8080/v1/api/json -H "Content-Type:application/json" -d '{"user":"admin","pswd":"123456"}'
 
 read -n1
-bin/curl -v localhost:8080/v1/api/form -F "file=@LICENSE"
+bin/curl -v localhost:8080/v1/api/form -F "user=admin pswd=123456"
+
+read -n1
+bin/curl -v localhost:8080/v1/api/upload -F "file=@LICENSE"
 
 read -n1
 bin/curl -v localhost:8080/v1/api/test -H "Content-Type:application/x-www-form-urlencoded" -d 'bool=1&int=123&float=3.14&string=hello'

+ 1 - 0
html/uploads/upload.sh

@@ -0,0 +1 @@
+bin/curl -v localhost:8080/v1/api/upload -F "file=@LICENSE"

+ 3 - 1
http/HttpMessage.cpp

@@ -342,7 +342,9 @@ int HttpMessage::ParseBody() {
             return false;
         }
         boundary += strlen("boundary=");
-        return parse_multipart(body, form, boundary);
+        string strBoundary(boundary);
+        strBoundary = trim_pairs(strBoundary, "\"\"\'\'");
+        return parse_multipart(body, form, strBoundary.c_str());
     }
     case X_WWW_FORM_URLENCODED:
         return parse_query_params(body.c_str(), kv);

+ 5 - 4
http/http_content.cpp

@@ -141,7 +141,8 @@ struct multipart_parser_userdata {
                 StringList kv = split(trim(str, " "), '=');
                 if (kv.size() == 2) {
                     const char* key = kv.begin()->c_str();
-                    const char* value = trim_pairs(*(kv.begin()+1), "\"\"").c_str();
+                    string value = *(kv.begin() + 1);
+                    value = trim_pairs(value, "\"\"\'\'");
                     if (strcmp(key, "name") == 0) {
                         name = value;
                     }
@@ -169,21 +170,21 @@ static int on_header_field(multipart_parser* parser, const char *at, size_t leng
     multipart_parser_userdata* userdata = (multipart_parser_userdata*)multipart_parser_get_data(parser);
     userdata->handle_header();
     userdata->state = MP_HEADER_FIELD;
-    userdata->header_field.insert(userdata->header_field.size(), at, length);
+    userdata->header_field.append(at, length);
     return 0;
 }
 static int on_header_value(multipart_parser* parser, const char *at, size_t length) {
     //printf("on_header_value:%.*s\n", (int)length, at);
     multipart_parser_userdata* userdata = (multipart_parser_userdata*)multipart_parser_get_data(parser);
     userdata->state = MP_HEADER_VALUE;
-    userdata->header_value.insert(userdata->header_value.size(), at, length);
+    userdata->header_value.append(at, length);
     return 0;
 }
 static int on_part_data(multipart_parser* parser, const char *at, size_t length) {
     //printf("on_part_data:%.*s\n", (int)length, at);
     multipart_parser_userdata* userdata = (multipart_parser_userdata*)multipart_parser_get_data(parser);
     userdata->state = MP_PART_DATA;
-    userdata->part_data.insert(userdata->part_data.size(), at, length);
+    userdata->part_data.append(at, length);
     return 0;
 }
 static int on_part_data_begin(multipart_parser* parser) {

+ 2 - 1
readme_cn.md

@@ -99,7 +99,8 @@ bin/curl -v localhost:8080/v1/api/echo -d "hello,world!"
 bin/curl -v localhost:8080/v1/api/query?page_no=1\&page_size=10
 bin/curl -v localhost:8080/v1/api/kv   -H "Content-Type:application/x-www-form-urlencoded" -d 'user=admin&pswd=123456'
 bin/curl -v localhost:8080/v1/api/json -H "Content-Type:application/json" -d '{"user":"admin","pswd":"123456"}'
-bin/curl -v localhost:8080/v1/api/form -F "file=@LICENSE"
+bin/curl -v localhost:8080/v1/api/form -F "user=admin pswd=123456"
+bin/curl -v localhost:8080/v1/api/upload -F "file=@LICENSE"
 
 bin/curl -v localhost:8080/v1/api/test -H "Content-Type:application/x-www-form-urlencoded" -d 'bool=1&int=123&float=3.14&string=hello'
 bin/curl -v localhost:8080/v1/api/test -H "Content-Type:application/json" -d '{"bool":true,"int":123,"float":3.14,"string":"hello"}'