0

I was trying to build a CLI tool in Crystal to use send-anywhere.com from the command line.

Sending multipart is not builtin in Crystal but before writing my own I thought I would try to use cURL to see how exactly I should make it but I can't even get it to work with cURL!

The issue is that when sending more than one file with cURL their server only sees 1 file incoming, they do see the total length but fail at 50% since they were only expecting one file.

What kills me is that it works in the browser, I have the network inspector open and I fail to see the difference with my cURL request. I've tried setting the Expect header to 100-continue, I've compared them but I fail to see what could make it work with the browser and not curl.

Here's the command I tried with cURL all with the same result, the server ends up seeing only 1 file incoming not 2.

For testing purposes I was using a few copies of a generic LICENSE file.

curl -F file1=@LICENSE -F file2=@LICENSE1 https://...their.weblink...

I've seen in the inspector that Chrome names the file name="file[]" in Content-Disposition, so I tried it myself (same result):

curl -F file[]=@LICENSE -F file[]=@LICENSE1 https://...their.weblink...

I also tried these 2 commands using -H "Expect: 100-continue" with same result.

At this point I got mad and thought I'd try it myself, maybe cURL can't do it properly (highly unlikely imo, much higher chance that I'm doing something wrong).

So before writing it from scratch I tried an implementation that was used by a Telegram bot see here: https://github.com/hangyas/TelegramBot/blob/b3fcbbb621bd669bbafe9f3e91364702d06d1e10/src/TelegramBot/http_client_multipart.cr

It's pretty straightforward but I still get the same issue. Only the first file is recognized.

Note: everything works fine with both cURL and the Crystal implementation when sending only one file.

I'm going crazy, what's the difference between the browser which works and the other two? What am I not seeing?

I'm not looking for an implementation but just for someone to point out what I missed that would make multiple files recognized correctly?

4

1 回答 1

2

这仅用于教育目的,实际上这样做违反了服务条款。它有一个记录在案的 API,你应该在给定 API 密钥后改用它。

正确地向key端点宣布文件数很重要。所以整个流程是这样的:

#!/bin/bash

# First we need to get a device key by registering ourselves as a
# device. For that we need a profile name. We need to store the
# received cookie and send it with the subsequent request.
profilename="$(openssl rand -hex 6)"
curl -c .session -vL https://send-anywhere.com/web/device \
  -d "os_type=web" \
  -d "profile_name=$profilename" \
  -d "manufacturer=Linux" \
  -d "model_number=Firefox" \
  -d "app_version=48" \
  -d "device_language=en-US"

# We need to know the individual filesizes in bytes as well as
# the total size we're going to upload
file0name="foo.txt"
file0size="$(wc -c "$file0name" | cut -d ' ' -f 1)"
file1name="bar.txt"
file1size="$(wc -c "$file1name" | cut -d ' ' -f 1)"
filesize="$(echo "$file0size + $file1size" | bc)"

# Using that info and the cookie we got from the device key
# we can correctly announce our upload
key="$(curl -b .session -vL https://send-anywhere.com/web/key \
  -d "file[0][name]=$file0name" -d "file[0][size]=$file0size" \
  -d "file[1][name]=$file1name" -d "file[1][size]=$file1size" \
  -d "file_number=2" -d "file_size=$filesize")"

# We get some JSON back with the URL to send to the receiver
# and the URL to upload back
url="$(echo "$key" | ruby -rjson -e 'print JSON.parse($stdin.read)["link"]')"
upload_url="$(echo "$key" | ruby -rjson -e 'print JSON.parse($stdin.read)["weblink"]')"

echo
echo "------------------------------------------------------------"
echo "Receive 2 files of $filesize bytes at $url"
echo "------------------------------------------------------------"
echo

# And finally do the upload
curl -vL "$upload_url" \
  -F "file[]=@$file0name" \
  -F "file[]=@$file1name"
于 2016-08-16T19:36:31.257 回答