About

All articles, tagged with “programming”

Adding Vary Header Support To Nginx

Although Nginx supports proxy caching it doesn’t provide support for the HTTP Vary header out of the box. This is a problem if you want to use Nginx to proxy different versions of the same URI which Vary on Content-Language or proxy different representations of a RESTful resource specified via the Accept header.

Fortunately it’s relatively easy to add support for the Vary header using the Nginx Lua module and a small amount of Lua, which is much easier than building and maintaining a 3rd party module and doesn’t greatly impact performance.

First, we define a dictionary in the nginx config which will store a mapping from URIs to Vary headers:

lua_shared_dict uriToVary 10m;

Next we define the default location in the nginx config, which will use the lua ProxyRequest function to make a subrequest to /proxy_request then store the Vary header in the response in the dictionary.

location / {

    # make subrequest to /proxy_request, then store response headers
    content_by_lua '
        local vary = require("vary")
        local response = vary.ProxyRequest()
    ';
}

function ProxyRequest()

    -- make subrequest and capture response
    local response = ngx.location.capture("/proxy_request", {
        method = GetRequestMethod(ngx.var.request_method), body = ngx.req.get_body_data()})

    -- forward HTTP headers from response
    for k,v in pairs(response.header) do
        ngx.header[k] = v
    end

    ngx.shared.uriToVary:set(ngx.var.request_uri, response.header["Vary"])

    -- forward status and body from response
    ngx.status = response.status
    ngx.print(response.body)

    return response

end

Finally, we define the /proxy_request location which will use the lua RewriteCache function to combine the uri with the vary headers to generate the final cache key used by the proxy_cache module.

location /proxy_request {
    internal;

    # set defaults
    set $noCache 1;
    set $cacheBypass 1;
    set $cacheKey nil;

    # rewrite using stored data
    rewrite_by_lua '
        local vary = require("vary")
        vary.RewriteCache()
    ';

    # proxy request
    proxy_cache_bypass $cacheBypass;
    proxy_no_cache $noCache;
    proxy_cache_key $cacheKey;
    proxy_cache API_CACHE;
    proxy_pass $proxy$request_uri;
}

function RewriteCache()

    local varyOn = ngx.shared.uriToVary:get(ngx.var.request_uri)
    local cacheKey = nil

    -- if vary unknown for this uri, bypass cache and do not cache
    if varyOn == nil then
        return
    end

    cacheKey = ngx.var.request_uri .. GenerateCacheKey(varyOn, ngx.req.get_headers())
    ngx.var.noCache = 0
    ngx.var.cacheKey = cacheKey
    ngx.var.cacheBypass = 0

end

function GenerateCacheKey(varyOnStr, requestHeaders)

    local cacheKey = ""
    for part in string.gmatch(varyOnStr, "([^,%s+]+)") do

        if requestHeaders[part] then
            cacheKey = cacheKey .. ":" .. requestHeaders[part]
        end

    end

    return cacheKey

end

The first time a URI is requested the cache will be bypassed, but the Vary header from the response will be stored in the shared dictionary. The second time the URI is requested the cache key will be generated from the URI and the appropriate request headers specified in the vary header and the response will be cached. When the URI is subsequently requested with the same set of headers it will be served from the cache.

Note that when the shared dictionary is full it will evict old entries using an LRU scheme. Nginx will generate “ngx_slab_alloc() failed” errors when this occurs, but these can safely be ignored.

Thanks to @jonastryggvi for working with me on the Vary support and @CCPGames for allowing me to blog about it.

Super Hyperpolyglot

A few years ago nearly all the code I wrote was in C++, but increasingly I’m finding myself writing in a variety of mostly C-style languages and having to perform crunching mental gear changes as I switch between them.

In the interests of making these language switches less painful I thought about listing the commonly used features of the languages I commonly use in a side-by-side format. Luckily I’m a lazy programmer, the web is large and there’s nothing new under the sun, so I quickly found Hyperpolyglot which provides commonly used programming language features in a side-by-side format, which is what I wanted. Nearly.

Hyperpolyglot organizes it’s language comparisons in to several catagories: scripting languages, C++ family languages, embeddable languages and so on. In my case (and I suspect in many cases) the languages I wanted to compare were spread across several pages.

After briefly considering some cut and paste to get what I wanted I started playing with Google Spreadsheets, which has a very nifty importHtml function which allowed me to pull the Hyperpolyglot data in to several sheets which can be combined to produce arbitrary language comparisons.

It’s not perfect as different languages have different features and in some cases the Hyperpolyglot data doesn’t use exactly the same terms across tables (“version used” vs “versions used”) and I’m not a spreadsheet ninja, but it’s good enough to generate PDFs like this JavaScript Python Java C++ Comparision. As a Hyperpolyglot derivative work, The Super Hyperpolyglot Spreadsheet is licensed under the Creative Commons Attribution-ShareAlike 3.0 License, please let me know if you improve it.

Bouncaline

Last week I took some time off to spend with Luke and Natty during half term and we spent Wednesday having a lovely time finishing off a game we started a couple of months ago: Bouncaline.

Luke has been interested in making games for a while: he made a level for the You’re The Boss game at the Radiator festival in Nottingham in 2006 — when he was 3!

More recently Luke started designing a game that I was helping him put together in Game Maker. He drew lots of backgrounds and characters that we scanned in and there were vague ideas about treasure hunting game play, but it felt a bit like Luke was biting off more than he could chew.

So, when Luke and Natty inherited a trampoline over the summer I suggested that we build a bouncing game and we started building it with Scratch, an educational programming environment that I’d been meaning to experiment with since seeing that it had been ported to Second Life.

Scratch has a very simple model based on plugging together blocks that is similar to the Lego Mindstorms environment. Luke quickly got the hang of it and built a significant portion of the logic with just a few leading questions. Like Mindstorms and LSL it uses multiple flows of control within the same scripted object for complex behaviour, which can take some getting used to when making an object that simultaneously waits to be touched and for a timer, for example.

In some respects I wish Scratch was a little purer — although message passing concurrency is possible, it’s very easy to share state between objects — something we shouldn’t be encouraging the programmers of tomorrow to do. It’s also harder to do multiple levels or screens than with Game Maker, but given Luke’s propensity to lose himself in Zelda style epics, the tight focus might help learn the basics of logic.

Overall it’s a delightfully easy and rewarding environment to use. After spending a couple of hours finishing the logic, we went in to the garden to take pictures of the trampoline and Luke and Natty striking poses for the animations and quickly got them imported in to Scratch along with some very cute drawings and sound effects by Luke.

Scratch also makes it very easy to share your work on the web, allowing Luke to proudly show off his handy work to his Grandparents over the weekend and for me to proudly share the game with you here. I hope you enjoy Bouncaline!

Use the left and right arrow keys to move and try to collect the food.Learn more about this project