httpd_post_upload.txt example: handle binary files too
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 13 Nov 2009 08:37:50 +0000 (09:37 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 13 Nov 2009 08:37:50 +0000 (09:37 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/httpd_post_upload.txt

index fd7fc2be4b14933004fdc70b36c441ebbce90f0b..9d504f48403a549c481ce2dd2100ff97b52f1fc9 100644 (file)
@@ -24,53 +24,42 @@ post_upload.cgi
 # ^M    <--------- extra empty line
 # -----------------------------29995809218093749221856446032--^M
 
-# Beware: bashism $'\r' is used to handle ^M
-
 file=/tmp/$$-$RANDOM
 
+CR=`printf '\r'`
+
 # CGI output must start with at least empty line (or headers)
 printf '\r\n'
 
-IFS=$'\r'
+IFS="$CR"
 read -r delim_line
-
-IFS=''
-delim_line="${delim_line}--"$'\r'
+IFS=""
 
 while read -r line; do
-    test "$line" = '' && break
-    test "$line" = $'\r' && break
+    test x"$line" = x"" && break
+    test x"$line" = x"$CR" && break
 done
 
-# This will not work well for binary files: bash 3.2 is upset
-# by reading NUL bytes and loses chunks of data.
-# If you are not bothered by having junk appended to the uploaded file,
-# consider using simple "cat >file" instead of the entire
-# fragment below.
+cat >"$file"
 
-while read -r line; do
+# We need to delete the tail of "\r\ndelim_line--\r\n"
+tail_len=$((${#delim_line} + 6))
 
-    while test "$line" = $'\r'; do
-       read -r line
-       test "$line" = "$delim_line" && {
-           # Aha! Empty line + delimiter! All done
-           cat <<EOF
-<html>
-<body>
-File upload has been accepted
-EOF
-           exit 0
-       }
-       # Empty line + NOT delimiter. Save empty line,
-       # and go check next line
-       printf "%s\n" $'\r' >&3
-    done
-    # Not empty line - just save
-    printf "%s\n" "$line" >&3
-done 3>"$file"
+# Get and check file size
+filesize=`stat -c"%s" "$file"`
+test "$filesize" -lt "$tail_len" && exit 1
 
-cat <<EOF
-<html>
-<body>
-File upload was not terminated with '$delim_line' - ??!
-EOF
+# Check that tail is correct
+dd if="$file" skip=$((filesize - tail_len)) bs=1 count=1000 >"$file.tail" 2>/dev/null
+printf "\r\n%s--\r\n" "$delim_line" >"$file.tail.expected"
+if ! diff -q "$file.tail" "$file.tail.expected" >/dev/null; then
+    printf "<html>\n<body>\nMalformed file upload"
+    exit 1
+fi
+rm "$file.tail"
+rm "$file.tail.expected"
+
+# Truncate the file
+dd of="$file" seek=$((filesize - tail_len)) bs=1 count=0 >/dev/null 2>/dev/null
+
+printf "<html>\n<body>\nFile upload has been accepted"