/** * @brief settings_init Init the setting with default values. */ static void settings_init(void) { settings.L = NULL; settings.is_daemon = 0; str_lcpy(settings.ip, "0.0.0.0", sizeof(settings.ip)); settings.port = 4869; settings.num_threads = get_cpu_cores(); /* N workers */ settings.backlog = 1024; settings.max_keepalives = 1; settings.retry = 3; str_lcpy(settings.version, STR(PROJECT_VERSION), sizeof(settings.version)); snprintf(settings.server_name, 128, "zimg/%s", settings.version); settings.headers = NULL; settings.etag = 0; settings.up_access = NULL; settings.down_access = NULL; settings.admin_access = NULL; settings.cache_on = 0; str_lcpy(settings.cache_ip, "127.0.0.1", sizeof(settings.cache_ip)); settings.cache_port = 11211; settings.log_level = 6; str_lcpy(settings.log_name, "./log/zimg.log", sizeof(settings.log_name)); str_lcpy(settings.root_path, "./www/index.html", sizeof(settings.root_path)); str_lcpy(settings.admin_path, "./www/admin.html", sizeof(settings.admin_path)); settings.disable_args = 0; settings.disable_type = 0; settings.disable_zoom_up = 0; settings.script_on = 0; settings.script_name[0] = '\0'; str_lcpy(settings.format, "none", sizeof(settings.format)); settings.quality = 75; settings.mode = 1; settings.save_new = 1; settings.max_size = 10485760; str_lcpy(settings.img_path, "./img", sizeof(settings.img_path)); str_lcpy(settings.beansdb_ip, "127.0.0.1", sizeof(settings.beansdb_ip)); settings.beansdb_port = 7905; str_lcpy(settings.ssdb_ip, "127.0.0.1", sizeof(settings.ssdb_ip)); settings.ssdb_port = 6379; multipart_parser_settings *callbacks = (multipart_parser_settings *)malloc(sizeof(multipart_parser_settings)); memset(callbacks, 0, sizeof(multipart_parser_settings)); //callbacks->on_header_field = on_header_field; callbacks->on_header_value = on_header_value; callbacks->on_chunk_data = on_chunk_data; settings.mp_set = callbacks; settings.get_img = NULL; settings.info_img = NULL; settings.admin_img = NULL; }
/** * @brief find_cache Connect to a memcached server and find a key's value. * * @param memc The connection to beansdb. * @param key The string of the key you want to find. * @param value It contains the string of the key's value. * * @return 1 for success and -1 for fail. */ int find_cache(memcached_st *memc, const char *key, char *value) { int rst = -1; if(memc == NULL) return rst; size_t valueLen; uint32_t flags; memcached_return rc; char *pvalue = memcached_get(memc, key, strlen(key), &valueLen, &flags, &rc); if (rc == MEMCACHED_SUCCESS) { LOG_PRINT(LOG_DEBUG, "Cache Find Key[%s] Value: %s", key, pvalue); str_lcpy(value, pvalue, sizeof(value)); free(pvalue); rst = 1; } else if (rc == MEMCACHED_NOTFOUND) { LOG_PRINT(LOG_DEBUG, "Cache Key[%s] Not Find!", key); rst = -1; } else { const char *str_rc = memcached_strerror(memc, rc); LOG_PRINT(LOG_DEBUG, "Cache Result: %s", str_rc); } return rst; }
/** * @brief load_conf load the conf of zimg * * @param conf conf name * * @return 1 for OK and -1 for fail */ static int load_conf(const char *conf) { lua_State *L = luaL_newstate(); luaL_openlibs(L); if (luaL_loadfile(L, conf) || lua_pcall(L, 0, 0, 0)) { lua_close(L); return -1; } lua_getglobal(L, "is_daemon"); //stack index: -12 if (lua_isnumber(L, -1)) settings.is_daemon = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "ip"); if (lua_isstring(L, -1)) str_lcpy(settings.ip, lua_tostring(L, -1), sizeof(settings.ip)); lua_pop(L, 1); lua_getglobal(L, "port"); if (lua_isnumber(L, -1)) settings.port = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "thread_num"); if (lua_isnumber(L, -1)) settings.num_threads = (int)lua_tonumber(L, -1); /* N workers */ lua_pop(L, 1); lua_getglobal(L, "backlog_num"); if (lua_isnumber(L, -1)) settings.backlog = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "max_keepalives"); if (lua_isnumber(L, -1)) settings.max_keepalives = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "retry"); if (lua_isnumber(L, -1)) settings.retry = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "system"); if (lua_isstring(L, -1)) { char tmp[128]; snprintf(tmp, 128, "%s %s", settings.server_name, lua_tostring(L, -1)); snprintf(settings.server_name, 128, "%s", tmp); } lua_pop(L, 1); lua_getglobal(L, "headers"); if (lua_isstring(L, -1)) { settings.headers = conf_get_headers(lua_tostring(L, -1)); } lua_pop(L, 1); lua_getglobal(L, "etag"); if (lua_isnumber(L, -1)) settings.etag = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "upload_rule"); if (lua_isstring(L, -1)) { settings.up_access = conf_get_rules(lua_tostring(L, -1)); } lua_pop(L, 1); lua_getglobal(L, "download_rule"); if (lua_isstring(L, -1)) { settings.down_access = conf_get_rules(lua_tostring(L, -1)); } lua_pop(L, 1); lua_getglobal(L, "admin_rule"); if (lua_isstring(L, -1)) { settings.admin_access = conf_get_rules(lua_tostring(L, -1)); } lua_pop(L, 1); lua_getglobal(L, "cache"); if (lua_isnumber(L, -1)) settings.cache_on = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "mc_ip"); if (lua_isstring(L, -1)) str_lcpy(settings.cache_ip, lua_tostring(L, -1), sizeof(settings.cache_ip)); lua_pop(L, 1); lua_getglobal(L, "mc_port"); if (lua_isnumber(L, -1)) settings.cache_port = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "log_level"); if (lua_isnumber(L, -1)) settings.log_level = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "log_name"); //stack index: -1 if (lua_isstring(L, -1)) str_lcpy(settings.log_name, lua_tostring(L, -1), sizeof(settings.log_name)); lua_pop(L, 1); lua_getglobal(L, "root_path"); if (lua_isstring(L, -1)) str_lcpy(settings.root_path, lua_tostring(L, -1), sizeof(settings.root_path)); lua_pop(L, 1); lua_getglobal(L, "admin_path"); if (lua_isstring(L, -1)) str_lcpy(settings.admin_path, lua_tostring(L, -1), sizeof(settings.admin_path)); lua_pop(L, 1); lua_getglobal(L, "disable_args"); if (lua_isnumber(L, -1)) settings.disable_args = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "disable_type"); if (lua_isnumber(L, -1)) settings.disable_type = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "disable_zoom_up"); if (lua_isnumber(L, -1)) settings.disable_zoom_up = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "script_name"); //stack index: -1 if (lua_isstring(L, -1)) str_lcpy(settings.script_name, lua_tostring(L, -1), sizeof(settings.script_name)); lua_pop(L, 1); lua_getglobal(L, "format"); if (lua_isstring(L, -1)) str_lcpy(settings.format, lua_tostring(L, -1), sizeof(settings.format)); lua_pop(L, 1); lua_getglobal(L, "quality"); if (lua_isnumber(L, -1)) settings.quality = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "mode"); if (lua_isnumber(L, -1)) settings.mode = (int)lua_tonumber(L, -1); lua_pop(L, 1); set_callback(settings.mode); lua_getglobal(L, "save_new"); if (lua_isnumber(L, -1)) settings.save_new = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "max_size"); if (lua_isnumber(L, -1)) settings.max_size = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "img_path"); if (lua_isstring(L, -1)) str_lcpy(settings.img_path, lua_tostring(L, -1), sizeof(settings.img_path)); lua_pop(L, 1); lua_getglobal(L, "beansdb_ip"); if (lua_isstring(L, -1)) str_lcpy(settings.beansdb_ip, lua_tostring(L, -1), sizeof(settings.beansdb_ip)); lua_pop(L, 1); lua_getglobal(L, "beansdb_port"); if (lua_isnumber(L, -1)) settings.beansdb_port = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_getglobal(L, "ssdb_ip"); if (lua_isstring(L, -1)) str_lcpy(settings.ssdb_ip, lua_tostring(L, -1), sizeof(settings.ssdb_ip)); lua_pop(L, 1); lua_getglobal(L, "ssdb_port"); if (lua_isnumber(L, -1)) settings.ssdb_port = (int)lua_tonumber(L, -1); lua_pop(L, 1); //settings.L = L; lua_close(L); return 1; }
/** * @brief get_request_cb The callback function of get a image request. * * @param req The request with a list of params and the md5 of image. * @param arg It is not useful. */ void get_request_cb(evhtp_request_t *req, void *arg) { char *md5 = NULL, *fmt = NULL, *type = NULL; zimg_req_t *zimg_req = NULL; char *buff = NULL; size_t len; evhtp_connection_t *ev_conn = evhtp_request_get_connection(req); struct sockaddr *saddr = ev_conn->saddr; struct sockaddr_in *ss = (struct sockaddr_in *)saddr; char address[16]; const char *xff_address = evhtp_header_find(req->headers_in, "X-Forwarded-For"); if(xff_address) { inet_aton(xff_address, &ss->sin_addr); } strncpy(address, inet_ntoa(ss->sin_addr), 16); int req_method = evhtp_request_get_method(req); if(req_method >= 16) req_method = 16; LOG_PRINT(LOG_DEBUG, "Method: %d", req_method); if(strcmp(method_strmap[req_method], "POST") == 0) { LOG_PRINT(LOG_DEBUG, "POST Request."); post_request_cb(req, NULL); return; } else if(strcmp(method_strmap[req_method], "GET") != 0) { LOG_PRINT(LOG_DEBUG, "Request Method Not Support."); LOG_PRINT(LOG_INFO, "%s refuse method", address); goto err; } if(settings.down_access != NULL) { int acs = zimg_access_inet(settings.down_access, ss->sin_addr.s_addr); LOG_PRINT(LOG_DEBUG, "access check: %d", acs); if(acs == ZIMG_FORBIDDEN) { LOG_PRINT(LOG_DEBUG, "check access: ip[%s] forbidden!", address); LOG_PRINT(LOG_INFO, "%s refuse get forbidden", address); goto forbidden; } else if(acs == ZIMG_ERROR) { LOG_PRINT(LOG_DEBUG, "check access: check ip[%s] failed!", address); LOG_PRINT(LOG_ERROR, "%s fail get access", address); goto err; } } const char *uri; uri = req->uri->path->full; if(strlen(uri) == 1 && uri[0] == '/') { LOG_PRINT(LOG_DEBUG, "Root Request."); int fd = -1; struct stat st; if((fd = open(settings.root_path, O_RDONLY)) == -1) { LOG_PRINT(LOG_DEBUG, "Root_page Open Failed. Return Default Page."); evbuffer_add_printf(req->buffer_out, "<html>\n<body>\n<h1>\nWelcome To zimg World!</h1>\n</body>\n</html>\n"); } else { if (fstat(fd, &st) < 0) { /* Make sure the length still matches, now that we * opened the file :/ */ LOG_PRINT(LOG_DEBUG, "Root_page Length fstat Failed. Return Default Page."); evbuffer_add_printf(req->buffer_out, "<html>\n<body>\n<h1>\nWelcome To zimg World!</h1>\n</body>\n</html>\n"); } else { evbuffer_add_file(req->buffer_out, fd, 0, st.st_size); } } //evbuffer_add_printf(req->buffer_out, "<html>\n </html>\n"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); evhtp_send_reply(req, EVHTP_RES_OK); LOG_PRINT(LOG_DEBUG, "============get_request_cb() DONE!==============="); LOG_PRINT(LOG_INFO, "%s succ root page", address); goto done; } if(strstr(uri, "favicon.ico")) { LOG_PRINT(LOG_DEBUG, "favicon.ico Request, Denied."); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); zimg_headers_add(req, settings.headers); evhtp_send_reply(req, EVHTP_RES_OK); goto done; } LOG_PRINT(LOG_DEBUG, "Got a GET request for <%s>", uri); /* Don't allow any ".."s in the path, to avoid exposing stuff outside * of the docroot. This test is both overzealous and underzealous: * it forbids aceptable paths like "/this/one..here", but it doesn't * do anything to prevent symlink following." */ if (strstr(uri, "..")) { LOG_PRINT(LOG_DEBUG, "attempt to upper dir!"); LOG_PRINT(LOG_INFO, "%s refuse directory", address); goto forbidden; } size_t md5_len = strlen(uri) + 1; md5 = (char *)malloc(md5_len); if(md5 == NULL) { LOG_PRINT(LOG_DEBUG, "md5 malloc failed!"); LOG_PRINT(LOG_ERROR, "%s fail malloc", address); goto err; } if(uri[0] == '/') str_lcpy(md5, uri+1, md5_len); else str_lcpy(md5, uri, md5_len); LOG_PRINT(LOG_DEBUG, "md5 of request is <%s>", md5); if(is_md5(md5) == -1) { LOG_PRINT(LOG_DEBUG, "Url is Not a zimg Request."); LOG_PRINT(LOG_INFO, "%s refuse url illegal", address); goto err; } /* This holds the content we're sending. */ evthr_t *thread = get_request_thr(req); thr_arg_t *thr_arg = (thr_arg_t *)evthr_get_aux(thread); int width, height, proportion, gray, x, y, rotate, quality, sv; width = 0; height = 0; proportion = 1; gray = 0; x = -1; y = -1; rotate = 0; quality = 0; sv = 0; evhtp_kvs_t *params; params = req->uri->query; if(params != NULL) { if(settings.disable_args != 1) { const char *str_w = evhtp_kv_find(params, "w"); const char *str_h = evhtp_kv_find(params, "h"); width = (str_w) ? atoi(str_w) : 0; height = (str_h) ? atoi(str_h) : 0; const char *str_p = evhtp_kv_find(params, "p"); proportion = (str_p) ? atoi(str_p) : 1; const char *str_g = evhtp_kv_find(params, "g"); gray = (str_g) ? atoi(str_g) : 0; const char *str_x = evhtp_kv_find(params, "x"); const char *str_y = evhtp_kv_find(params, "y"); x = (str_x) ? atoi(str_x) : -1; y = (str_y) ? atoi(str_y) : -1; if(x != -1 || y != -1) { proportion = 1; } const char *str_r = evhtp_kv_find(params, "r"); rotate = (str_r) ? atoi(str_r) : 0; const char *str_q = evhtp_kv_find(params, "q"); quality = (str_q) ? atoi(str_q) : 0; const char *str_f = evhtp_kv_find(params, "f"); if(str_f) { size_t fmt_len = strlen(str_f) + 1; fmt = (char *)malloc(fmt_len); if(fmt != NULL) str_lcpy(fmt, str_f, fmt_len); LOG_PRINT(LOG_DEBUG, "fmt = %s", fmt); } } if(settings.disable_type != 1) { const char *str_t = evhtp_kv_find(params, "t"); if(str_t) { size_t type_len = strlen(str_t) + 1; type = (char *)malloc(type_len); if(type != NULL) str_lcpy(type, str_t, type_len); LOG_PRINT(LOG_DEBUG, "type = %s", type); } } } else { sv = 1; } quality = (quality != 0 ? quality : settings.quality); zimg_req = (zimg_req_t *)malloc(sizeof(zimg_req_t)); if(zimg_req == NULL) { LOG_PRINT(LOG_DEBUG, "zimg_req malloc failed!"); LOG_PRINT(LOG_ERROR, "%s fail malloc", address); goto err; } zimg_req -> md5 = md5; zimg_req -> type = type; zimg_req -> width = width; zimg_req -> height = height; zimg_req -> proportion = proportion; zimg_req -> gray = gray; zimg_req -> x = x; zimg_req -> y = y; zimg_req -> rotate = rotate; zimg_req -> quality = quality; zimg_req -> fmt = (fmt != NULL ? fmt : settings.format); zimg_req -> sv = sv; zimg_req -> thr_arg = thr_arg; int get_img_rst = -1; get_img_rst = settings.get_img(zimg_req, req); if(get_img_rst == -1) { LOG_PRINT(LOG_DEBUG, "zimg Requset Get Image[MD5: %s] Failed!", zimg_req->md5); if(type) LOG_PRINT(LOG_ERROR, "%s fail pic:%s t:%s", address, md5, type); else LOG_PRINT(LOG_ERROR, "%s fail pic:%s w:%d h:%d p:%d g:%d x:%d y:%d r:%d q:%d f:%s", address, md5, width, height, proportion, gray, x, y, rotate, quality, zimg_req->fmt); goto err; } if(get_img_rst == 2) { LOG_PRINT(LOG_DEBUG, "Etag Matched Return 304 EVHTP_RES_NOTMOD."); if(type) LOG_PRINT(LOG_INFO, "%s succ 304 pic:%s t:%s", address, md5, type); else LOG_PRINT(LOG_INFO, "%s succ 304 pic:%s w:%d h:%d p:%d g:%d x:%d y:%d r:%d q:%d f:%s", address, md5, width, height, proportion, gray, x, y, rotate, quality, zimg_req->fmt); evhtp_send_reply(req, EVHTP_RES_NOTMOD); goto done; } len = evbuffer_get_length(req->buffer_out); LOG_PRINT(LOG_DEBUG, "get buffer length: %d", len); LOG_PRINT(LOG_DEBUG, "Got the File!"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "image/jpeg", 0, 0)); zimg_headers_add(req, settings.headers); evhtp_send_reply(req, EVHTP_RES_OK); if(type) LOG_PRINT(LOG_INFO, "%s succ pic:%s t:%s size:%d", address, md5, type, len); else LOG_PRINT(LOG_INFO, "%s succ pic:%s w:%d h:%d p:%d g:%d x:%d y:%d r:%d q:%d f:%s size:%d", address, md5, width, height, proportion, gray, x, y, rotate, quality, zimg_req->fmt, len); LOG_PRINT(LOG_DEBUG, "============get_request_cb() DONE!==============="); goto done; forbidden: evbuffer_add_printf(req->buffer_out, "<html><body><h1>403 Forbidden!</h1></body></html>"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); evhtp_send_reply(req, EVHTP_RES_FORBIDDEN); LOG_PRINT(LOG_DEBUG, "============get_request_cb() FORBIDDEN!==============="); goto done; err: evbuffer_add_printf(req->buffer_out, "<html><body><h1>404 Not Found!</h1></body></html>"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); evhtp_send_reply(req, EVHTP_RES_NOTFOUND); LOG_PRINT(LOG_DEBUG, "============get_request_cb() ERROR!==============="); done: free(fmt); free(md5); free(type); free(zimg_req); free(buff); }
int multipart_parse(evhtp_request_t *req, const char *content_type, const char *address, const char *buff, int post_size) { int err_no = 0; char *boundary = NULL, *boundary_end = NULL; char *boundaryPattern = NULL; int boundary_len = 0; mp_arg_t *mp_arg = NULL; evbuffer_add_printf(req->buffer_out, "<html>\n<head>\n" "<title>Upload Result</title>\n" "</head>\n" "<body>\n" ); if(strstr(content_type, "boundary") == 0) { LOG_PRINT(LOG_DEBUG, "boundary NOT found!"); LOG_PRINT(LOG_ERROR, "%s fail post parse", address); err_no = 6; goto done; } boundary = strchr(content_type, '='); boundary++; boundary_len = strlen(boundary); if(boundary[0] == '"') { boundary++; boundary_end = strchr(boundary, '"'); if (!boundary_end) { LOG_PRINT(LOG_DEBUG, "Invalid boundary in multipart/form-data POST data"); LOG_PRINT(LOG_ERROR, "%s fail post parse", address); err_no = 6; goto done; } } else { /* search for the end of the boundary */ boundary_end = strpbrk(boundary, ",;"); } if (boundary_end) { boundary_end[0] = '\0'; boundary_len = boundary_end-boundary; } LOG_PRINT(LOG_DEBUG, "boundary Find. boundary = %s", boundary); boundaryPattern = (char *)malloc(boundary_len + 3); if(boundaryPattern == NULL) { LOG_PRINT(LOG_DEBUG, "boundarypattern malloc failed!"); LOG_PRINT(LOG_ERROR, "%s fail malloc", address); err_no = 0; goto done; } snprintf(boundaryPattern, boundary_len + 3, "--%s", boundary); LOG_PRINT(LOG_DEBUG, "boundaryPattern = %s, strlen = %d", boundaryPattern, (int)strlen(boundaryPattern)); multipart_parser* parser = multipart_parser_init(boundaryPattern); if(!parser) { LOG_PRINT(LOG_DEBUG, "Multipart_parser Init Failed!"); LOG_PRINT(LOG_ERROR, "%s fail post save", address); err_no = 0; goto done; } mp_arg = (mp_arg_t *)malloc(sizeof(mp_arg_t)); if(!mp_arg) { LOG_PRINT(LOG_DEBUG, "Multipart_parser Arg Malloc Failed!"); LOG_PRINT(LOG_ERROR, "%s fail post save", address); err_no = 0; goto done; } evthr_t *thread = get_request_thr(req); thr_arg_t *thr_arg = (thr_arg_t *)evthr_get_aux(thread); mp_arg->req = req; mp_arg->thr_arg = thr_arg; str_lcpy(mp_arg->address, address, 16); mp_arg->partno = 0; mp_arg->succno = 0; mp_arg->check_name = 0; multipart_parser_set_data(parser, mp_arg); multipart_parser_execute(parser, buff, post_size); multipart_parser_free(parser); if(mp_arg->succno == 0) { evbuffer_add_printf(req->buffer_out, "<h1>Upload Failed!</h1>\n"); } evbuffer_add_printf(req->buffer_out, "</body>\n</html>\n"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); err_no = -1; done: free(boundaryPattern); free(mp_arg); return err_no; }
/** * @brief admin_request_cb the callback function of admin requests * * @param req the evhtp request * @param arg the arg of request */ void admin_request_cb(evhtp_request_t *req, void *arg) { char md5[33]; evhtp_connection_t *ev_conn = evhtp_request_get_connection(req); struct sockaddr *saddr = ev_conn->saddr; struct sockaddr_in *ss = (struct sockaddr_in *)saddr; char address[16]; const char *xff_address = evhtp_header_find(req->headers_in, "X-Forwarded-For"); if(xff_address) { inet_aton(xff_address, &ss->sin_addr); } strncpy(address, inet_ntoa(ss->sin_addr), 16); int req_method = evhtp_request_get_method(req); if(req_method >= 16) req_method = 16; LOG_PRINT(LOG_DEBUG, "Method: %d", req_method); if(strcmp(method_strmap[req_method], "POST") == 0) { LOG_PRINT(LOG_DEBUG, "POST Request."); post_request_cb(req, NULL); return; } else if(strcmp(method_strmap[req_method], "GET") != 0) { LOG_PRINT(LOG_DEBUG, "Request Method Not Support."); LOG_PRINT(LOG_INFO, "%s refuse method", address); goto err; } if(settings.admin_access != NULL) { int acs = zimg_access_inet(settings.admin_access, ss->sin_addr.s_addr); LOG_PRINT(LOG_DEBUG, "access check: %d", acs); if(acs == ZIMG_FORBIDDEN) { LOG_PRINT(LOG_DEBUG, "check access: ip[%s] forbidden!", address); LOG_PRINT(LOG_INFO, "%s refuse admin forbidden", address); goto forbidden; } else if(acs == ZIMG_ERROR) { LOG_PRINT(LOG_DEBUG, "check access: check ip[%s] failed!", address); LOG_PRINT(LOG_ERROR, "%s fail admin access", address); goto err; } } const char *uri; uri = req->uri->path->full; if(strstr(uri, "favicon.ico")) { LOG_PRINT(LOG_DEBUG, "favicon.ico Request, Denied."); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); zimg_headers_add(req, settings.headers); evhtp_send_reply(req, EVHTP_RES_OK); return; } LOG_PRINT(LOG_DEBUG, "Got a Admin request for <%s>", uri); int t; evhtp_kvs_t *params; params = req->uri->query; if(!params) { LOG_PRINT(LOG_DEBUG, "Admin Root Request."); int fd = -1; struct stat st; //TODO: use admin_path if((fd = open(settings.admin_path, O_RDONLY)) == -1) { LOG_PRINT(LOG_DEBUG, "Admin_page Open Failed. Return Default Page."); evbuffer_add_printf(req->buffer_out, "<html>\n<body>\n<h1>\nWelcome To zimg Admin!</h1>\n</body>\n</html>\n"); } else { if (fstat(fd, &st) < 0) { /* Make sure the length still matches, now that we * opened the file :/ */ LOG_PRINT(LOG_DEBUG, "Root_page Length fstat Failed. Return Default Page."); evbuffer_add_printf(req->buffer_out, "<html>\n<body>\n<h1>\nWelcome To zimg Admin!</h1>\n</body>\n</html>\n"); } else { evbuffer_add_file(req->buffer_out, fd, 0, st.st_size); } } //evbuffer_add_printf(req->buffer_out, "<html>\n </html>\n"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); evhtp_send_reply(req, EVHTP_RES_OK); LOG_PRINT(LOG_DEBUG, "============admin_request_cb() DONE!==============="); LOG_PRINT(LOG_INFO, "%s succ admin root page", address); return; } else { const char *str_md5, *str_t; str_md5 = evhtp_kv_find(params, "md5"); if(str_md5 == NULL) { LOG_PRINT(LOG_DEBUG, "md5() = NULL return"); goto err; } str_lcpy(md5, str_md5, sizeof(md5)); if(is_md5(md5) == -1) { LOG_PRINT(LOG_DEBUG, "Admin Request MD5 Error."); LOG_PRINT(LOG_INFO, "%s refuse admin url illegal", address); goto err; } str_t = evhtp_kv_find(params, "t"); LOG_PRINT(LOG_DEBUG, "md5() = %s; t() = %s;", str_md5, str_t); t = (str_t) ? atoi(str_t) : 0; } evthr_t *thread = get_request_thr(req); thr_arg_t *thr_arg = (thr_arg_t *)evthr_get_aux(thread); int admin_img_rst = -1; admin_img_rst = settings.admin_img(req, thr_arg, md5, t); if(admin_img_rst == -1) { evbuffer_add_printf(req->buffer_out, "<html><body><h1>Admin Command Failed!</h1> \ <p>MD5: %s</p> \ <p>Command Type: %d</p> \ <p>Command Failed.</p> \ </body></html>", md5, t); LOG_PRINT(LOG_ERROR, "%s fail admin pic:%s t:%d", address, md5, t); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); }
/** * @brief save_img Save buffer from POST requests * * @param thr_arg Thread arg struct. * @param buff The char * from POST request * @param len The length of buff * @param md5 Parsed md5 from url * * @return 1 for success and -1 for fail */ int save_img(thr_arg_t *thr_arg, const char *buff, const int len, char *md5) { int result = -1; LOG_PRINT(LOG_DEBUG, "Begin to Caculate MD5..."); md5_state_t mdctx; md5_byte_t md_value[16]; char md5sum[33]; int i; int h, l; md5_init(&mdctx); md5_append(&mdctx, (const unsigned char*)(buff), len); md5_finish(&mdctx, md_value); for(i=0; i<16; ++i) { h = md_value[i] & 0xf0; h >>= 4; l = md_value[i] & 0x0f; md5sum[i * 2] = (char)((h >= 0x0 && h <= 0x9) ? (h + 0x30) : (h + 0x57)); md5sum[i * 2 + 1] = (char)((l >= 0x0 && l <= 0x9) ? (l + 0x30) : (l + 0x57)); } md5sum[32] = '\0'; str_lcpy(md5, md5sum, 33); LOG_PRINT(LOG_DEBUG, "md5: %s", md5sum); char save_path[512]; char save_name[512]; if(settings.mode != 1) { if(exist_db(thr_arg, md5sum) == 1) { LOG_PRINT(LOG_DEBUG, "File Exist, Needn't Save."); result = 1; goto done; } LOG_PRINT(LOG_DEBUG, "exist_db not found. Begin to Save File."); if(save_img_db(thr_arg, md5sum, buff, len) == -1) { LOG_PRINT(LOG_DEBUG, "save_img_db failed."); goto done; } else { LOG_PRINT(LOG_DEBUG, "save_img_db succ."); result = 1; goto done; } } //caculate 2-level path int lvl1 = str_hash(md5sum); int lvl2 = str_hash(md5sum + 3); snprintf(save_path, 512, "%s/%d/%d/%s", settings.img_path, lvl1, lvl2, md5sum); LOG_PRINT(LOG_DEBUG, "save_path: %s", save_path); if(is_dir(save_path) != 1) { if(mk_dirs(save_path) == -1) { LOG_PRINT(LOG_DEBUG, "save_path[%s] Create Failed!", save_path); goto done; } LOG_PRINT(LOG_DEBUG, "save_path[%s] Create Finish.", save_path); } snprintf(save_name, 512, "%s/0*0", save_path); LOG_PRINT(LOG_DEBUG, "save_name-->: %s", save_name); if(is_file(save_name) == 1) { LOG_PRINT(LOG_DEBUG, "Check File Exist. Needn't Save."); goto cache; } if(new_img(buff, len, save_name) == -1) { LOG_PRINT(LOG_DEBUG, "Save Image[%s] Failed!", save_name); goto done; } cache: if(len < CACHE_MAX_SIZE) { set_cache_bin(thr_arg, md5sum, buff, len); } result = 1; done: return result; }
/** * @brief get_img get image from disk mode through the request * * @param req the zimg request * @param request the evhtp request * * @return 1 for OK, 2 for 304 needn't response buffer and -1 for failed */ int get_img(zimg_req_t *req, evhtp_request_t *request) { int result = -1; char rsp_cache_key[CACHE_KEY_SIZE]; int fd = -1; struct stat f_stat; char *buff = NULL; char *orig_buff = NULL; MagickWand *im = NULL; size_t len = 0; bool to_save = true; LOG_PRINT(LOG_DEBUG, "get_img() start processing zimg request..."); int lvl1 = str_hash(req->md5); int lvl2 = str_hash(req->md5 + 3); char whole_path[512]; snprintf(whole_path, 512, "%s/%d/%d/%s", settings.img_path, lvl1, lvl2, req->md5); LOG_PRINT(LOG_DEBUG, "whole_path: %s", whole_path); if(is_dir(whole_path) == -1) { LOG_PRINT(LOG_DEBUG, "Image %s is not existed!", req->md5); goto err; } if(settings.script_on == 1 && req->type != NULL) snprintf(rsp_cache_key, CACHE_KEY_SIZE, "%s:%s", req->md5, req->type); else { if(req->proportion == 0 && req->width == 0 && req->height == 0) str_lcpy(rsp_cache_key, req->md5, CACHE_KEY_SIZE); else gen_key(rsp_cache_key, req->md5, 9, req->width, req->height, req->proportion, req->gray, req->x, req->y, req->rotate, req->quality, req->fmt); } if(find_cache_bin(req->thr_arg, rsp_cache_key, &buff, &len) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Cache[Key: %s].", rsp_cache_key); to_save = false; goto done; } LOG_PRINT(LOG_DEBUG, "Start to Find the Image..."); char orig_path[512]; snprintf(orig_path, 512, "%s/0*0", whole_path); LOG_PRINT(LOG_DEBUG, "0rig File Path: %s", orig_path); char rsp_path[512]; if(settings.script_on == 1 && req->type != NULL) snprintf(rsp_path, 512, "%s/t_%s", whole_path, req->type); else { char name[128]; snprintf(name, 128, "%d*%d_p%d_g%d_%d*%d_r%d_q%d.%s", req->width, req->height, req->proportion, req->gray, req->x, req->y, req->rotate, req->quality, req->fmt); if(req->width == 0 && req->height == 0 && req->proportion == 0) { LOG_PRINT(LOG_DEBUG, "Return original image."); strncpy(rsp_path, orig_path, 512); } else { snprintf(rsp_path, 512, "%s/%s", whole_path, name); } } LOG_PRINT(LOG_DEBUG, "Got the rsp_path: %s", rsp_path); if((fd = open(rsp_path, O_RDONLY)) == -1) { im = NewMagickWand(); if (im == NULL) goto err; int ret; if(find_cache_bin(req->thr_arg, req->md5, &orig_buff, &len) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Orignal Image Cache[Key: %s].", req->md5); ret = MagickReadImageBlob(im, (const unsigned char *)orig_buff, len); if (ret != MagickTrue) { LOG_PRINT(LOG_DEBUG, "Open Original Image From Blob Failed! Begin to Open it From Disk."); del_cache(req->thr_arg, req->md5); ret = MagickReadImage(im, orig_path); if (ret != MagickTrue) { LOG_PRINT(LOG_DEBUG, "Open Original Image From Disk Failed!"); goto err; } else { MagickSizeType size = MagickGetImageSize(im); LOG_PRINT(LOG_DEBUG, "image size = %d", size); if(size < CACHE_MAX_SIZE) { MagickResetIterator(im); char *new_buff = (char *)MagickWriteImageBlob(im, &len); if (new_buff == NULL) { LOG_PRINT(LOG_DEBUG, "Webimg Get Original Blob Failed!"); goto err; } set_cache_bin(req->thr_arg, req->md5, new_buff, len); free(new_buff); } } } } else { LOG_PRINT(LOG_DEBUG, "Not Hit Original Image Cache. Begin to Open it."); ret = MagickReadImage(im, orig_path); if (ret != MagickTrue) { LOG_PRINT(LOG_DEBUG, "Open Original Image From Disk Failed! %d != %d", ret, MagickTrue); LOG_PRINT(LOG_DEBUG, "Open Original Image From Disk Failed!"); goto err; } else { MagickSizeType size = MagickGetImageSize(im); LOG_PRINT(LOG_DEBUG, "image size = %d", size); if(size < CACHE_MAX_SIZE) { MagickResetIterator(im); char *new_buff = (char *)MagickWriteImageBlob(im, &len); if (new_buff == NULL) { LOG_PRINT(LOG_DEBUG, "Webimg Get Original Blob Failed!"); goto err; } set_cache_bin(req->thr_arg, req->md5, new_buff, len); free(new_buff); } } } if(settings.script_on == 1 && req->type != NULL) ret = lua_convert(im, req); else ret = convert(im, req); if(ret == -1) goto err; if(ret == 0) to_save = false; buff = (char *)MagickWriteImageBlob(im, &len); if (buff == NULL) { LOG_PRINT(LOG_DEBUG, "Webimg Get Blob Failed!"); goto err; } } else { to_save = false; fstat(fd, &f_stat); size_t rlen = 0; len = f_stat.st_size; if(len <= 0) { LOG_PRINT(LOG_DEBUG, "File[%s] is Empty.", rsp_path); goto err; } if((buff = (char *)malloc(len)) == NULL) { LOG_PRINT(LOG_DEBUG, "buff Malloc Failed!"); goto err; } LOG_PRINT(LOG_DEBUG, "img_size = %d", len); if((rlen = read(fd, buff, len)) == -1) { LOG_PRINT(LOG_DEBUG, "File[%s] Read Failed: %s", rsp_path, strerror(errno)); goto err; } else if(rlen < len) { LOG_PRINT(LOG_DEBUG, "File[%s] Read Not Compeletly.", rsp_path); goto err; } } //LOG_PRINT(LOG_INFO, "New Image[%s]", rsp_path); int save_new = 0; if(to_save == true) { if(req->sv == 1 || settings.save_new == 1 || (settings.save_new == 2 && req->type != NULL)) { save_new = 1; } } if(save_new == 1) { LOG_PRINT(LOG_DEBUG, "Image[%s] is Not Existed. Begin to Save it.", rsp_path); if(new_img(buff, len, rsp_path) == -1) { LOG_PRINT(LOG_DEBUG, "New Image[%s] Save Failed!", rsp_path); LOG_PRINT(LOG_WARNING, "fail save %s", rsp_path); } } else LOG_PRINT(LOG_DEBUG, "Image [%s] Needn't to Storage.", rsp_path); if(len < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, rsp_cache_key, buff, len); } done: if(settings.etag == 1) { result = zimg_etag_set(request, buff, len); if(result == 2) goto err; } result = evbuffer_add(request->buffer_out, buff, len); if(result != -1) { result = 1; } err: if(fd != -1) close(fd); if(im != NULL) DestroyMagickWand(im); free(buff); free(orig_buff); return result; }