1

I need do an RFC 1867 upload to a server of the raw data (without riff headers) of a wav file. I have written a perl script to do this. Looks like this:

my $wav = new Audio::Wav;
my $read = $wav->read($wavtoupload);
my $rawdata = $read->read_raw($read->length()); #raw data w/o riff

my $url = "http://thehost.com";
my $req = HTTP::Request->new();
$req = POST $url,
   Referer => 'hxxp://www.mydomain.com/some.php3', 
   Accept_Language => 'en-us',
   Content_Type => 'form-data',
   Accept_Encoding => 'wav',
   User_Agent => 'Mozilla/4.0',
   Host => 'www.mydomain.com',
   Connection => 'Keep-Alive',
   Content => [ $rawdata ];
print $req->as_string;

my $ua = LWP::UserAgent->new;
my $resp = $ua->request($req);

if ($resp->is_success) {
   #...
}

According to http://search.cpan.org/~ether/HTTP-Message-6.11/lib/HTTP/Request/Common.pm:

"The POST method also supports the multipart/form-data content used for Form-based File Upload as specified in RFC 1867. You trigger this content format by specifying a content type of 'form-data' as one of the request headers."

However, the server is receiving Content_Type = "form-data" is doesn't like it because it expects "multipart/form-data". Also the Content_Length is 0, and the body isn't being uploaded.

What am I doing wrong? Thanks

B-Dawg
  • 13
  • 3

1 Answers1

2

You didn't post the output of:

print $req->as_string;

One thing you are doing wrong is you are not assembling your data into key/value pairs, which is how all HTTP requests organize their data.

Also the Content_Length is 0

That's because all the data is being used as the key part of a key/value pair, thus there is no value, and no value has a Content-Length of 0.

Nevertheless, the server should not be receiving the header:

Content_Type = "form-data"

For the raw request, I get:

POST http://thehost.com
Connection: Keep-Alive
Accept-Encoding: wav
Accept-Language: en-us
Host: www.mydomain.com
Referer: hxxp://www.mydomain.com/some.php3
User-Agent: Mozilla/4.0
Content-Length: 82
Content-Type: multipart/form-data; boundary=xYzZY

--xYzZY
Content-Disposition: form-data; name="mydata"

hello world
--xYzZY--

As you can clearly see, the Content-Type header is multipart/form-data. That's because:

You trigger this content format by specifying a content type of 'form-data' as one of the request headers.

In other words, the perl module creates the header Content-Type: multipart/form-data in the actual request.

Here's the code I used:

use strict;
use warnings; 
use 5.020;
use Data::Dumper;
use HTTP::Message;
use HTTP::Request::Common;

my $rawdata = "hello world";
my $url = "http://thehost.com";

my $requ = POST $url,
   Referer => 'hxxp://www.mydomain.com/some.php3', 
   Accept_Language => 'en-us',
   Content_Type => 'form-data',
   Accept_Encoding => 'wav',
   User_Agent => 'Mozilla/4.0',
   Host => 'www.mydomain.com',
   Connection => 'Keep-Alive',
   Content => [ mydata => $rawdata ];

say $requ->as_string;

The following shows the difference between specifying a key/value pair v. just specifying a value:

use strict;
use warnings; 
use 5.020;
use Data::Dumper;
use HTTP::Message;
use HTTP::Request::Common;

my $rawdata = "hello world";
my $url = "http://thehost.com";

my $requ = POST $url,
   Referer => 'hxxp://www.mydomain.com/some.php3', 
   Accept_Language => 'en-us',
   Content_Type => 'form-data',
   Accept_Encoding => 'wav',
   User_Agent => 'Mozilla/4.0',
   Host => 'www.mydomain.com',
   Connection => 'Keep-Alive',
   Content => [ 
       mykey => 'myValue',
       $rawdata, 
   ];


say $requ->as_string;

--output:--
POST http://thehost.com
Connection: Keep-Alive
Accept-Encoding: wav
Accept-Language: en-us
Host: www.mydomain.com
Referer: hxxp://www.mydomain.com/some.php3
User-Agent: Mozilla/4.0
Content-Length: 142
Content-Type: multipart/form-data; boundary=xYzZY

--xYzZY
Content-Disposition: form-data; name="mykey"  #<===HERE

myValue  #<======AND HERE
--xYzZY
Content-Disposition: form-data; name="hello world"  #<===COMPARED TO

        #<======COMPARED TO
--xYzZY--

The bare value ends up being used as the key, and because there is no value the Content-Length ends up being 0.

According to the docs, here is how you should specify a file upload:

use strict;
use warnings; 
use 5.020;
use Data::Dumper;
use HTTP::Message;
use HTTP::Request::Common;

my $rawdata = "hello world";
my $url = "http://thehost.com";

my $requ = POST $url,
   Referer => 'hxxp://www.mydomain.com/some.php3', 
   Accept_Language => 'en-us',
   Content_Type => 'form-data',
   Accept_Encoding => 'wav',
   User_Agent => 'Mozilla/4.0',
   Host => 'www.mydomain.com',
   Connection => 'Keep-Alive',
   Content => [ 
       mykey => 'myValue',         #some other key/value pair
       cool_sounds => [undef,      #file upload key/value pair
                       'myfile.wav', 
                       Content => $rawdata
                      ] 

   ];


say $requ->as_string;

--output:--
POST http://thehost.com
Connection: Keep-Alive
Accept-Encoding: wav
Accept-Language: en-us
Host: www.mydomain.com
Referer: hxxp://www.mydomain.com/some.php3
User-Agent: Mozilla/4.0
Content-Length: 176
Content-Type: multipart/form-data; boundary=xYzZY

--xYzZY
Content-Disposition: form-data; name="mykey"

myValue
--xYzZY
Content-Disposition: form-data; name="cool_sounds"; filename="myfile.wav"

hello world
--xYzZY--

If you need to set the Content-Type for the file section, you can do it like this:

use strict;
use warnings; 
use 5.020;
use Data::Dumper;
use HTTP::Message;
use HTTP::Request::Common;

my $rawdata = "hello world";
my $url = "http://thehost.com";

my $requ = POST $url,
   Referer => 'hxxp://www.mydomain.com/some.php3', 
   Accept_Language => 'en-us',
   Content_Type => 'form-data',
   Accept_Encoding => 'wav',
   User_Agent => 'Mozilla/4.0',
   Host => 'www.mydomain.com',
   Connection => 'Keep-Alive',
   Content => [ 
       mykey => 'myValue',         #some other key/value pair
       cool_sounds => [undef,      #file upload key/value pair
                       'myfile.wav', 
                       'Content-Type' => 'audio/x-wav', 
                       Content => $rawdata
                      ]  #=>If one of the values in the $form_ref is an array reference...

   ];


say $requ->as_string;

--output:--
OST http://thehost.com
Connection: Keep-Alive
Accept-Encoding: wav
Accept-Language: en-us
Host: www.mydomain.com
Referer: hxxp://www.mydomain.com/some.php3
User-Agent: Mozilla/4.0
Content-Length: 203
Content-Type: multipart/form-data; boundary=xYzZY

--xYzZY
Content-Disposition: form-data; name="mykey"

myValue
--xYzZY
Content-Disposition: form-data; name="cool_sounds"; filename="myfile.wav"
Content-Type: audio/x-wav

hello world
--xYzZY--

And, if you need to set the Content-Disposition of the file section to something else:

use strict;
use warnings; 
use 5.020;
use Data::Dumper;
use HTTP::Message;
use HTTP::Request::Common;

my $rawdata = "hello world";
my $url = "http://thehost.com";

my $requ = POST $url,
   Referer => 'hxxp://www.mydomain.com/some.php3', 
   Accept_Language => 'en-us',
   Content_Type => 'form-data',
   Accept_Encoding => 'wav',
   User_Agent => 'Mozilla/4.0',
   Host => 'www.mydomain.com',
   Connection => 'Keep-Alive',
   Content => [ 
       mykey => 'myValue',         #some other key/value pair
       cool_sounds => [undef,      #file upload key/value pair
                       'myfile.wav', 
                      'Content-Type' => 'audio/x-wav', 
                      'Content-Disposition' => 'file',
                       Content => $rawdata
                      ]

   ];


say $requ->as_string;

--output:--
POST http://thehost.com
Connection: Keep-Alive
Accept-Encoding: wav
Accept-Language: en-us
Host: www.mydomain.com
Referer: hxxp://www.mydomain.com/some.php3
User-Agent: Mozilla/4.0
Content-Length: 155
Content-Type: multipart/form-data; boundary=xYzZY

--xYzZY
Content-Disposition: form-data; name="mykey"

myValue
--xYzZY
Content-Disposition: file
Content-Type: audio/x-wav

hello world
--xYzZY--

Note that in this case there's no name attribute for the file section.

By the way, what made you think that not posting your use statements was helpful? Don't do that.

7stud
  • 46,922
  • 14
  • 101
  • 127
  • "which is how all HTTP requests organize their data" — that isn't true, that's just how the two standard request encodings you can trigger from a standard HTML form organise their data. – Quentin Apr 08 '16 at 11:41
  • Thanks, that helps a lot. My issue was simply that the Content section wasn't in the right format. – B-Dawg Apr 11 '16 at 01:14