2022/10/15

Nginx上傳模組(續)

摘要

本文概要介紹使用Nginx上傳模組搭配後端程式mini_httpd進行檔案上傳。 

本文

承前,基於Nginx上傳模組mini_httpd套件,令前者作為反向代理伺服器(reverse proxy)、並使用後者作為後端程式,以處理上傳完畢的後續動作。

修改Nginx組態設置,於上傳完畢時轉向至後端程式;留意location參數、和proxy_pass參數。

 

建構mini_httpd套件、並編輯組態設置;留意port參數、cgipat參數、及套件版本。

wget https://acme.com/software/mini_httpd/mini_httpd-1.27.tar.gz --no-check-certificate
tar -zxvf mini_httpd-1.27.tar.gz

cd mini_httpd-1.27
make
sudo make install

sudo mkdir -p /web/html
sudo chmod a+rw /web/
sudo echo -e "nochroot\nuser=root\nport=8081\ndir=/web/html\ncgipat=**.cgi\npidfile=/web/mini_httpd.pid\nlogfile=/web/mini_httpd.log\ncharset=UTF-8\n" > /web/mini_httpd.conf


sudo /usr/local/sbin/mini_httpd -C /web/mini_httpd.conf

 

撰寫基於mini_httpd的CGI程式upload.c,如下,以便於POST上傳結束後呈現相關資訊;留意各個參數係透過STDIN、和環境變數取得,以及解析參數時的識別字串。

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static int traverse_parameter(char* str, int sz, const char* fmt)
{
	if(NULL == str || 0 == sz || NULL == fmt)
	{
		return -1;
	}

	const char* PATT1 = "Content-Disposition: form-data; name=\"";
	size_t len_patt1 = strlen(PATT1);
	const char* PATT2 = "\"\r\n\r\n";
	size_t len_patt2 = strlen(PATT2);
	const char* PATT3 = "\r\n--------------------------";
	size_t len_patt3 = strlen(PATT3);

	char* p1 = NULL;
	char* p2 = NULL;
	char* p3 = NULL;
	p1 = strstr(str, PATT1);
	int err = (NULL == p1)?(-1):(0);
	while(NULL != p1)
	{
		p2 = strstr(p1 + len_patt1, PATT2);
		if(NULL != p2)
		{
			p3 = strstr(p2 + len_patt2, PATT3);
			if(NULL != p3)
			{
				char k[64] = {'\0'};
				memcpy(k, p1 + len_patt1, p2 - (p1 + len_patt1));
				char v[256] = {'\0'};
				memcpy(v, p2 + len_patt2, p3 - (p2 + len_patt2));
				printf(fmt, k, v);
				p1 = strstr(p3 + len_patt3, PATT1);
			}
			else
			{
				err = -1;
				break;
			}
		}
		else
		{
			err = -1;
			break;
		}
	}

	return err;
}

int main(void)
{
	printf("Content-type: application/json; charset=utf-8\n");
	printf("\n\n");
	printf("{\n");
	printf("\"HTTP_USER_AGENT\": \"%s\",\n", getenv("HTTP_USER_AGENT"));
	printf("\"REQUEST_METHOD\": \"%s\",\n", getenv("REQUEST_METHOD"));
	char* query_str = getenv("QUERY_STRING");
	if(NULL != query_str)
	{
		printf("\"QUERY_STRING\": \"%s\",\n", query_str);
	}
	char* c_l_str = getenv("CONTENT_LENGTH");
	if(NULL != c_l_str)
	{
		printf("\"CONTENT_LENGTH\": \"%s\",\n", c_l_str);
		char parameter_str[2048] = {'\0'};
		int parameter_sz = atoi(c_l_str);
		(void)fread(parameter_str, parameter_sz, sizeof(char), stdin);
		const char* fmt_kvp = "\"%s\": \"%s\",\n";
		(void)traverse_parameter(parameter_str, parameter_sz, fmt_kvp);
	}
	printf("\"HTTP_HOST\": \"%s\",\n", getenv("HTTP_HOST"));
	printf("\"REMOTE_ADDR\": \"%s\",\n", getenv("REMOTE_ADDR"));
	printf("}\n");
	return EXIT_SUCCESS;
}


建構前述的CGI程式,並且擺放至組態設置所指定的目錄。

gcc -o upload.cgi upload.c
sudo cp upload.cgi /web/html/


因應組態設置來分別執行Nginx與mini_httpd。


使用curl進行檔案上傳測試;可以POST、且會接收到上傳檔案的相關資訊;留意JSON格式編排的各個鍵值對(key-value pair)。


完成。

 

參考文獻

https://www.796t.com/content/1549294049.html
https://bingbig.github.io/gossip/cURL_multipart_form-data.html
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
https://www.w3.org/Security/Faq/wwwsf4.html
https://blog.csdn.net/sidemap/article/details/101750798

 

沒有留言:

張貼留言