J'essaie de publier un fichier en utilisant cURL et de le recevoir de l'autre côté via un script CGI Bash et de le stocker avec le même nom. Une fois le téléchargement terminé, diff
entre le fichier d'origine et le fichier reconstruit doit retourner zéro.
La façon dont cURL envoie les données:
curl --request POST --data-binary "@dummy.dat" 127.0.0.1/cgi-bin/upload-rpm
Script récepteur:
#!/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
Mais ça ne marche pas. Le fichier n'est pas créé côté serveur. Et comment puis-je obtenir le nom du fichier?
tant que vous téléchargez toujours exactement 1 fichier à l'aide du multipart/form-data
format et le client met toujours le Content-Type
en tant que dernier en-tête du téléchargement du fichier (ce que semble toujours faire curl), cela semble fonctionner:
#!/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
exemple d'invocation de téléchargement (que j'ai utilisé pour déboguer ce qui précède):
curl http://localhost:81/cgi-bin/wtf.sh -F "[email protected]"
Avec champs:
curl --data "param1=value1¶m2=value2" https://example.com/resource.cgi
Avec des champs spécifiés individuellement:
curl --data "param1=value1" --data "param2=value2" https://example.com/resource.cgi
Multipart:
curl --form "[email protected]" https://example.com/resource.cgi
Multipart avec des champs et un nom de fichier:
curl --form "[email protected];filename=desired-filename.txt" --form param1=value1 --form param2=value2 https://example.com/resource.cgi
Pour un HTTP RESTful POST contenant XML:
curl -X POST -d @filename.txt http://example.com/path/to/resource --header "Content-Type:text/xml"
ou pour JSON, utilisez ceci:
curl -X POST -d @filename.txt http://example.com/path/to/resource --header "Content-Type:application/json"
Cela lira le contenu du fichier nommé filename.txt et l'enverra comme demande de publication.
Pour plus d'informations, voir
Comment obtenir la longueur du contenu:
if [ "$REQUEST_METHOD" = "POST" ]; then
if [ "$CONTENT_LENGTH" -gt 0 ]; then
read -n $CONTENT_LENGTH POST_DATA <&0
echo "$CONTENT_LENGTH"
fi
fi
Pour enregistrer un fichier binaire ou texte:
boundary=$(export | \
sed '/CONTENT_TYPE/!d;s/^.*dary=//;s/.$//')
filename=$(echo "$QUERY_STRING" | \
sed -n '2!d;s/\(.*filename=\"\)\(.*\)\".*$/\2/;p')
file=$(echo "$QUERY_STRING" | \
sed -n "1,/$boundary/p" | sed '1,4d;$d')
Le fichier téléchargé est maintenant contenu dans la variable $ file et le nom de fichier dans la variable $ filename.