views:

116

answers:

2

I'm sending an image from an Android phone to an AppEngine. The AppEngine is throwing content exceptions. My process of elimination has failed so I suspect I've done something larger wrong. Do I have a content type problem or a larger problem?

The AppEngine log shows the following errors depending on the content type [content type --> resulting error]:

multipart/mixed stream --> org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found the request was rejected because no multipart boundary was found

image/jpg --> org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is image/jpg

binary/octet-stream --> org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is binary/octet-stream

ANDROID CODE:

static void apachePost(File file) {
    File file = new File(directory, fileName);

    try {
        String url = "http://chexserve.appspot.com/chexappengine";

        HttpClient httpclient = new DefaultHttpClient();

        HttpPost httpPost = new HttpPost(url);

        FileEntity entity = new FileEntity(file, "multipart/mixed stream");

        httpPost.setEntity(entity);

        Log.v(Constants.CHEX,
                "executing request " + httpPost.getRequestLine());

        HttpResponse response = httpclient.execute(httpPost);

        Log.v(Constants.CHEX, "received http response " + response);

        HttpEntity resEntity = response.getEntity();

        httpclient.getConnectionManager().shutdown();

    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

APPENGINE CODE:

 public class ChexAppEngineServlet extends HttpServlet {

private static final Logger LOG = Logger
        .getLogger(ChexAppEngineServlet.class.getName());

/** Processes the incoming request */
@Override
protected void doPost(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {

    LOG.info("LOG: received post");

    System.out.println("PRINTLN: received post " + request);

    try {

        ServletFileUpload upload = new ServletFileUpload();
        FileItemIterator iter;

        iter = upload.getItemIterator(request);

        if (iter.hasNext()) {

            FileItemStream imageItem = iter.next();

            InputStream imgStream = imageItem.openStream();

            System.out.println("PRINTLN: created imgStream " + imgStream);

            // construct our entity objects
            Blob imageBlob = new Blob(IOUtils.toByteArray(imgStream));
            MyImage myImage = new MyImage(imageItem.getName(), imageBlob);

            System.out.println("PRINTLN: created my image " + myImage);

        } else {
            System.out.println("PRINTLN: no file in post");
            LOG.info("LOG: no file in post");
        }

    } catch (FileUploadException e) {
        LOG.info("failed to parse post request: " + e);
        e.printStackTrace();
    }
}
A: 

The content type is "multipart/mixed", not "multipart/mixed stream". Also valid should be "multipart/form-data". If you're just uploading the image, though, you can upload it as image/jpeg, and read the raw data from the request on the server, by calling (If I recall correctly), request.getInputStream() - no need to use the Apache forms library at all.

Nick Johnson
Nick and others: I have changed the Android's content line to FileEntity entity = new FileEntity(file, "multipart/mixed");
That still won't help unless you package the file you're sending up in a mime multipart message. Why not just switch to reading the raw data from the request as I suggested?
Nick Johnson
I did not switch to reading the raw data because I don't know which classes and methods to use to transmit the image as raw bytes. If I use a tcp socket and build the header and payload myself, I'll have a maintenance nightmare. I'm trying to work with some higher level API, but have no commitment to Apache forms.
You don't need special classes and methods - do it exactly as you're doing on the Android side, but with a content-type of 'image/jpeg', and then use getInputStream on the server side to read the bytes of the uploaded image.
Nick Johnson
Thanks - I have the upload working I think. I need to test some more to validate.
A: 

Nick,

AppEngine is still rejecting the request with "the request was rejected because no multipart boundary was found" error after I changed the Android's entity line to:

FileEntity entity = new FileEntity(file, "multipart/mixed");

According to the documentation [http://hc.apache.org/httpclient-3.x/preference-api.html],"The multipart boundary string to use in conjunction with the MultipartRequestEntity. When not set a random value will be generated for each request."

Further, there are no setter methods for the boundary.

How can I set the boundary?

Thanks

Jeff

Please don't leave comments/updates as answers.
Nick Johnson