3

I am writing a http handler that will load a file (css template) modify it's contents and serve it up as text/css.

I am basing the code on an example I found here:

http://madskristensen.net/post/Remove-whitespace-from-stylesheets-and-JavaScript-files.aspx

The business part of the code is:

public void ProcessRequest(HttpContext context)
{
    try
    {
        string file = context.Request.PhysicalPath;
        if (!File.Exists(file))
            return;

        string body = string.Empty;

        if (context.Cache[CSS_CACHE_BODY + file] != null)
            body = context.Cache[CSS_CACHE_BODY + file].ToString();

       if (body == string.Empty)
        {
            StreamReader reader = new StreamReader(file);
            body = reader.ReadToEnd();
            reader.Close();

            // Modify css template here
            CacheDependency cd = new CacheDependency(file);

            context.Cache.Insert(CSS_CACHE_BODY + file, body, cd);
        }

        context.Response.ContentType = "text/css";
        context.Response.Write(body);
    }
    catch (Exception ex)
    {
        context.Response.Write(ex.Message);
    }
}

I would appreciate if people could comment on the efficency and robustness of this code. I would rather not wait until it is a production environment to find out any problems!

2
  • 1
    You might check the corresponding source code from this project- requestreduce.com Commented Dec 20, 2011 at 14:42
  • Maybe wrap the StreamReader in a using block Commented Dec 20, 2011 at 14:45

1 Answer 1

2

There are some performance tips, you can cache the response client-side (using HTTP Headers). Andalso before sending the response, you can use White Space Removal method for your output. Another point is compression: compress the reponse if the browser support it.

Sample of client-side caching (in VB):

        Dim incomingEtag As String = context.Request.Headers("If-None-Match")
        Dim freshness As New TimeSpan(100, 0, 0, 0)
        context.Response.Cache.SetCacheability(HttpCacheability.Public)
        context.Response.Cache.SetExpires(DateTime.Now.ToUniversalTime.Add(freshness))
        context.Response.Cache.SetMaxAge(freshness)
        context.Response.Cache.SetValidUntilExpires(True)
        context.Response.Cache.VaryByHeaders("Accept-Encoding") = True
        context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches)

        Dim outgoingEtag As String = context.Request.Url.Authority & context.Request.Url.Query.GetHashCode()
        context.Response.Cache.SetETag(outgoingEtag)

Sample of White Space Removel function for CSS:

    Private Function StripWhitespace(ByVal body As String) As String

        body = body.Replace("  ", " ")
        body = body.Replace(Environment.NewLine, [String].Empty)
        body = body.Replace(vbTab, String.Empty)
        body = body.Replace(" {", "{")
        body = body.Replace(" :", ":")
        body = body.Replace(": ", ":")
        body = body.Replace(", ", ",")
        body = body.Replace("; ", ";")
        body = body.Replace(";}", "}")

        ' sometimes found when retrieving CSS remotely
        body = body.Replace("?", String.Empty)

        'body = Regex.Replace(body, @"/\*[^\*]*\*+([^/\*]*\*+)*/", "$1");
        body = Regex.Replace(body, "(?<=[>])\s{2,}(?=[<])|(?<=[>])\s{2,}(?=&nbsp;)|(?<=&ndsp;)\s{2,}(?=[<])", [String].Empty)

        'Remove comments from CSS
        body = Regex.Replace(body, "/\*[\d\D]*?\*/", String.Empty)

        Return body

    End Function

Sample of White Space Removel function for JS:

    Private Function StripWhitespace(ByVal body As String) As String

        Dim lines As String() = body.Split(New String() {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
        Dim emptyLines As New StringBuilder()
        For Each line As String In lines
            Dim s As String = line.Trim()
            If s.Length > 0 AndAlso Not s.StartsWith("//") Then
                emptyLines.AppendLine(s.Trim())
            End If
        Next

        body = emptyLines.ToString()
        body = Regex.Replace(body, "^[\s]+|[ \f\r\t\v]+$", [String].Empty)
        body = Regex.Replace(body, "([+-])\n\1", "$1 $1")
        body = Regex.Replace(body, "([^+-][+-])\n", "$1")
        body = Regex.Replace(body, "([^+]) ?(\+)", "$1$2")
        body = Regex.Replace(body, "(\+) ?([^+])", "$1$2")
        body = Regex.Replace(body, "([^-]) ?(\-)", "$1$2")
        body = Regex.Replace(body, "(\-) ?([^-])", "$1$2")
        body = Regex.Replace(body, "\n([{}()[\],<>/*%&|^!~?:=.;+-])", "$1")
        body = Regex.Replace(body, "(\W(if|while|for)\([^{]*?\))\n", "$1")
        body = Regex.Replace(body, "(\W(if|while|for)\([^{]*?\))((if|while|for)\([^{]*?\))\n", "$1$3")
        body = Regex.Replace(body, "([;}]else)\n", "$1 ")
        body = Regex.Replace(body, "(?<=[>])\s{2,}(?=[<])|(?<=[>])\s{2,}(?=&nbsp;)|(?<=&ndsp;)\s{2,}(?=[<])", [String].Empty)

        Return body

    End Function

Here is a sample to compress the output:

        Dim request As HttpRequest = context.Request
        Dim response As HttpResponse = context.Response

        Dim browserAcceptedEncoding As String = request.Headers("Accept-Encoding")

        If Not String.IsNullOrEmpty(browserAcceptedEncoding) Then

            browserAcceptedEncoding = browserAcceptedEncoding.ToLowerInvariant

            If (browserAcceptedEncoding.Contains("gzip")) Then
                response.AppendHeader("Content-encoding", "gzip")
                response.Filter = New GZipStream(response.Filter, CompressionMode.Compress)

            ElseIf (browserAcceptedEncoding.Contains("deflate")) Then
                response.AppendHeader("Content-encoding", "deflate")
                response.Filter = New DeflateStream(response.Filter, CompressionMode.Compress)

            End If

        End If
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.