Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get file from POST data in Bash CGI script?

Tags:

bash

curl

cgi

I am trying to post a file using cURL and receive it on the other side via a CGI Bash script and store it with the same name. After upload is completed, diff between the original file and reconstructed one should return zero.

The way cURL sends data:

curl --request POST --data-binary "@dummy.dat" 127.0.0.1/cgi-bin/upload-rpm

Receiver script:

#!/bin/bash

echo "Content-type: text/html"
echo ""

echo '<html>'
echo '<head>'
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
echo '<title>Foo</title>'
echo '</head>'
echo '<body>'

echo "<p>Start</p>"

if [ "$REQUEST_METHOD" = "POST" ]; then
    echo "<p>Post Method</p>"
    if [ "$CONTENT_LENGTH" -gt 0 ]; then
        echo "<p>Size=$CONTENT_LENGTH</p>"
        while read -n 1 byte -t 3; do echo -n -e "$byte" >> ./foo.dat ; done
    fi
fi
echo '</body>'
echo '</html>'

exit 0

But it's not working. File is not created on the server side. And how can I get the file name?

like image 562
sorush-r Avatar asked Sep 09 '18 07:09

sorush-r


People also ask

How does the posted data come to the CGI script?

POST sends the data through standard input, while GET passes the information through environment variables. If no method is specified, the server defaults to GET.

What is CGI bash?

CGI stands for Common Gateway Interface. It is a way to let Apache execute script files and send the output to the client. Those script files can be written in any language understood by the server. Yes, you can write a CGI script using BASH, Korn shell, Perl, Python or even C! Tools of the trade.

What is Linux CGI script?

In computing, Common Gateway Interface (CGI) is an interface specification that enables web servers to execute an external program, typically to process user requests. Such programs are often written in a scripting language and are commonly referred to as CGI scripts, but they may include compiled programs.


Video Answer


1 Answers

as long as you're always uploading exactly 1 file using the multipart/form-data format and the client always put the Content-Type as the last header of the file upload (which curl always seem to do), this seem to work:

#!/bin/bash

echo "Content-type: text/html"
echo ""

echo '<html>'
echo '<head>'
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
echo '<title>Foo</title>'
echo '</head>'
echo '<body>'

echo "<p>Start</p>"

if [ "$REQUEST_METHOD" = "POST" ]; then
    echo "<p>Post Method</p>"
    if [ "$CONTENT_LENGTH" -gt 0 ]; then
    in_raw="$(cat)"
    boundary=$(echo -n "$in_raw" | head -1 | tr -d '\r\n');
    filename=$(echo -n "$in_raw" | grep --text --max-count=1 -oP "(?<=filename=\")[^\"]*");
    file_content=$(echo -n "$in_raw" | sed '1,/Content-Type:/d' | tail -c +3 | head --lines=-1 | head --bytes=-4  );
    echo "boundary: $boundary"
    echo "filename: $filename"
    #echo "file_content: $file_content"
    fi
fi
echo '</body>'
echo '</html>'

exit 0

example upload invocation (which I used to debug the above):

curl http://localhost:81/cgi-bin/wtf.sh -F "[email protected]"
  • with all that said, THIS IS INSANITY! bash is absolutely not suitable for handling binary data, such as http file uploads, use something else. (PHP? Python?)
like image 183
hanshenrik Avatar answered Oct 07 '22 16:10

hanshenrik