Imageprocessor: Rewriting urls before hitting ImageProcessor Module

Created on 25 Oct 2016  路  14Comments  路  Source: JimBobSquarePants/ImageProcessor

I just upgraded Umbraco from 7.5.3 to 7.5.4.

  • ImageProcessor 2.4.4 -> 2.4.5
  • ImageProcessor.Web 4.6.4 -> 4.6.6

I am using a custom IHttpModule in front of ImageProcessorModule to do security checks and rewrite urls. Using the HttpContext.RewritePath method the module is rewriting querystring on images to take advantage of imageprocessor.

This has been working perfectly until last update.

I did a test using the default IIS UrlRewriteModule:

    <rewrite>
      <rules>
        <rule name="imageProcessor test">
          <match url="^test1.png$" />
          <action type="Rewrite" url="/remote.axd/<#mybucket-name#>.s3.amazonaws.com/media/1001/test1.png?width=700" appendQueryString="false" />
        </rule>
       </rules>
    </rewrite>

This works on Umbraco 7.5.3 but not on Umbraco 7.5.4

Is ImageProcessor reading from Request.RawUrl instead of Request.Url ?

framework

Most helpful comment

Hi @JimBobSquarePants

I added a new file ImageProcessingModuleFix.cs in App_Code:

using ImageProcessor.Web.HttpModules;
using System.Web;

public class ImageProcessingModuleFix : ImageProcessingModule
{
    protected override string GetRequestUrl(HttpRequest request)
    {
        return request.Url.PathAndQuery;
    }
}

And changed current ImageProcessorModule to this new file in web.config:
<add name="ImageProcessorModule" type="ImageProcessingModuleFix, App_Code" />

Now all my URL Rewrite rules are working again. Awesome.

Thank you.

All 14 comments

We parse the raw unvalidated url.

https://github.com/JimBobSquarePants/ImageProcessor/blob/9f90597468132373609fb6f7b31e6a5c65e446d7/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs#L446

I had to make recent changes to the url parsing mechanism as urls encoded by Facebook and other major services were not being parsed correctly by Request.Url.

If you are pulling your remote images from one location you would be much better off using the CloudImageService with a media/ prefix. That way you are not rewriting the url on every image request.

<service prefix="media/" name="CloudImageService" type="ImageProcessor.Web.Services.CloudImageService, ImageProcessor.Web">
    <settings>
        <setting key="MaxBytes" value="8194304"/>
        <setting key="Timeout" value="30000"/>
        <setting key="Host" value="http://<#mybucket-name#>.s3.amazonaws.com/media/"/>
    </settings>
</service>

Is there a way to modify unvalidated url in a HttpModule or a way to tell ImageProcessingModule what url to use?

I am doing a lot of other security checks and rewrite so I cannot use CloudImageService.

Apologies for the slow reply.

There's an event called ImageProcessingModule.ValidatingRequest which is designed to allow you to validate the request and augment the querystring? Would that be enough?

http://imageprocessor.org/imageprocessor-web/imageprocessingmodule/#events

Otherwise I could unseal the HttpModule class (That was a mistake) so you can inherit it and overwrite anything you need to.

I found the same kind of issues when trying to "hide" the imageprocessor url's behind some more generic urls.

For example I would sometimes make urls that rewrite

/product/xxx_large.jpg => /images/products/xxx.jpg?width=500
/product/xxx_small.jpg => /images/products/xxx.jpg?width=200

And that sort of thing.

Would be nice if this was possible without overriding the imageprocessor classes. Maybe with a config setting, deciding wether to use the unvalidated url or the rewritten one?

I realize that more config settings lead to more complex code in the end, but just throwing in some alternate usecases for urlrewriting. :)

@mortenbock Wouldn't you use IIS rewriting for that?

I'm loath to add any more complexity to the current implementation to be honest. I think if you want a result, you should ask for it via the correct command.

@JimBobSquarePants I did use IIS rewriting. But if that is supposed to work, then this issue might have been a combination of my rewriting, and using the azure blob storage/caching in a specific way.

I will see if I can reproduce, and open a separate issue if that is the case :)

@mortenbock Thanks..

Odd... Being an IIS module, that should intercept the request way before my httpmodule does. I'm wondering if unsealing the class would help here and making this method protected virtual would help?

By my reckoning that would make it possible to use your own module with your own code then call mine.

The problem is that Imagesprocessor is using the readonly raw unvalidated url.

For example @mortenbock was using IIS module to rewrite
/product/xxx_large.jpg => /images/products/xxx.jpg?width=500

When the request hits imageprocessor after IIS module the Request.Url will be /images/products/xxx.jpg?width=500 and the raw url will still be /product/xxx_large.jpg

@albinj Could you please reply to the question I asked 21 days ago?

@JimBobSquarePants Sorry for not replying.

It doesn't feel right that you have to use ImageProcessingModule.ValidatingRequest or inherit the HttpModule class to be able to do a simple url rewrite. This logic should be in a IIS rewrite HttpModule.

I guess the easiest hack would be to somehow override the "request.Unvalidated.RawUrl" part in the HttpModule and replace it with the normal Request.Url. (I don't use facebook as a remote service). To allow you to keep the rewrite logic in the IIS rewrite module and make ImageProcessor process the rewritten url.
You could unseal the HttpModule and move request.Unvalidated.RawUrl into its own method and allow it to be overridden ?

That might be an idea, I'll have a look.

Hi @albinj @mortenbock @dsargent3220

I've done a couple of things that should now allow you all to do what you need.

Firstly ImageProcessingModule is now no-longer sealed.

Secondly I've made two critical methods virtual so they can be overriden. The original methods are as follows:

/// <summary>
/// Occurs when the user for the current request has been authorized.
/// </summary>
/// <param name="sender">
/// The source of the event.
/// </param>
/// <param name="e">
/// An <see cref="T:System.EventArgs">EventArgs</see> that contains the event data.
/// </param>
/// <returns>
/// The <see cref="T:System.Threading.Tasks.Task"/>.
/// </returns>
protected virtual Task PostAuthorizeRequest(object sender, EventArgs e)
{
    HttpContext context = ((HttpApplication)sender).Context;
    return this.ProcessImageAsync(context);
}

/// <summary>
/// Gets url for the current request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
protected virtual string GetRequestUrl(HttpRequest request)
{
    return request.Unvalidated.RawUrl;
}

This is the best I can do I'm afraid as there appears to be no way for me to workaround the encoding issues and allow rewriting in one stroke. Inheriting the class and overriding the methods will give you a lot to work with though.

Let me know if that helps.

Hi @JimBobSquarePants

I added a new file ImageProcessingModuleFix.cs in App_Code:

using ImageProcessor.Web.HttpModules;
using System.Web;

public class ImageProcessingModuleFix : ImageProcessingModule
{
    protected override string GetRequestUrl(HttpRequest request)
    {
        return request.Url.PathAndQuery;
    }
}

And changed current ImageProcessorModule to this new file in web.config:
<add name="ImageProcessorModule" type="ImageProcessingModuleFix, App_Code" />

Now all my URL Rewrite rules are working again. Awesome.

Thank you.

Great stuff! Glad I could help 馃槃

Was this page helpful?
0 / 5 - 0 ratings