'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.