Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: fallback image on processing error #35

Closed
xtagon opened this issue Mar 20, 2015 · 7 comments
Closed

Feature request: fallback image on processing error #35

xtagon opened this issue Mar 20, 2015 · 7 comments
Labels

Comments

@xtagon
Copy link
Contributor

xtagon commented Mar 20, 2015

It would be extremely useful to be able to specify a fallback to be returned to the browser when an image fails to be processed as a thumbnail. Errors happen. We're logging all failures anyway, but we don't want the user to see the browser's missing image icon. It would be better for them to see either a noop of the original image, or an alternate image URL we specify.

Something like this: ?url=URL&op=resize&w=50&fallback=noop or ?url=URL&op=resize&w=50&fallback=IMAGE_NOT_FOUND_URL

Thoughts?

@agschwender
Copy link
Owner

Couldn't this be accomplished in nginx or apache by specifying a 500 or 404 file?

@agschwender
Copy link
Owner

@xtagon
Copy link
Contributor Author

xtagon commented Mar 20, 2015

Thanks for the suggestion. We're not running behind nginx or apache (Heroku's default is to just run the Python server) but it would probably be a good idea to find a way to do that anyway.

I took a look at the nginx docs, and I can see how this would work if I wanted the same error page redirection for every request, but we have multiple client apps using our Pilbox server for different purposes and it would be handy to be able to specify different fallback functionality for each request. I'll do some experimenting and see if I can setup nginx to URL-rewrite with a check for a fallback=noop in the request params, and then somehow rewrite op=xxx to op=noop for the redirect.

@agschwender
Copy link
Owner

I thought this was a good example of an nginx configuration which did a ton of falling back:

https://github.com/fredpalmer/dimwit/blob/develop/nginx.conf

@xtagon
Copy link
Contributor Author

xtagon commented Mar 20, 2015

Thanks, I'll look into that!

@agschwender
Copy link
Owner

Here's some additional options discussed in #34, repeating here for completeness.

Solve in the browser

  • consider using a :before pseudo element and render images using background-image style property
  • consider loading the image with javascript

Use a custom application

#!/usr/bin/env python

import tornado.gen

from pilbox.app import PilboxApplication, ImageHandler, \
    start_server, parse_command_line
from pilbox.errors import ImageFormatError


class CustomApplication(PilboxApplication):
    def get_handlers(self):
        return [(r"/", CustomImageHandler)]


class CustomImageHandler(ImageHandler):
    def prepare(self):
        self.has_error = False

    @tornado.gen.coroutine
    def get(self):
        self.validate_request()
        resp = yield self.fetch_image()

        try: 
            self.render_image(resp)
        except ImageFormatError:
            self.has_error = True
            self.render_image(resp)

    def get_argument(self, name, default=None):
        if self.has_error and name == "op":
            return "noop"
        return super(CustomImageHandler, self).get_argument(name, default)


if __name__ == "__main__":
    parse_command_line()
    start_server(CustomApplication())

Gonna close this because I feel like there are several methods for solving this outside of and within Pilbox.

@xtagon
Copy link
Contributor Author

xtagon commented Mar 20, 2015

All the functionality I want is working now. Here was the final solution:

If fallback is set to direct, log the error and redirect to the original URL.
If fallback is set to noop, log the error and render the original image.
If fallback is set to anything else, treat the value as an arbitrary URL to redirect to (e.g. a missing image placeholder).

#!/usr/bin/env python

import sys

import tornado.gen
from pilbox.app import PilboxApplication, ImageHandler, \
    start_server, parse_command_line
from pilbox.errors import ImageFormatError

class CustomApplication(PilboxApplication):
    def get_handlers(self):
        return [(r"/", CustomImageHandler)]

class CustomImageHandler(ImageHandler):
    def prepare(self):
        self.has_error = False

    @tornado.gen.coroutine
    def get(self):
        self.validate_request()
        resp = yield self.fetch_image()

        try:
            self.render_image(resp)
        except ImageFormatError:
            fallback = self.get_argument("fallback")
            if fallback != None:
                self.log_exception(*sys.exc_info())
                if fallback == "direct":
                    self.redirect(self.get_argument("url"))
                elif fallback == "noop":
                    self.has_error = True
                    self.render_image(resp)
                else:
                    self.redirect(self.get_argument("fallback"))
            else:
                raise

    def get_argument(self, name, default=None):
        if name == "op" and self.has_error:
            return "noop"
        return super(CustomImageHandler, self).get_argument(name, default)

if __name__ == "__main__":
    parse_command_line()
    start_server(CustomApplication())

Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants