Wandering Thoughts archives

2016-05-09

An Apache trick: using directories to create redirections

Suppose, not entirely hypothetically, that you're using Apache ProxyPass directives as a reverse proxy to map /someurl/ on your website to another web server. You generally have to redirect the URL with the trailing slash, but of course you would like a request for a plain '/someurl' to also work right instead of just getting a 404 status response. Here, 'work right' means that you'll generate a redirection from '/someurl' to '/someurl/'.

It's certainly possible to do this with one of the various Apache directives for explicit redirections (I'd use RedirectMatch). But often there's an easier way: use a real filesystem directory. If somedir is a directory in the Apache document root and you send a request for '/somedir', Apache's default behavior is to send exactly the redirection we want. And Apache doesn't care if the '/somedir/' URL is being diverted somewhere other than the filesystem (via ProxyPass or other directives); it will still send that redirection regardless.

So we can just do 'mkdir /docroot/someurl' and everything will work. The directory contents don't matter; I tend to put a README file there with a note about how the directory is just there for the redirection and actual contents in it will be ignored.

(This redirection trick happens automatically if you're using .htaccess files in a directory to control, say, internal redirections. However there are various reasons for not using .htaccess files, including centralizing your configuration in one easily visible place instead of spraying it all over the filesystem in a bunch of nominally invisible files.)

Back when I wrote my entry on ProxyPass, I theorized about using this trick. I can now say that we've actually done this in our configuration and it works fine.

(This trick is a very old one, of course; I'm sure people have been doing it in Apache for ages. I just feel like writing it down explicitly for various reasons.)

web/ApacheDirectoryRedirectTrick written at 22:01:33; Add Comment

You can't use expvar.Func to expose a bunch of expvar types

Suppose, hypothetically, that you have a collection of statistics that are each one of the expvar package's types. You want to put them in a namespace (so they are all 'mything.var1', 'mything.var2' and so on), but you'd like to avoid the tedious clutter of registering each expvar variable by hand with .Set(). So you have a clever idea.

First, you will embed all of the variables in a structure:

var somestats struct {
   var1, var2, var3   expvar.Int
   var4, var5, var6   expvar.Int
}

Then you will write a Stats() function that simply hands back the structure and then register it through expvar.Func():

func ReportStats() interface{} {
   return somestats
}

Unfortunately, this will not work (at least today). As I mentioned in my first set of notes on the expvar package, expvar.Func turns what your function returns into JSON by using json.Marshal, and this only returns exported fields. None of the expvar variable types have any exported fields, and so as a result expvar.Func() will convert them all to empty JSON (or possibly malfunction). You just can't get there from here.

This is kind of a bug (at a minimum, expvar.Func should document this restriction), but it's unlikely to change (apart from the documentation being updated). Beyond it not working today, there's no way to have a simple ReportStats function like this that work safely, and since you can't do this there's little to no point in making expvar variable types JSON-serializable through json.Marshal.

(To make this work, each expvar type would implement a MarshalJSON() method that did the appropriate thing. In fact, since expvar.String is really MarshalJSON() in disguise, you could just make one call the other.)

Sidebar: Why clear and complete documentation matters

Here is a question: is it deliberate that the 'thing to JSON' function for expvar.Var is not called MarshalJSON, or is it a historical accident? You can certainly argue that because my pattern above is fundamentally wrong, it's a feature that it doesn't work at all. Thus the choice of not using MarshalJSON in the expvar.Var interface could be entirely deliberate and informed, since it makes a broken thing (and all its variants) simply not work. Or this could be ultimately a mistake on the order of using String() in the expvar.Var interface, and so something that would be corrected in a hypothetical Go 2 (which is allowed to change APIs).

Without better documentation, people who come along to Go later just don't know. If you want to preserve the intent of the original designers of the language and the standard library, it really helps to be clear on what that intent is and perhaps the logic behind it. Otherwise it's hard to tell deliberate decisions from accidents.

programming/GoExpvarFuncLimit written at 02:45:15; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.