# nginx-upload-return-200 **Repository Path**: dev_ma/nginx-upload-return-200 ## Basic Information - **Project Name**: nginx-upload-return-200 - **Description**: nginx with upload module and return 200 without upstream backend - **Primary Language**: C - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2025-01-05 - **Last Updated**: 2026-07-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # nginx-upload-return-200 * [介绍](#介绍) * [成功运行平台](#成功运行平台) * [安装编译环境](#安装编译环境) * [1. Cygwin环境](#1--cygwin环境) * [2. MinGW64环境](#2--mingw64环境) * [3. MinGW32环境](#3--mingw32环境) * [4. Ubuntu环境](#4--ubuntu环境) * [4. AlpineLinux环境](#4--alpinelinux环境) * [使用说明](#使用说明) * [1. 编译](#1--编译) * [2. 模块加载](#2--模块加载) * [3. Nginx UTF8](#3--nginx-utf8) * [4. C99 variadic macros](#4--c99-variadic-macros) * [5. curl post](#5--curl-post) * [上传](#上传) * [断点续传](#断点续传) * [Post body sample](#post-body-sample) * [UTF-8 filename](#utf-8-filename) * [6. Run nginx and dump logs](#6--run-nginx-and-dump-logs) * [7. Check uploaded files](#7--check-uploaded-files) * [8. Check errors in log](#8--check-errors-in-log) * [补丁文件](#补丁文件) * [1. http-upload-module patch](#1-http-upload-module-patch) * [2. nginx-release patch](#2-nginx-release-patch) * [3. markdown.perl.patch](#3-markdownperlpatch) * [工具](#工具) * [1. gen-rd-patches.sh](#1-gen-rd-patchessh) * [2. apl-rd-patches.sh](#2-apl-rd-patchessh) * [3. gen-md-toc.sh](#3-gen-md-tocsh) * [4. playList.html](#4-playlisthtml) * [5. upload.js](#5-uploadjs) * [SSH via SSL tunnel](#ssh-via-ssl-tunnel) * [Nginx用作coturn桥](#nginx用作coturn桥) * [使用桥接口令](#使用桥接口令) * [已知问题](#已知问题) * [1. Microsoft-WebDAV-MiniRedir of Windows File Explorer not work with Webdav via https](#1-microsoft-webdav-miniredir-of-windows-file-explorer-not-work-with-webdav-via-https) * [2. MinGW UCRT64 console fails to run cmd.exe with commands](#2-mingw-ucrt64-console-fails-to-run-cmdexe-with-commands) ## 介绍 一个程序独立运行 Nginx with upload module and return 200 without upstream backend. Ningx服务器集成多个功能,包括文件上传和webdav。 编译 ``` sh build.nginx.sh ``` Yocto build请参见"meta-poky-patch/README.txt". 运行 ``` # run in MinGW, Cygwin and Linux ( set -xv; cd nginx-release-1.24.0._install && mkdir -p logs temp && sbin/nginx -p $(pwd) -c conf/nginx.conf; echo $? ) # run in cmd.exe cmd /c "echo on && cd nginx-release-1.24.0._install && sbin\nginx -p . -c conf/nginx.conf && echo cmd.exe run nginx OK" ``` 浏览器中查探 http://127.0.0.1:8080 cmd.exe中可以直接运行Cygwin和MinGW中编译出来的。 ## 成功运行平台 俺旧电脑编译环境 ``` uname -a gcc -v ``` Ubuntu 20.04.1 LTS in LXC container, x86\_64-linux-gnu gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) CYGWIN\_NT-10.0 hostname 2.5.2(0.297/5/3) 2016-06-23 14:29 x86\_64 Cygwin, x86\_64-pc-cygwin gcc version 5.4.0 (GCC) MINGW64\_NT-10.0-17134 hostname 3.4.10.x86\_64 2023-12-22 10:06 UTC x86\_64 Msys, x86\_64-w64-mingw32 gcc version 13.2.0 (Rev3, Built by MSYS2 project) MINGW32\_NT-6.2 hostname 1.0.19(0.48/3/2) 2016-07-13 17:45 i686 Msys, mingw32 gcc version 6.3.0 (MinGW.org GCC-6.3.0-1) ## 安装编译环境 ### 1. Cygwin环境 最接近俺的是这个版本 ``` http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/setup/snapshots/setup-x86_64-2.874.exe http://www.crouchingtigerhiddenfruitbat.org/Cygwin/timemachine.html ``` 安装 ``` setup-x86_64.exe --help setup-x86_64.exe --no-admin --package-manager --only-site --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2016/07/25/221302 --no-verify --local-package-dir %cd% ``` 得安装GCC-5.4和libcrypt-devel。 ### 2. MinGW64环境 俺用的是这个版本 ``` https://repo.msys2.org/distrib/x86_64/ https://github.com/msys2/msys2-installer/releases/tag/2024-01-13 msys2-base-x86_64-20240113.tar.xz ``` 安装GCC 在ucrt64终端窗口中安装 mingw-w64-ucrt-x86\_64-gcc 13.2.0-3 并运行编译。 ``` pacman -v -S mingw-w64-ucrt-x86_64-gcc ``` 在mingw64终端窗口中安装 mingw-w64-x86\_64-gcc 13.2.0-3 并运行编译。 ``` pacman -v -S mingw-w64-x86_64-gcc ``` 安装libcrypt-devel ``` pacman -v -S libxcrypt-devel ``` 安装所需工具 ``` pacman -v -S patch diffutils make unzip ``` ### 3. MinGW32环境 俺用的是这个版本 ``` https://sourceforge.net/projects/mingw/files/Installer/ mingw-get-setup.exe 0.6.2-beta-20131004-1, 0.602.22340.1 ``` 木有命令行,只能点鼠标。安装gcc-6.3和libcrypt-devel。 ### 4. Ubuntu环境 Ubuntu 20.04.1 LTS, x86\_64-linux-gnu gcc-9.3.0 Host lxd and lxc version 4.0.10. ``` https://documentation.ubuntu.com/lxd/ ``` 俺电脑快满盘了,木有再试docker。 ### 4. AlpineLinux环境 Alpine Linux v3.11, x86\_64-alpine-linux-musl gcc-9.3.0 ``` apk add gcc g++ make musl-dev gcompat xz tar perl patch ``` Busybox patch utility has bug, may mistakenly apply patch to wrong block when multiple identical blocks of context exist in large file. Use GNU patch utility. ## 使用说明 ### 1. 编译 遇事不决看帮助 ``` sh build.nginx.sh -h ``` 有问题先运行 ``` sh -xv build.nginx.sh -vv 2>&1 | tee build.nginx.log ``` 再查看build.nginx.log ### 2. 模块加载 模块加载多出在依赖库跟nginx.exe不在一个目录,或者库文件名木进符号表。 ``` # In MinGW64 and Cygwin, check loaded dll and so files in proc maps file "/proc//maps". grep -i -e '\.so' -e '\.dll' /proc/54321/maps # check symble table objdump -x nginx-release-1.24.0.build/objs/ngx_http_dav_ext_module.so | grep NEEDED ``` MinGW GCC-6.3有个缺陷 Need linker options: -static-libgcc -static-libstdc++ Or need dll file: libgcc\_s\_dw2-1.dll ``` https://stackoverflow.com/questions/4702732/the-program-cant-start-because-libgcc-s-dw2-1-dll-is-missing ``` ### 3. Nginx UTF8 Nginx-1.20 built in MinGW autoindex module output charset is CP936 (GB2312). But built in Cygwin autoindex output charset is UTF-8. In Windows and MinGW, autoindex charset shall match "Current code page" of "cmd.exe". In Linux and Cygwin, autoindex charset shall match "LANG" and "LC\_" env var of bash. In Windows and nginx is built by MinGW, When charset is not utf-8, browser display well, but cannot download file. To solve this problem, patches needed. The fix is merged since nginx-1.23.4. ``` https://github.com/myfreeer/nginx-build-msys2 https://github.com/nginx/nginx/commits/release-1.23.4/src/os/win32 ``` 一言难尽,上代码。 ``` /* # Test gcc string encoding and terminal charset # # Check charset of terminal # Mintty Terminal emulator settings -> Text -> Character set # Windows cmd.exe window -> Properties -> Current code page # # Compile ( set -xv; env | grep -i -e utf -e LC_ -e LANG; gcc -g -Wall -o u utf8.c && ( LC_ALL=en_US.UTF-8; LC_CTYPE=en_US.UTF-8; LANG=en_US.UTF-8; export LC_CTYPE LC_ALL LANG; gcc -g -Wall -o u.e utf8.c ) && gcc -fexec-charset=utf-8 -g -Wall -o u.fu utf8.c && gcc -fexec-charset=gb2312 -g -Wall -o u.fg utf8.c; echo rt=$? ) # # Run tests in Cygwin, MinGW32 and MinGW64 ( set -xv; env | grep -i -e utf -e LC_ -e LANG; ./u && ./u.e && ./u.fu && ./u.fg && ( LC_ALL=en_US.UTF-8; LC_CTYPE=en_US.UTF-8; LANG=en_US.UTF-8; export LC_CTYPE LC_ALL LANG; ./u.e ) && ./u | iconv -f utf-8 -t cp936 && ./u.fg -f gb2312 -t utf-8 && ./u | iconv -f cp936 -t utf-8 && ./u.fg -f utf-8 -t gb2312; echo rt=$? ) # Run tests in Windows cmd.exe cmd /c "echo on && .\u && .\u.e && .\u.fu && .\u.fg && echo OK" */ #include int main( int argc, char * agrv[]) { printf("Hello.\n"); printf("LuanMa乱码LuanMa\n"); printf("End.\n"); // return 0; } ``` 在各种终端运行更头晕。 ### 4. C99 variadic macros 好东西,好使。 ``` https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html https://en.wikipedia.org/wiki/Variadic_macro_in_the_C_preprocessor ``` ### 5. curl post #### 上传 上传文件b.log和t.exe ``` ( set -xv; history | tail -n1; curl --output - --dump-header - --include --verbose --progress-bar --insecure --user usr:123 -F "useruploadfile[]=@\"b.log\"" -F "useruploadfile[]=@\"t.exe\"" -F "description=SomeDescription" http://127.0.0.1:8080/ptupload/doupload && d=nginx-release-1.24.0._install/logs && for i in $d/*.log; do cat $i; done; echo rt=$? ) 2>&1 | tee curl.upload.log ``` #### 断点续传 ``` ( set -xv; history | tail -n1; f=b.log; s=$(stat -c %s "$f"); e=$(( $s / 2 + 1)); dd if="$f" of="$f.pt1" bs=$e count=1 && curl --output - --dump-header - --include --verbose --progress-bar --insecure --user usr:123 -H "Session-ID: 0123456789" -H "Content-Range: bytes 0-$(( $e - 1 ))/$s" -H "Content-Type: application/octet-stream" -H "Content-Disposition: form-data; name=\"useruploadfile.name\"; filename=\"$f\"" --data-binary @"$f.pt1" http://127.0.0.1:8080/ptupload/doupload && dd if="$f" of="$f.pt2" bs=$e skip=1 count=1 && curl --output - --dump-header - --include --verbose --progress-bar --insecure --user usr:123 -H "Session-ID: 0123456789" -H "Content-Range: bytes $e-$(( $s - 1 ))/$s" -H "Content-Type: application/octet-stream" -H "Content-Disposition: form-data; name=\"useruploadfile.name\"; filename=\"$f\"" --data-binary @"$f.pt2" http://127.0.0.1:8080/ptupload/doupload && d=nginx-release-1.24.0._install/logs && for i in $d/*.log; do cat $i; done; echo rt=$? ) 2>&1 | tee curl.upload.log ``` 参考资料 ``` https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range https://curl.se/docs/manpage.html#--data-binary ``` #### Post body sample ``` --------------------------d2f4c15433d52118 Content-Disposition: form-data; name="useruploadfile.name" "b.log" --------------------------d2f4c15433d52118 # Content-Disposition: form-data; name="file1"; filename="..."^M # Content-Type: application/octet-stream^M ``` #### UTF-8 filename curl-7.64 failed to post UTF-8 filename, curl-8.5 works well. ``` https://superuser.com/questions/1338056/how-can-i-upload-a-file-using-curl-instead-of-the-form https://github.com/curl/curl/issues/1888 ( set -xv; history | tail -n1; curl --output - --dump-header - --include --verbose --progress-bar --insecure -H "Content-Type: multipart/form-data; charset=UTF-8" --user usr:123 -F "useruploadfile[]=@\"b.log\"" -F "file=@\"莫言 :人类的好日子不多了,文学也将毫无意义.html\";filename*=utf-8''\"莫言:人类的好日子不多了 ,文学也将毫无意义.html\"" -F "description=SomeDescription" http://127.0.0.1:8080/ptupload/doupload && d=nginx-release-1.24.0._install/logs && for i in $d/*.log; do echo cat $i; done; echo rt=$? ) 2>&1 ``` ### 6. Run nginx and dump logs ``` ( set -xv; cd nginx-release-1.24.0._install || exit $?; mkdir -p logs temp && echo | tee logs/access.log logs/error.log && { tail -F logs/* logs/nginx.pid & eval pt=\$\!; ( set +xv; while true; do sleep 3; [ -e logs/nginx.pid ] || break; done; set -xv; kill $pt; sleep 1; ps -ef | grep -i -e nginx -e tail ) & } && pwd && sbin/nginx -p $(pwd) -c conf/nginx.conf ; echo $? ) ``` ### 7. Check uploaded files ``` ( set -xv; d=nginx-release-1.24.0._install/upload/upload_store; find "$d/" -name '*.sum.txt' | while read f; do i=${f%.sum.txt}; printf "%s *$i\n" $(grep -o -e 'md5=.*' "$f" | cut -d= -f2) | tee -a _s_.md5.txt && printf "%s *$i\n" $(grep -o -e 'sha256=.*' "$f" | cut -d= -f2) | tee -a _s_.sha256.txt || exit $?; done && md5sum -c _s_.md5.txt && sha256sum -c _s_.sha256.txt && rm _s_.md5.txt _s_.sha256.txt; echo rt=$? ) ``` ### 8. Check errors in log ``` grep -i -e Unexpect -e fail -e error -e abnorm -e abort nginx-release-1.24.0._install/logs/error.log | grep -v -e SSL_get_error -e 'http script value' -e 'http script var' ``` ## 补丁文件 补丁文件都放在patches目录。 ### 1. http-upload-module patch 源码来自:`https://github.com/fdintino/nginx-upload-module` 采用版本:2.3.0 新增功能和配置参数请参考"README.en.md" ### 2. nginx-release patch 主要针对MinGW和Cygwin中编译遇到的问题。 源码来自:`https://github.com/nginx/nginx/` 采用版本:1.24.0 从官网(nginx.org)下载的源码无法在MinGW中编译。"src/os/win32" only exists in source tarball from github. ### 3. markdown.perl.patch Ubuntu有个工具markdown,将markdown文档转成html。 源码来自:`https://daringfireball.net/projects/downloads/Markdown_1.0.1.zip` Ubuntu有改动。此处再次改动,更好支持code block。 ## 工具 期间用到几个小工具。 ### 1. gen-rd-patches.sh 将改动分成Debug补丁和Realease补丁。 ### 2. apl-rd-patches.sh 将Debug补丁和Release补丁补到指定文件。 ### 3. gen-md-toc.sh 给markdown文档生成目录。可顺带转html。 ### 4. playList.html 网页MP3播放器。可配合nginx autoindex使用,也可离线使用playList.js。 ### 5. upload.js 使用Selenium WebDriver的nodejs脚本,驱动浏览器上传文件。 ## SSH via SSL tunnel 利用Nginx stream_ssl和stream_ssl_preread,可复用TCP 443端口,既用作HTTPS又用作SSH。 MinGW中ssh运行流畅,git-bash中有卡顿且需要"-o ServerAliveInterval=3"保持刷新. Openssl needs "-ign_eof" to void failure: SSL routines:SSL_key_update:wrong ssl version:ssl/ssl_lib.c Openssl needs "-servername" to send TLS SNI. Use "-tlsextdebug" to show SNI debug message. Use "-tls1_2" to specify "TLSv1.2" version. Nginx shall be built with "TLS SNI support enabled". ``` nginx -V 2>&1 | grep -i -e sni -e sna ``` Nginx server IP 192.168.1.251. Run ssh client ``` ssh -o ServerAliveInterval=3 -o ProxyCommand="openssl s_client -ign_eof -servername %h.mysvr.com -connect 192.168.1.251:443" svra ``` If Mutual TLS used, run ssh client as below. ``` ssh -v -o ServerAliveInterval=3 -o ProxyCommand="openssl s_client -ign_eof -servername %h -connect 192.168.1.251:443 -cert client.crt -key client.key -CAfile ca.crt" svra.mysvr.com ``` ## Nginx用作coturn桥 Nginx和socat一起用作端口桥接,类似coturn。 Nginx配置请参见"stream.conf",socat桥请参见"nginx.socat.bridge.sh"。 Socat嵌套可避免从端不随主端一同退出的问题。 Run socat as bridge to cooperate with nginx. ``` ( set -xv; history | tail -n1; socat -d -d TCP4-LISTEN:51231,bind=127.0.0.1,fork,reuseaddr exec:"socat \"-d -d TCP4-LISTEN:51232,bind=127.0.0.1,reuseaddr -\"" ) 2>&1 | tee socat.bridge.log ``` In second remote server, forward its local service port to nginx server, mutual TLS used. ``` ( set -xv; while true; do date -Is; socat -d -d -T29 exec:"openssl \"s_client -quiet -ign_eof -servername pa.mysvr.com -connect 192.168.1.251:443 -cert client.crt -key client.key -CAfile ca.crt\"" tcp4:127.0.0.1:22; sleep 5; done ) 2>&1 | tee forwardport.log ``` Client connect second remote server via nginx bridge. ``` ssh -v -o ServerAliveInterval=3 -o ProxyCommand="openssl s_client -ign_eof -tlsextdebug -servername %h -connect 192.168.1.251:443" pb.mysvr.com ``` Nginx server IP 192.168.1.251. Second server IP 192.168.58.251. Another example, forward port of local http server to remote nginx server, mutual TLS used. ``` # socat-1.7.4 supports option "snihost" ( set -xv; socat -d -d -d -d OPENSSL:192.168.1.251:443,commonname=mysvr.mysvr.com,snihost=pa.mysvr.com,cert=client.crt,key=client.key,cafile=ca.crt TCP4-CONNECT:192.168.58.251:80; echo $? ) ``` Client connect it via nginx bridge. ``` printf "GET / HTTP/1.1\r\nHost: mysvr.mysvr.com\r\nConnection: keep\r\n\r\n" | openssl s_client -ign_eof -tlsextdebug -servername pb.mysvr.com -connect 192.168.1.251:443 ``` Optional, add static DNS. ``` # grep -e mysvr /c/Windows/System32/drivers/etc/hosts # grep -e mysvr /etc/hosts 192.168.1.251 mysvr.com mysvr.mysvr.com pa.mysvr.com pb.mysvr.com ``` ### 使用桥接口令 口令验证可放在原server端,也可放在Nginx上。具体验证代码请参见“nginx.socat.bridge.sh”中的“psck”段。 简易桥接管理请参见“nginx.bridge.html”和“nginx.bridge.sh”。 Nginx server IP 192.168.1.251. Second server IP 192.168.58.251. 在原server端验证口令 ``` # check passcode before forward connect to server socat -d -d -T29 EXEC:"openssl \"s_client -quiet -ign_eof -servername pa.mysvr.com -connect 192.168.1.251:443 -cert client.1.crt -key client.1.key -CAfile ca.crt\"" EXEC:"socat \"-d -d -d -d EXEC:./psck.sh,fdin=6,fdout=7 TCP4:192.168.58.251:80\"" # ( set -xv; socat -d -d -d -d OPENSSL:192.168.1.251:443,commonname=mysvr.mysvr.com,snihost=pa.mysvr.com,cert=client.1.crt,key=client.1.key,cafile=ca.crt EXEC:'socat "-d -d -d -d EXEC:./psck.sh,fdin=6,fdout=7 TCP4-CONNECT:192.168.58.251:80"'; echo $? ) ``` 用户端先发口令,通过验证之后才能继续。 ``` # client side provides passcode printf "psc\nGET / HTTP/1.1\r\nHost: mysvr.mysvr.com\r\nConnection: keep\r\n\r\n" | openssl s_client -ign_eof -tlsextdebug -servername pb.mysvr.com -connect 192.168.1.251:443 ``` SSH server and clinet ``` # forward port of local sshd server to remote nginx server, mutual TLS used # use nc to connect local server socat -d -d -T29 EXEC:"openssl \"s_client -quiet -ign_eof -servername pa.mysvr.com -connect 192.168.1.251:443 -cert client.1.crt -key client.1.key -CAfile ca.crt\"" SYSTEM:'set -xv; read -r i; [ "$i" = "psc" ] || { echo "psc failed!" >&2; exit 1; }; cat | nc -v 127.0.0.1 22' # ssh client provide passcode to connect ssh -v -o ServerAliveInterval=3 -o ProxyCommand="sh -xvc '{ echo psc; cat; } | openssl s_client -ign_eof -tlsextdebug -servername %h -connect 192.168.1.251:443'" pb.mysvr.com ``` ## 已知问题 ### 1. Microsoft-WebDAV-MiniRedir of Windows File Explorer not work with Webdav via https Firefox webdav plugin works well with webdav, both http and https. ``` https://github.com/WebDAVDevs/webdav-browser-extension ``` Microsoft-WebDAV-MiniRedir can connect http webdav, but failed to connect https webdav. It can view, move and delete files, but can only create empty new file, until apply this patch to support PROPPATCH. ``` https://github.com/arut/nginx-dav-ext-module/issues/52 https://github.com/arut/nginx-dav-ext-module/files/3835180/proppatch.patch.gz ``` ### 2. MinGW UCRT64 console fails to run cmd.exe with commands MinGW UCRT64 minitty-3.7.0 fails to run cmd.exe with commands. For example, command line below expects to return 0, but will stuck in cmd.exe: ``` ( set -xv; cmd.exe /c "echo test"; echo rt=$? ) ``` 解决方法:使用"//c"。