CGI配置程序开发总结


CGI的后端,简单理解就是C、或者python写的后端服务,接收前端HTML form表单的输入,然后进行相应的操作。


CGI上传程序花的时间相对多些,在deepseek生成代码的基础上,结合抓包对form表单的分析,确实效率是提升了不少。但deepseek不能解决所有的问题,就跟网上说的一样,碰到程序员的问题,给出的答案就开始胡说,哈哈哈。


呱牛笔记

呱牛笔记


呱牛笔记


其中上传程序的CGI代码参考:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/stat.h> 
#include <sys/types.h> 
#include <signal.h>
#include <fcntl.h> 

#define UPLOAD_DIR "/tmp/bms/" // 上传文件保存目录
#define BUF_SIZE 4096

// 创建上传目录(如果不存在)
void create_upload_dir() {
    if (access(UPLOAD_DIR, F_OK)) {
        mkdir(UPLOAD_DIR, 0777);
    }
}
  

// 安全释放指针并将指针置空
#define SAFE_FREE(ptr) do { free(ptr); (ptr) = NULL; } while (0)


/*
 * 在内存中找出一段字符串,返回出现的首地址
 * m 缓冲区地址
 * len 缓冲区长度
 * str 带有结束符的字符串
 */
void *memstr(unsigned char *m, int len, const char *str)
{
    unsigned char *sub = (unsigned char *)str;
    unsigned char *s, *d;
    int i = 0;
    int slen = len - strlen(str) + 1;
    if ((m == NULL) || (slen < 1)) {
        return NULL;
    }
    
    while (i < slen) {
        s = m + i; d = (unsigned char *)str;
        while(*s == *d) {
            s += 1;
            d += 1;
        };
        if (*d == 0) {
            return m + i;
        }
        i += 1;
    }
    return NULL;
}

// 解析 multipart/form-data 数据
void parse_multipart_data(const char *boundary) {
    char *line = NULL;
    size_t line_len = 0;
    FILE *file = NULL;
    char filepath[256];
    char buffer[BUF_SIZE];
    int start_flag = 0;

    struct timeval tv; 
    gettimeofday(&tv, NULL);  
    int curr_system_time = tv.tv_sec*1000+tv.tv_usec/1000;//ms 
    // 逐行读取输入
    while (1) {
        getline(&line, &line_len, stdin);
        // 1. 查找文件名
        if (!file && strstr(line, "filename=\"")) {
            char *filename_start = strstr(line, "filename=\"") + 10;
            char *filename_end = strchr(filename_start, '\"');
            if (!filename_end) continue; // 格式错误
            
            *filename_end = '\0'; // 截断文件名
            //snprintf(filepath, sizeof(filepath), "%s/%d_%s.tar.gz", UPLOAD_DIR, curr_system_time, filename_end);
            
            snprintf(filepath, sizeof(filepath), "%s/%s", UPLOAD_DIR, filename_start);

            
            sprintf(buffer, "rm %s -rf", filepath);
            system(buffer);  

            // 打开文件
            if (!(file = fopen(filepath, "wb"))) {
                printf("Status: 500\r\nContent-Type: application/json\r\n\r\n"
                       "{\"code\":1, \"msg\":\"Failed to open file\"}");
                SAFE_FREE(line);
                return;
            }

            // 跳过头部剩余部分直到空行 
		while (getline(&line, &line_len, stdin) != -1 && strcmp(line, "\r\n") != 0) {
		    free(line);
		    line = NULL;
		}
            SAFE_FREE(line);
            break;
        } 
        SAFE_FREE(line);   
    }
    
        
    int file_len=atoi(getenv("CONTENT_LENGTH"));
    char *http_buf=(char *)malloc(file_len+1);
	if (http_buf == NULL) {
	    printf("malloc fail.\r\n");
	    return;
	}
	memset((char *)http_buf,0x0,file_len+1);
	char *tmp = http_buf;
	int readlen = 0; 
	int ret = 0;
	int temp_len = file_len;
	int read_count = 0;
	while (temp_len) {
	    readlen = (temp_len > 1024) ? 1024 : temp_len;
	    ret =fread(tmp, 1, readlen, stdin); 
	    if(readlen != ret) {
	    	read_count += ret;
		//printf("failed to read len %d size %d\r\n", readlen, ret);
		break;
	    }
	    read_count += ret;
	    tmp += readlen;
	    temp_len -= readlen;
	}
	tmp = http_buf;
	#if 1
	read_count -= 2 + strlen(boundary) + 2;
        fwrite(tmp, 1,  read_count, file);
	#else
	if (tmp[0] = '\n'){
		tmp += 1;
		read_count -= 1;
	}else if (tmp[0] = '\r' && tmp[1] == '\n'){
		tmp += 2;
		read_count -= 2;
	} 
        char *end = memstr(tmp, read_count , boundary);
        if (end == NULL){       
	    fwrite(tmp, 1,  read_count, file);
        }else{
 		read_count = end - tmp + 1;
        
		fwrite(tmp, 1,  read_count, file);
	}
	#endif
        
	printf("Status: 200 OK\r\n");
	printf("Content-Type: application/json\r\n\r\n");
	printf("{\"code\": 0, \"boundary\":\"%s\", \"msg\": \"File uploaded successfully\"}", boundary);
    free(http_buf);

    // 清理残留
    if (file) fclose(file);
    SAFE_FREE(line);
}

int main() {
    // 创建上传目录
    create_upload_dir();

    // 获取 Content-Type 中的 boundary
    char *content_type = getenv("CONTENT_TYPE");
    if (!content_type || !strstr(content_type, "multipart/form-data")) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"code\": 1, \"msg\": \"Invalid content type ,%s\"}", content_type);
        return 1;
    }

    char *boundary_start = strstr(content_type, "boundary=");
    if (!boundary_start) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"code\": 1, \"msg\": \"No boundary found\"}");
        return 1;
    }

    boundary_start += 9; // 跳过 "boundary="
    char boundary[1024];
    snprintf(boundary, sizeof(boundary), "--%s--", boundary_start);

    // 解析上传数据
    parse_multipart_data(boundary);

    return 0;
}



deepseek给的几个版本,上传的文件,写出来的内容总是差很多个字节。细节处理包括:

1、回车符号的处理;

2、分隔符的处理,特别是分隔符号的长度处理,--%s--,这也是调试才能发现的问题。

3、读数据到缓冲区,然后一次性写入文件内容的处理。


-------------------广告线---------------
项目、合作,欢迎勾搭,邮箱:promall@qq.com


本文为呱牛笔记原创文章,转载无需和我联系,但请注明来自呱牛笔记 ,it3q.com

请先登录后发表评论
  • 最新评论
  • 总共0条评论