So it turns out that uploading files over HTTP from a perl script using LWP isn't as obvious and straightforward as you might expect it to be. This stuff should be plainly documented, and it's not. All the examples I could find online for how to do it are about ten years old and each of them is slightly wrong, in various different ways!
So first off, yes, the right way to do this is probably
But if you really want to use LWP::UserAgent and do things manually, here are the
# You MUST specify the boundary explicitly here. You can use whatever
# unique string you like here, and it will do the right thing.
my @headers=('Content-type'=>'multipart/form-data; boundary=xYzZY');
# Notice that we're passing an arrayref, not a hashref,
# even though the contents look like a hash.
my $request=new HTTP::Request('POST'=>$url,\@headers);
# If you have other form fields you need to submit in addition
# to the file you're uploading, here's how you attach them. This is
# equivalent to:
# <input name="field1" value="value1">
# Finally, to upload your file:
'Content-disposition'=>'form-data; name="myfile"; filename="upload.csv"',
# Finally, submit the query:: my $response=$ua->request($request);
Obviously you should choose the right MIME type for the type of file you're uploading, only use valid characters for the filename, and that sort of thing. I actually haven't tested this with binary data; I assume it works but it's possible there may be some escaping required somewhere that I've skipped here. Please let me know if you notice something I've missed, but this is working for me!