Thttpd上传大文件的方法

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

      最近在给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哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值