RequestBuilder + POST + multipart/form-data

2,569 views
Skip to first unread message

Alex Rice

unread,
Oct 22, 2008, 1:37:07 PM10/22/08
to Google Web Toolkit
My cms server (Alfresco) requires form POSTs to have the tag
enctype="multipart/form-data" (even if no files or uploads are in the
form).

Since GWT doesn't provide any methods for constructing the body/
payload of post requests, I am trying to roll my own but so far my
server isn't recognizing the data. This is not an SOP issue; I am
hitting the server successfully. Can anyone spot any errors in the
following? I have GWT.Logged the requestData and it looks correct
AFAIK based on the RFC and web articles I've read about this.

In a subclass of RequestBuilder I have:

// post body delimiters and headers:
public static final String BOUNDARY = "c0ff33";
public static final String CONTENT_DISP_LINE = "Content-disposition:
form-data; filename=\"\" name=\"";
public static final String TEXT_PLAIN = "Content-type: text/plain;
charset=utf-8";

// http headers:
public static final String CONTENT_TYPE_HEADER = "Content-type";
public static final String CONTENT_LENGTH_HEADER = "Content-
length";
public static final String CONTENT_TYPE = "multipart/form-data;
boundary="+BOUNDARY;

// builds the body of the request, and sets appropriate
headers
public void setMultipartFormData(final String key, final String
value)
{
StringBuffer body = new StringBuffer();
body.append("--" + BOUNDARY+"\n");
body.append(CONTENT_DISP_LINE+ key+"\"\n");
body.append(TEXT_PLAIN+"\n\n");
body.append(value);
body.append("\n--" + BOUNDARY+"--\n");
setHeader(CONTENT_TYPE_HEADER, CONTENT_TYPE);
setHeader(CONTENT_LENGTH_HEADER, String.valueOf(body.length()));
setRequestData(body.toString());
}

// in another class:
MyRequestBuilder rb = new MyRequestBuilder(RequestBuilder.POST, url);
rb.setMultipartFormData("json", jsonStr);
rb.setCallback(new RequestCallback() ...);
rb.send();


An alternate idea would be to have a hidden FormPanel that I setup and
let the browser do the Posting for me. However, a drawback there
would be that the FormHandler is less useful than the
RequestCallback.

Any suggestions appreciated. Thanks

Alex Rice

unread,
Oct 22, 2008, 6:22:32 PM10/22/08
to Google Web Toolkit
Can anyone confirm whether RequestBuilder actually works for POSTs
setRequestData() and with multipart/form-data content type?

I have many hours trying to get this to work, and can't get either an
Apache/PHP script ,or an Alfresco web script server to parse the
content being posted. I also tried sendRequest("hello", new
RequestCallback().. ) instead of using the setRequestData() method.

Mac OS X
GWT 1.5.3

Lothar Kimmeringer

unread,
Oct 23, 2008, 2:04:55 AM10/23/08
to Google-We...@googlegroups.com
Alex Rice schrieb:

> Can anyone confirm whether RequestBuilder actually works for POSTs
> setRequestData() and with multipart/form-data content type?

I can't confirm it for RequestBuilder, but can do it for
FormPanel, because there are constants that can be used to
set the encoding to mulitpart/form-data.

So you should give it a try, use the widget instead or
do the request on the server-side inside a RemoteServiceServlet.
There are a couple of examples out there using FormPanel
especially when the topic is "upload a file using GWT" where
this panel is in general used.


Regards, Lothar

Thomas Broyer

unread,
Oct 23, 2008, 6:40:08 AM10/23/08
to Google Web Toolkit

On 22 oct, 19:37, Alex Rice <mindl...@gmail.com> wrote:
> My cms server (Alfresco) requires form POSTs to have the tag
> enctype="multipart/form-data" (even if no files or uploads are in the
> form).

Extensively working with Alfresco, I can assure you Web Scripts can
actually accept application/x-www-form-urlencoded data. You'll just
get them into args and argsM instead of formdata. Note that this is a
side-effect of running the Web Script within a servlet context (and
probably constrained to running within Tomcat) as it depends on the
implementation of ServletRequest.getParameterMap(), which (at least in
Tomcat) decodes application/x-www-urlencoded request bodies.
I was with Michael Uzquiano (Director of Alfresco WCM Products) and
David Caruana (Alfresco Chief Architect) last week and we talked about
it. I asked them if they could at least document it, or even better
guarantee this behavior even in non-servlet environments (such as the
unit-testing standalone Web Script runtime).

But this is all going to change with Alfresco 3 though...
(if you can read French, I wrote some notes about the new Alfresco
Surf platform on my company's blog, and some of this is available on
the Web Script side: http://blog.atolcd.com/?p=26 )

> Since GWT doesn't provide any methods for constructing the body/
> payload of post requests, I am trying to roll my own but so far my
> server isn't recognizing the data.

I wrote one too for GWT-in-the-AIR (it outputs to a ByteArray, which
is specific to Adobe AIR, but you could easily change it to append to
a StringBuilder):
http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/ltgt/gwt/air/user/client/ui/impl/MultipartFormDataGenerator.java

> This is not an SOP issue; I am
> hitting the server successfully.  Can anyone spot any errors in the
> following? I have GWT.Logged the requestData and it looks correct
> AFAIK based on the RFC and web articles I've read about this.
>
> In a subclass of RequestBuilder I have:
>
>     // post body delimiters and headers:
>         public static final String BOUNDARY = "c0ff33";
>         public static final String CONTENT_DISP_LINE = "Content-disposition:
> form-data; filename=\"\" name=\"";

If you don't send files, don't output filename=""

>         public static final String TEXT_PLAIN  = "Content-type: text/plain;
> charset=utf-8";
>
>         // http headers:
>         public static final String CONTENT_TYPE_HEADER = "Content-type";
>         public static final String CONTENT_LENGTH_HEADER = "Content-
> length";
>         public static final String CONTENT_TYPE  = "multipart/form-data;
> boundary="+BOUNDARY;
>
>        // builds the body of the request, and sets appropriate
> headers
>         public void setMultipartFormData(final String key, final String
> value)
>         {
>                 StringBuffer body = new StringBuffer();
>                 body.append("--" + BOUNDARY+"\n");

Line separator should be CRLF (\r\n)

>                 body.append(CONTENT_DISP_LINE+ key+"\"\n");
>                 body.append(TEXT_PLAIN+"\n\n");
>                 body.append(value);
>                 body.append("\n--" + BOUNDARY+"--\n");
>                 setHeader(CONTENT_TYPE_HEADER, CONTENT_TYPE);
>                 setHeader(CONTENT_LENGTH_HEADER, String.valueOf(body.length()));

Content-Length is expressed in bytes, while body.length() is a
character count; you shouldn't set the Content-Length (the browser
will do it for you eventually)

>                 setRequestData(body.toString());
>         }
>
> // in another class:
> MyRequestBuilder rb = new MyRequestBuilder(RequestBuilder.POST, url);
> rb.setMultipartFormData("json", jsonStr);
> rb.setCallback(new RequestCallback() ...);
> rb.send();
>
> An alternate idea would be to have a hidden FormPanel that I setup and
> let the browser do the Posting  for me. However, a drawback there
> would be that the FormHandler is less useful than the
> RequestCallback.
>
> Any suggestions appreciated. Thanks

The best advice I could give you is to use application/x-www-form-
urlencoded with your Alfresco Web Script ;-)

Alex Rice

unread,
Oct 23, 2008, 2:12:48 PM10/23/08
to Google Web Toolkit, t.br...@gmail.com
(sorry if this double posts- I think I messed up my last reply)

On Oct 23, 4:40 am, Thomas Broyer <t.bro...@gmail.com> wrote:
> The best advice I could give you is to use application/x-www-form-
> urlencoded with your Alfresco Web Script ;-)

Thomas, thanks for your insights into Alfresco, and pointing out the
problems with my code! I am trying x-www-form-urlencoded data now
with Alfresco 2.1.6E - Tomcat, but can't get it to work- no data
appears in args and argsM. Is this how you are doing it? This seems
like it would be easier than messing with multipart , for sure.

String jsonUrlEncodedStr = "json="+
URL.encodeComponent(json.toString());
RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, url);
rb.setRequestData(jsonUrlEncodedStr);
rb.setHeader("Content-Type", "application/x-www-form-urlencoded
data");
rb.setCallback(new RequestCallback()...);
rb.send();

BTW when I append guest=true to my url, then that appears in args and
argM, which I actually need do for both GET and POST submissions to my
webscripts.

Thanks again

Alex Rice

unread,
Oct 23, 2008, 2:16:21 PM10/23/08
to Google Web Toolkit, t.br...@gmail.com


On Oct 23, 12:12 pm, Alex Rice <mindl...@gmail.com> wrote:

> rb.setHeader("Content-Type", "application/x-www-form-urlencoded
> data");

UGH! typo in the content type ^^^^^ . Fixed and now it works :-)
Thanks again

Alex Rice

unread,
Oct 23, 2008, 2:04:41 PM10/23/08
to Google Web Toolkit, t.br...@gmail.com
On Oct 23, 4:40 am, Thomas Broyer <t.br...@gmail.com> wrote:

> The best advice I could give you is to use application/x-www-form-
> urlencoded with your Alfresco Web Script ;-)

Thomas, thanks for pointing out my code errors, and your valuable
insights about Alfresco! I would like to use x-www-form-urlencoded
data, and not muck about with multipart encoding, but can't seem to
get it to work. Running Alfresco 2.1.6 w/ Tomcat. I think
RequestBuilder.GET is working fine, POST is the problem.

Is this how you are doing it? In GWT:

RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, url);
String jsonUrlEncodedStr = "json="+
URL.encodeComponent(json.toString());
rb.setRequestData(jsonUrlEncodedStr);
rb.setHeader("Content-Type", "application/x-www-form-urlencoded
data");
rb.setCallback(new RequestCallback()... );
rb.send();

In Alfresco web script:

var sResult = "";
for (arg in args)
sResult += arg + "=" + args[arg] + "<br/>";

for (arg in argsM)
{
for each (val in argsM[arg])
sResult += arg + "=" + val + "<br/>";
}
model.response = sResult;

What I get back from Alfresco is empty, unless I append guest=true to
my URL, which is actually needed for both GET and POST because I am
running web scripts with guest authentication. In that case I do see
guest=true in args and argsM.

Reply all
Reply to author
Forward
0 new messages