Reputation: 106
I am using titan-files in my Google App Engine application to provide a filesystem-like layer to Data Store and Blob Store storage. I have a Google Apps Script that sends POST requests to my Google App Engine application to store the data in the blob store. It works fine when sending JSON data (as a string), but it doesn't work when sending binary data, like images.
I ended up trying to send base64 encoded data as a string and store it in the blob store. I thought that I could retrieve the data from the blob store and base64 decode it to get the original image. However, it doesn't seem to work.
Here's the code I am using to send the data from the Google Apps Script:
function pushFileToFilePath(file, destinationFilePath) {
var payload =
{
"content" : Utilities.base64Encode(file.getAs("image/jpeg").getBytes())
};
var options =
{
"method" : "post",
"payload" : payload
};
var response = UrlFetchApp.fetch("https://myappname.appspot.com/_titan/file?path=" + destinationFilePath, options);
if (response.getResponseCode() == 201)
{
return true;
}
return false;
}
The data is available in the blob store after the request is sent, and its size is in line with what I would expect from the results of base64-encoding the file. However, if I download the file from the blob store using the Google App Engine dashboard and base64-decode it using
openssl -d -in base_64_encoded_file.txt -out image.jpg
I get a zero-byte image.jpg file.
I also tried other ways to setup the payload object. For instance using:
var payload =
{
"content" : file.getAs("image/jpeg").getBytes()
};
gives a file of 18 bytes on the blob store, containing the string "[Ljava.lang.Object". Using:
var payload =
{
"content" : file.getAs("image/jpeg")
};
I get the following exception in my Google App Engine logs:
Bad request:
Traceback (most recent call last):
File "/base/data/home/apps/s~myappname/live-1.364814133265166345/titan/files/handlers.py", line 103, in post
content, blob=blob, mime_type=mime_type, meta=meta, **method_kwargs)
File "/base/data/home/apps/s~myappname/live-1.364814133265166345/titan/files/files.py", line 408, in Write
content, blob = self._MaybeWriteToBlobstore(content, blob)
File "/base/data/home/apps/s~myappname/live-1.364814133265166345/titan/files/files.py", line 341, in _MaybeWriteToBlobstore
blob = utils.WriteToBlobstore(content, old_blobinfo=old_blobinfo)
File "/base/data/home/apps/s~myappname/live-1.364814133265166345/titan/common/utils.py", line 277, in WriteToBlobstore
content_file = cStringIO.StringIO(content)
TypeError: expected read buffer, instance found
I tried using BytesIO to stream the content, but I got other exceptions.
Do you have any idea of how I could POST images (or more generally binary data) to titan-files?
Thank you!
UPDATE
I fixed my issue by changing the way the "content" data is retrieved from this:
content = self.request.str_POST.get('content')
to this:
content = self.request.get('content')
and by sending the data using the following code in my Google Apps Script:
var payload =
{
"content" : file.getAs("image/jpeg")
};
that is, just setting "content" to be a Blob instance.
I don't know why I didn't try this in the first place :) Anyway, the change in titan-file is a hack and not a permanent solution, so I'll try to come up with a solid patch that handles both binary and non-binary data and submit it to the project.
Thank you!
Upvotes: 1
Views: 1393
Reputation: 106
I created an issue in titan-files's issues tracker here: http://code.google.com/p/titan-files/issues/detail?id=1 . The patch attached to it fixes the issue, but it is not a clean and robust fix. Titan Files' maintainers will probably update the issue with a reference to a proper fix soon.
Upvotes: 1