'm trying to upload a file with the google app engine blobstore. 

It's supposed to work like this: you call the BlobstoreService to get an 
upload url, supplying a callback URL. The client is redirected to the 
upload URL, sends the data, then when they've finished they will be 
redirected to the callback URL with a couple of parameters which represent 
the blobstore key.

The dev server behaves differently to the production server as we shall see.

Against production, my code gets as far as completing the upload, then 
instead of getting a redirect back to my callback URL, I get a 400 error 
response (implying something wrong with my request). How do I debug this in 
production? I don't know how to switch on logging for the blobstore.

So I tried to run it locally against the dev server. This time if I don't 
set the 'content-length' property, I get a 411 (content length not set). 
But if I try and set that property, I get 'IllegalStateException: Already 
connected'. Neither of these exceptions happen against production. 

So I don't know where to go next. I need to either get it working against 
dev, in the hope that I can debug the blobstore locally, or work out why 
it's not working on the blobstore in production.

    public void upload(String uri, File file) throws IOException    {
    HttpURLConnection conn=null;
    HttpURLConnection conn2=null;
    FileInputStream fileInputStream = null;
    DataOutputStream dos=null;
    try {
        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";
        int bytesRead, bytesAvailable, bufferSize;
        byte[] buffer;
        int maxBufferSize = 1 * 1024 * 1024; 
        // open a URL connection to the Servlet
        fileInputStream = new FileInputStream(file);
        URL url = new URL(uri);

        // Open a HTTP  connection to  the URL
        conn = (HttpURLConnection) url.openConnection();
        conn.setDoInput(true); // Allow Inputs
        conn.setDoOutput(true); // Allow Outputs
        conn.setUseCaches(false); // Don't use a Cached Copy
        conn.setInstanceFollowRedirects(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.setRequestProperty("ENCTYPE", "multipart/form-data");
        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" 
+ boundary);//          conn.setChunkedStreamingMode(1024);
        conn.setRequestProperty("content-length", 
String.valueOf(file.length()));   //caused IllegalStateException "Already 
connected" locally, but not remotely

        log("Orignal URL: " + conn.getURL());
        //conn.connect();   //TODO duplicates url.openConnection() above?
        conn.getInputStream();  //so we can follow the redirect
        String redirectedUrl = conn.getHeaderField("Location");
        log("Redirected URL: " + redirectedUrl);
        //this is horrible and messy but let's get it working then clean it up 
later

        conn.disconnect();
        url = new URL(redirectedUrl);

        // Open a new HTTP  connection to  the URL
        conn2 = (HttpURLConnection) url.openConnection();
        conn2.setDoInput(true); // Allow Inputs
        conn2.setDoOutput(true); // Allow Outputs
        conn2.setUseCaches(false); // Don't use a Cached Copy
        conn2.setInstanceFollowRedirects(false);
        conn2.setRequestMethod("POST");
        conn2.setRequestProperty("Connection", "Keep-Alive");
        conn2.setRequestProperty("ENCTYPE", "multipart/form-data");
        conn2.setRequestProperty("Content-Type", 
"multipart/form-data;boundary=" + boundary);
        conn2.setChunkedStreamingMode(maxBufferSize);
        conn2.setRequestProperty("Content-Length", 
String.valueOf(file.length()));
        conn2.connect();
        dos = new DataOutputStream(conn2.getOutputStream());

        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; 
name=\"myFile\";filename=\""+file.getName()+"\"" + lineEnd);
        dos.writeBytes(lineEnd);

        // create a buffer of  maximum size
        bytesAvailable = fileInputStream.available();

        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        buffer = new byte[bufferSize];

        // read file and write it into form...
        bytesRead = fileInputStream.read(buffer, 0, bufferSize); 

        while (bytesRead > 0) {
            dos.write(buffer, 0, bufferSize);
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);  
        }

        // send multipart form data necesssary after file data...
        dos.writeBytes(lineEnd);
        dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

        // Responses from the server (code and message)
        int serverResponseCode = conn2.getResponseCode();
        String serverResponseMessage = conn2.getResponseMessage();
        //we are expecting another redirect here
        log("aaaargh! 400 instead of 302! "+serverResponseCode+" to 
"+conn2.getHeaderField("Location"));
    }catch (IOException e)  {
        log(e.getMessage());
        throw e;
    }catch(Exception e) {
        log(e.getMessage());
        throw new IOException(e);
    }   finally {
        //close the streams //
        if (dos!=null)  {   
            try {
                dos.flush();
                dos.close();
            }catch(IOException ioe){}
        }
        if (fileInputStream!=null)
            try {
                fileInputStream.close();
            }catch(IOException ioe){}

        if (conn!=null )
            try {
                conn.disconnect();
            }catch(Exception ioe){}

        if (conn2!=null)
            try {
                conn2.disconnect();
            }catch(Exception ioe){}

    }}

NB the serverResponseMessage string above comes back from the production 
blobstore as "Bad Request"

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-appengine.
For more options, visit https://groups.google.com/d/optout.

Reply via email to