File Upload: what am I doing wrong?


#1

Hello,

I need to upload a file to a server. The server side cgi expects a parameter userId and the file name. I try the following code, but it’s not even able to see userId on the other end (the script doesn’t go on to see if the file has been posted yet but I am sure that wouldn’t work either. This is my first attempt at using juce for file upload and I think I’m missing something simple:

juce::File myFile(“c:\testfile.txt”);
const juce::URL url = new URL(serverCgiPath);
url = &(url->withParameter(“userId”, 1));
url = &(url->withFileToUpload(“uploadfile”, myFile);
juce::InputStream
input = url->createInputStream(true);

input->read((void*) buffer, 1024);

The buffer has a response from the cgi script that is sent when no userId has been set.

Also why do the different URL methods return a copy of the URL and not modify the URL itself?


#2

I’m going to take a wild guess here and speculate that the reason your code doesn’t work is that http file upload requires that all parameters be placed inside the body (multi-part form post) and that the URL’s withParameter method puts the parameter in the query string instead of the post body, at least that’s what the docs say. Note that the http protocol specifies that parameters are put in the body if the method is POST. Thus, if withParameter’s documentation is correct, Juce’s URL class does not correctly implement the HTTP protocol, at least for a POST with parameters.

I don’t have a solution that only relies on Juce code as I’m not sure if the URL class can put parameters in the http body.


#3

i stumbled upon http/ftp upload/download problems with juce and decided to go aroung and use curl, here is what i did:
http://code.google.com/p/ketonal/source/browse/#svn/trunk
(FileUpload class), i’m still hoping that jules will use curl one day in the place of his current NET code.


#4

I’m don’t know if my problem is at all related. I’m also trying to use POST to post a large encrypted string 1024 chars to a cgi script which returns the same. Basically I’m just doing something like this:

URL someURL(“http://blah.blah.blah/myscript.cgi”);

String request(“blahblahblah…”);

URL requestURL= someURL.withParameter(“paramname”, request);

String response = requestURL.readEntireTextStream(true); // where true is POST method which script expects and gets from cin up to “CONTENT_LENGTH”.

works fine in debug, however in release for some reason I get a 12007 error (which apparently is unresolved host name or something).

IOW:

HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0)

…is failing in juce_openInternetFile() and I put a getlasterror in there to find out why… but if I past the same url in IE, it’s fine… am I miss-reading the error?

I’m totally stumped, especially since it’s only broken in release, which makes it hard to debug. Any ideas most appreciated! I’d rather just fix the bug than start from scratch. Perhaps I’ll take a look at your class and see if it will work for me without too much modification. Thx for posting :slight_smile:


#5

Utterly bizarre. Unless there’s been some kind of memory corruption of the data that’s getting passed into the HttpRequest call, I can’t think why on earth it’d behave differently in release mode. Maybe add some code to dump all its input parameters just before the call is made?


#6

Yeah I traced out every param in the call, and everything looks correct right up to HttpSendRequest call. I’m thinking there probably something weird about my “environment” rather than the code itself… as I tested release on two other machines and it worked. Still would like to figure it out in case my “environment” isn’t uncommon, possibly IE version or something, who knows. It’s been awhile since I’ve looked at windows networking stuff, but I have used curl in the past and was happy with that, so it’s worth consideration.


#7

Well, that does sound like a problem with your setup then, but it’s certainly a strange one!


#8

Well, strangely enough, my firewall had secretly created an allow rule for the executable in the debug directory, then quietly decided to deny all other requests from the same executable. Hindsight is 20/20 but I had the blinders on, following the cookie crumb trail MSDN left down the road to perdition.

So with my face fully lost, I feel free to ask another dumb question: While everything seems hunky dory on Windows, the same code I posted above, compiled on the Mac, gives me errors…

If I look at the server logs, here’s what I get:

#Fields: date time c-ip cs-username s-sitename s-computername s-ip s-port cs-method cs-uri-stem cs-uri-query sc-status sc-win32-status sc-bytes cs-bytes time-taken cs-version

// From a windows XP machine:

2008-12-17 21:43:56 1.2.3.4 - W3SVC1 MYSERVER 10.10.1.100 1234 POST /somedir/myscript.cgi - 200 0 1625 1237 10969 HTTP/1.1 my.domain.name:1234 juce - -

// where 200 is the server status (OK) and everything works as expected.

// From a Leopard machine:

2008-12-17 22:01:50 1.2.3.4 - W3SVC1 MYSERVER 10.10.1.100 1234 POST /somedir/myscript.cgi - 400 87 4148 1024 0 HTTP/1.0 reg.dynalias.net:8000 JUCE/1.46 - -

where 400 is a bad request returned from the server and 87 seems to indicate invalid parameter, for example if there was some invalid character I imagine.

I guess my first dumb question is… is there a difference between the way http 1.0 and 1.1 send a POST, or perhaps different limits on the length of the query string. Certainly the windows one has got it right in terms of bytes… but I don’t know where the mac request is getting it’s numbers.

Note that if I trace out the request (myurl.toString(true)) there seems to be a newline between the “?” and the parameter=value string. I don’t see anywhere in my code or the url code that would put that there, but I suppose a POST to “…/myscript.cgi?” with nothing (newline) after it might generate 87 “invalid parameter” error?

Anyway, all paths lead to said cgi, so I’ll probably just write some asp for the 400 page that spits back the request/query/post in plain text so I can see exactly what juce is sending me, but I thought I’d ask first.

Thanks :slight_smile:


#9

The tip has all-new mac networking code, so if you’ve not already got that, it might be worth grabbing it to try…


#10

I don’t know the latest network class, but you should investigate the request headers first. When I used URL class, the headers were different from PC app and Mac one made by JUCE.

Microsoft Network Monitor is very useful to monitor your requests. I recommend it.


#11

Thanks, the trunk seems to work for the http request, however it’s broken all sorts of stuff with the VST only the Mac side.

Among other things, the main problem is that now the main plugin window behaves differently as if it’s in the wrong place in the hierarchy. For example, in Reaper it seems to be the topmost window so that when you resize the host plugin container window, the plugin remains on top and not resized, and it’s not receiving some other messages as well such as mouse move. I see that in the new demoplugin you’ve added a corner resizer class… is this related? Any idea why this behavior is happening?

Also, wondering if it might make sense to use a single juce header, and have some config define which “proxies” it to regular or amalgamated version. This way I could compile all my projects, the example projects, etc. via a single define without modifying anything. Unfortunately the amalgamated stuff doesn’t play nice with my tools or coding habits and I decided it was more trouble than it was worth, and removed it.

ITMT, I’ll try compiling the demoplugin project and see if it exhibits the same behavior… maybe it’s Reapers problem (?) although other plugins do not exhibit this behavior.

thx :slight_smile:


#12

Well, you’ve probably jumped from the old carbon VST wrapper to the cocoa one - and the entire structure is different. Because it’s not possible for a cocoa plugin to sit inside an old carbon window, I’ve had to use Apple’s suggested workaround, and float a cocoa window in front of the host’s window.

I’d not tried it yet in reaper, but will have a go.