C语言CGI上传文件

时间:2022-04-23 04:56:18

找到的资料

用于向嵌入式linux系统上跑的简单web服务上传文件

说一下原理

把文件的post表单域安排在post数据流的最后部分,根据 content_length的长度和post流的固定的数据格式,计算出上传的文件大小,然后从流中边读边写这个大小的数据存入文件就可以了,因为表单 的提交直接是无法直接用ajax操作的所以使用iframe方式来动态更新上传状态,可以在此基础上做个上传进度条

在minihttpd环境下测试成功,随便传个几十兆很轻快

C语言CGI上传文件

// 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;
}