找到的资料
用于向嵌入式linux系统上跑的简单web服务上传文件
说一下原理
把文件的post表单域安排在post数据流的最后部分,根据 content_length的长度和post流的固定的数据格式,计算出上传的文件大小,然后从流中边读边写这个大小的数据存入文件就可以了,因为表单 的提交直接是无法直接用ajax操作的所以使用iframe方式来动态更新上传状态,可以在此基础上做个上传进度条
在minihttpd环境下测试成功,随便传个几十兆很轻快
// vim:ft=c
// /cgi/upload.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef enum{
UP_SHOW,
UP_OK,
UP_FAIL,
UP_NONE,
}UP_STATUS;
#define debug(x...) fprintf(stderr,x)
int main(int argc,char* argv[]){
printf("ContentType:text/html\r\n");
printf("Cache-Control:private,max-age=0;\r\n");
printf("\r\n");
UP_STATUS up_s;
char *p;
char updir[256]="/tmp/";
if(getenv("CONTENT_TYPE")){
if(!strncmp(getenv("CONTENT_TYPE"),"multipart/form-data",19)){
//get boundary
char boundary[64]="--";
p=strstr(getenv("CONTENT_TYPE"),"boundary=");
strcpy(boundary+2,p+9);
debug("boundary=%s\n",boundary);
//get content length
int len=atoi(getenv("CONTENT_LENGTH"));
//read down to last file field
char str[512];
char fname[256];
int pos=0;
while(1){
if(fgets(str,512,stdin)){
pos+=strlen(str);
if(strstr(str,"filename=")){
//get filename
p=strstr(str,"filename=");
strcpy(fname,p+9);
if(!strcmp(fname,"\"\"\r\n")){debug("nothing\n");up_s=UP_NONE;goto done;}
strcpy(fname,strrchr(fname,'\\')+1);
p=strchr(fname,'\"');
*p='\0';
debug("*upload file %s\n",fname);
break;
}
}
}
fgets(str,512,stdin);
pos+=strlen(str);
fgets(str,512,stdin);
pos+=strlen(str);
int fSize=len-pos-strlen(boundary)-6;
debug("*file size %d\n",fSize);
int bSize=4096;
//open file for writing
char fpath[256]="";
strcat(fpath,updir);
strcat(fpath,fname);
debug("write to %s\n",fpath);
FILE *f=fopen(fpath,"wb");
if(!f){debug("open file failure");goto fail;}
//chunk read
int chunk=fSize/bSize;
debug("chunk=%d\n",chunk);
int lbSize=fSize%bSize;
debug("lbSize=%d\n",lbSize);
void* buf=malloc(bSize);
int i;
for(i=0;i<chunk;i++){
if(fread(buf,bSize,1,stdin)){
if(!fwrite(buf,bSize,1,f)){debug("error write chunk %d\n",i);goto fail;}
}else{
debug("error read chunk %d\n",i); goto fail;
}
}
free(buf);
if(lbSize){
buf=malloc(lbSize);
if(fread(buf,lbSize,1,stdin)){
if(!fwrite(buf,lbSize,1,f)){debug("error write last chunk");goto fail;}
}else{
debug("error read last chunk"); goto fail;
}
free(buf);
}
if(fflush(f)){debug("error flush file");goto fail;}
fclose(f);
up_s=UP_OK;
goto done;
}
}
goto done;
fail:
up_s=UP_FAIL;
done:
printf("\
\n <html><head><title>new</title></head>\
\n <script>\
\n function $(id){\
\n return document.getElementById(id);\
\n }\
\n ");if(up_s==UP_SHOW){printf("\
\n function post(){\
\n $(\"status\").innerHTML=\"uploading..\";\
\n }\
\n function none(){\
\n $(\"status\").innerHTML=\"none\";\
\n }\
\n function ok(){\
\n $(\"status\").innerHTML=\"done\";\
\n }\
\n function fail(){\
\n $(\"status\").innerHTML=\"fail\";\
\n }\
\n ");}else if(up_s==UP_OK){printf("\
\n parent.ok();\
\n ");}else if(up_s==UP_FAIL){printf("\
\n parent.fail();\
\n ");}else if(up_s==UP_NONE){printf("\
\n parent.none();\
\n ");}printf("\
\n </script>\
\n ");if(up_s==UP_SHOW){printf("\
\n <body>\
\n <form name=\"fup\" action=\"/cgi/upload\" enctype=\"multipart/form-data\" method=\"post\" target=\"tfrm\">\
\n <input type=\"file\" name=\"fp\"/>\
\n <input type=\"submit\" onclick=\"post()\"/>\
\n </form>\
\n <div id=\"status\" style=\"background-color:#abcdef;\"></div>\
\n <iframe width=0 height=0 name=\"tfrm\"></iframe>\
\n ");}printf("\
\n </body>\
\n </html>\
\n ");
return 1;
}