views:

42

answers:

3

Hi,

I allow my users to upload avatar images (google app engine, java). I don't know what image type it is when they upload. I'm just storing whatever they give me in their submission form. I'm following the example here:

http://code.google.com/appengine/docs/python/images/usingimages.html

Is there a way to check what image type it is before storing it? For example, if they submit a text file, I don't want to accept it.

Also, how would I change the content type when serving the image back? I need to know what image type it is, in order to set the content type correctly?:

 resp.setHeader("Content-Type", "image/jpg");   

I am using java,

Thanks

A: 

Why dont you just get the extension off the filename, and use that to determine what type of image it is, and from that work out the mime type?

The other way to do it would to be to open your images using the google app engine image processing API using different file types and check which one does not result in an error. This would be more CPU intensive but more reliable.

corydoras
+1  A: 

If it's affordable to check the content type based on the file extension, then use ServletContext#getMimeType().

String mimeType = getServletContext().getMimeType(filename);

if (mimeType.startsWith("image")) {
    // It's an image.
}

The default mime types are definied in the web.xml of the servletcontainer in question. In for example Tomcat, it's located in /conf/web.xml. You can extend/override it in the /WEB-INF/web.xml of your webapp as follows:

<mime-mapping>
    <extension>svg</extension>
    <mime-type>image/svg-xml</mime-type>
</mime-mapping>

But this doesn't prevent you from users which are fooling you by changing the file extension. If you'd like to cover this as well, then you can also determine the mime type based on the actual file content. You can do that by sniffing the file headers. Consider using a 3rd party library to do all the work. I've found JMimeMagic useful for this. You can use it as follows:

String mimeType = Magic.getMagicMatch(uploadedFile, false).getMimeType();

To be able to serve the image back, you can just set the response content type with the outcome of ServletContext#getMimeType() (don't forget during the upload to confirm that this equals to what JMimeMagic returns, for the case that).

response.setContentType(getServletContext().getMimeType(file.getName()));
BalusC
+2  A: 

Typically if you're using a browser-based file upload, the form data will include a file name and a content-type inferred from the file extension. However, this is no guarantee that the user hasn't uploaded a file with a misleading extension. To verify the content type, you can use the Images service:

Image img = ImagesServiceFactory.makeImage(uploadedBytes);
String contentType = "image/" + img.getFormat().toString().toLowerCase();

Supported types are BMP, GIF, ICO, JPEG, PNG and TIFF. Anything else should fail.

This may go without saying, but you should check the content type only on upload and then store it with the image; don't call the images service to find out the type on every download request.

Drew Sears
+1 for a GAE API I wasn't aware about. This is the way to go (instead of JMimeMagic as I suggested).
BalusC
Cool yeah I am using the image api whenever the user submits a photo to rescale it for thumbnails so during this step I get the image type out and store it as mentioned above.