最近在给Microsoft做一个项目,碰到需要上传几百MB的文件,而thttpd本身也是支持上传文件功能的,只是thttpd为了考虑一些需求在某些方面进行了限制。
这里我做个简单的介绍,thttpd的main()函数在thttpd.c里面,解析http参数的功能在libhttpd.c。config.h头文件有一些关于系统以及CGI的配置项,关于CGI的配置项主要是考虑一些系统的安全性和网络拥塞问题。
在有client连接时,thttpd会相应创建一个fd来进行连接,并且会fork()一个子进程来与之对应,记录对应子进程的fd。在libhttpd.c的ls函数。


在这个函数里面实现了fork功能,在这个函数里还有一个比较重要的处理,依我之见是为了维护好系统的fd操作,防止创建大量fd陷入死循环达到thttpd限制的上限或者系统最大文件描述数量。

这里创建了一个定时器,当定时器时间到达时,就去把之前对应创建的子进程kill,CGI_TIMELIMIT宏就是在config.h定义的,
#define CGI_TIMELIMIT 30
原本这个值为30,代表着定时器的时间为30秒。
在调试上传大文件功能的时候,我发现小文件上传时间时间短,小于30秒的都能正常上传成功,而当将近百MB及以上的文件时,上传到中途就中断连接了,导致thttpd无法读取全部文件内容而不去执行相应的CGI程序。原因就是大文件上传的时间需要比较长,当大于thttpd本身限制的30秒时,对应子进程被kill,fd也就释放了。
所以为了解决这个问题,只需要去加大CGI_TIMELIMIT的值就可以,具体的值根据需求而定,我是修改到了十分钟,这个宏最好不要注释掉。
#define CGI_TIMELIMIT 600
修改了一个宏的值,就这样完美解决了大文件上传问题。
thttpd在读取文件的时候,必须要全部读取完成才会去执行相应的CGI。
以下是我简单做个程序案例:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/socket.h>
#include "cgic.h"
#include "am_cgi.h"
#include "websetting_cgimain.h"
#include "openssl/md5.h"
#define F_FILENAME_1 "NewImage"
//#define F_FILENAME_1 "fileName"//
#define F_FILENAME_2 "MD5sum"
#define FILENAME_LEN 1024
#define BUF_LEN 10240
#define CMD_LEN 1024
#define WRITE_LOG 1
#if WRITE_LOG
#define EZCAST_WRITE_LOG(fmt, args...) do { struct timeval tv; gettimeofday(&tv,NULL); char msg[1024]; snprintf(msg, 1024, "-%06lu.%06lu- "fmt,tv.tv_sec,tv.tv_usec,##args); write_log(msg); } while (0)
#else
#define EZCAST_WRITE_LOG(fmt, args...)
#endif
#define LOG_PATH "/tmp/ms_setting.log"
static void write_log(char *str)
{
if(access(LOG_PATH, F_OK) == 0)
{
struct stat info;
stat(LOG_PATH, &info);
if(info.st_size >= 102400)
unlink(LOG_PATH);
}
FILE *fp = fopen(LOG_PATH, "a");
if(fp != NULL)
{
fwrite(str, 1, strlen(str), fp);
fclose(fp);
}
}
int cgiMain(int argc, char *argv[])
{
int ret, retToken=-1;
char cmd_string[2048]={0},cmdbuf[256] = {0};
char value[256]={0};
char result[128]={0};
char **array, **arrayStep;
char *req_method = NULL;
cgiFilePtr cfp,mfp;
char rfile[FILENAME_LEN] /*remote file */ ,rfile_1[FILENAME_LEN],
lfile[FILENAME_LEN] = "/tmp/Image"/* local file */ ,mfile[FILENAME_LEN] = "/tmp/MD5sum",
buf[BUF_LEN],cmd[CMD_LEN];
int fd = -1,fd1 = -1;
int got, i,n,contentLength;
long int fsize,msize;
char file_MD5Sum[33];
MD5_CTX c;
unsigned char md[17];
cgiHeaderContentType("text/html");
req_method = getenv("REQUEST_METHOD");
EZCAST_WRITE_LOG("---- req_method: %s\n", req_method);
if (!strcmp(req_method, "GET"))
{
if (cgiFormEntries(&array) != cgiFormSuccess)
{
EZCAST_WRITE_LOG("No file was uploaded.(%d)", ret);
return -1;
}
arrayStep = array;
while(*arrayStep)
{
memset(value,0,sizeof(value));
cgiFormString((char *)*arrayStep, value, sizeof(value));
strcat(cmd_string,value);
strcat(cmd_string,"\t");
arrayStep++;
}
cgiStringArrayFree(array);
create_websetting_client("cgi_setting_server");
websetting_client_write(cmd_string);
ret=websetting_client_read();
}
else if (!strcmp(req_method, "POST"))
{
if ((ret = cgiFormFileName(F_FILENAME_1, rfile, sizeof(rfile))) != cgiFormSuccess)
{
EZCAST_WRITE_LOG("No (%s)file was uploaded.(%d)",F_FILENAME_1, ret);
return -1;
}
EZCAST_WRITE_LOG("----rfile filename: %s\n", rfile);
//strncpy(lfile,rfile,strlen(rfile));
EZCAST_WRITE_LOG("----lfile filename: %s\n", lfile);
cgiFormFileSize(F_FILENAME_1, &fsize);
EZCAST_WRITE_LOG("---- filesize: %d\n", fsize);
if ((ret = cgiFormFileOpen(F_FILENAME_1, &cfp)) != cgiFormSuccess)
{
fprintf(cgiOut, "<p>open cgi file failed.(%d)</p>", ret);
EZCAST_WRITE_LOG("open cgi file failed.(%d)", ret);
return -1;
}
if ((fd = open(lfile, O_CREAT | O_RDWR)) < 0)
{
fprintf(cgiOut, "<p>create file on server failed.(%s)</p>", strerror(errno));
EZCAST_WRITE_LOG("create file on server failed.(%s)", strerror(errno));
return -1;
}
//MD5_Init(&c); // Ready to calculate MD5 sum
while (cgiFormFileRead(cfp, buf, sizeof(buf), &got) == cgiFormSuccess)
{
if ((ret = write(fd, buf, got)) < 0)
{
fprintf(cgiOut, "<p> write failed(%d/%s)</p>\n", errno, strerror(errno));
EZCAST_WRITE_LOG("write failed(%d/%s)\n", errno, strerror(errno));
}
fprintf(cgiOut, "<p>got(%d)</p>\n", got);
//EZCAST_WRITE_LOG("got(%d)\n", got);
//MD5_Update(&c, buf, got); // Calculate MD5 sum
}
memset(buf,0,sizeof(buf));
#if 0
if ((ret = cgiFormFileName(F_FILENAME_2, rfile_1, sizeof(rfile_1))) != cgiFormSuccess)
{
EZCAST_WRITE_LOG("No (%s)file was uploaded.(%d)", F_FILENAME_2,ret);
return -1;
}
EZCAST_WRITE_LOG("---- file2name: %s\n", rfile_1);
cgiFormFileSize(F_FILENAME_2, &msize);
printf("---- file2size: %d\n", msize);
EZCAST_WRITE_LOG("---- file2size: %d\n", msize);
if ((ret = cgiFormFileOpen(F_FILENAME_2, &mfp)) != cgiFormSuccess)
{
fprintf(cgiOut, "<p>open cgi file failed.(%d)</p>", ret);
EZCAST_WRITE_LOG("open cgi file failed.(%d)", ret);
return -1;
}
if ((fd1 = open(mfile, O_CREAT | O_RDWR)) < 0)
{
fprintf(cgiOut, "<p>create file on server failed.(%s)</p>", strerror(errno));
EZCAST_WRITE_LOG("create file on server failed.(%s)", strerror(errno));
return -1;
}
while (cgiFormFileRead(mfp, buf, sizeof(buf), &got) == cgiFormSuccess)
{
if ((ret = write(fd1, buf, got)) < 0)
{
fprintf(cgiOut, "<p> write failed(%d/%s)</p>\n", errno, strerror(errno));
EZCAST_WRITE_LOG("write failed(%d/%s)\n", errno, strerror(errno));
}
fprintf(cgiOut, "<p>got(%d)</p>\n", got);
EZCAST_WRITE_LOG("got(%d)\n", got);
}
if (fd1 > 0)
close(fd1);
if (mfp cfp != NULL)
cgiFormFileClose(mfp);
#endif
if (fd > 0)
close(fd);
if (cfp)
cgiFormFileClose(cfp);
#if 0
MD5_Final(md, &c);
memset(file_MD5Sum, 0, sizeof(file_MD5Sum));
for(i=0; i<16; i++)
{
sprintf(&file_MD5Sum[2*i], "%02x", md[i]&0xff);
}
file_MD5Sum[32] = '\0';
#endif
char *data=getenv("QUERY_STRING");
EZCAST_WRITE_LOG("---- date: %s\n", data);
char *p = strstr(data,"Type=");
if (p)
strcpy(cmdbuf,p + strlen("Type="));
sprintf(cmd_string,"%s\t%s","UploadFirmware",cmdbuf);
create_websetting_client("cgi_setting_server");
websetting_client_write(cmd_string);
ret=websetting_client_read();
}
return ret;
}
喜欢本文章的可以给个Like哦!
解决Thttpd上传大文件中断问题

本文介绍了在使用thttpd时遇到的大文件上传中断问题,原因是thttpd的CGI_TIMELIMIT默认设置为30秒,超过这个时间的上传会被中断。解决方法是通过增大CGI_TIMELIMIT的值,例如改为600秒,以适应大文件的上传需求。
805

被折叠的 条评论
为什么被折叠?



