<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Darian Moody - Atom Feed</title>
  <id>urn:uuid:38d7ec10-9339-3fd2-bff2-2896de9ee944</id>
  <updated>2016-05-15T00:00:00Z</updated>
  <link href="https://www.djm.org.uk/" />
  <link href="https://www.djm.org.uk/feed.xml" rel="self" />
  <author>
    <name></name>
  </author>
  <generator uri="https://github.com/ajdavis/lektor-atom" version="0.1">Lektor Atom Plugin</generator>
  <entry xml:base="https://www.djm.org.uk/posts/elixir-behaviours-vs-protocols-what-is-the-difference/">
    <title type="text">Elixir's Behaviours vs Protocols</title>
    <id>urn:uuid:18dac311-4865-39c8-bafd-9a54d9d45f69</id>
    <updated>2016-05-15T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/elixir-behaviours-vs-protocols-what-is-the-difference/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;If you're just starting to learn Elixir, you will see both of these terms bandied about quite a bit and if you've taken the same route I did back when I first started then you've mostly ignored them until now, aside from reading short blurbs here and there. This has landed you in the situation where you likely don't know when or where you'd use them or even what the fundamental difference between the two are...that ends now! Behaviours and Protocols both bring polymorphic abilities to Elixir and are thus often confused but they are intrinsically different and bring their own flavour of polymorphism to different parts of the language.&lt;/p&gt;
&lt;p&gt;This post will be deliberately light on actual code; once you grok the core concepts there is &lt;a href=&quot;http://elixir-lang.org/getting-started/protocols.html&quot;&gt;plenty of great&lt;/a&gt; information &lt;a href=&quot;http://elixir-lang.org/getting-started/typespecs-and-behaviours.html#behaviours&quot;&gt;out there&lt;/a&gt; detailing how to implement them.&lt;/p&gt;
&lt;h2&gt;Polymorphic what mate?&lt;/h2&gt;
&lt;p&gt;If you didn't think of the &lt;em&gt;Mighty Morphin Power Rangers&lt;/em&gt; when you read that word, you can probably skip to the next header or be glad you never watched the Power Rangers. But for the rest of you, here's a quick lesson on what polymorphism is and why we would need it.&lt;/p&gt;
&lt;p&gt;Poly = &lt;em&gt;many&lt;/em&gt;. Morph = &lt;em&gt;change or form&lt;/em&gt;. Polymorphism is the ability in programming to present the same interface for differing underlying forms. What does that mean for us? Protocols allow the defining of interfaces (a series of functions) which can go on to be implemented by any data type and then used generically; and Behaviours define a common interface to a module, so that modules can be used interchangeably. Don't worry if you're lost, we'll delve deeper later.&lt;/p&gt;
&lt;p&gt;If you're ever added a float to an integer in a dynamic language, this is under-the-hood polymorphism at work. Both of them are numbers to us but they are stored differently in memory and are therefore different from the perspective of a computer. Polymorphism allows us to do calculations between the two data types without worrying about their underlying differences. In most languages, this happens behind the scenes by defining a &lt;em&gt;common contract&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Polymorphism in Elixirlang&lt;/h2&gt;
&lt;p&gt;Elixir can mostly be thought of in terms of 3 core things: processes, modules &amp;amp; data. In José's words: &quot;they are all interconnected: processes run the code defined in modules that manipulate the data types&quot; &lt;a href=&quot;https://groups.google.com/d/msg/elixir-lang-talk/Vq--xwBMmAI/WRjH3NKlZVYJ&quot;&gt;¹&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All 3 have their own way of &quot;doing&quot; polymorphism in Elixir:&lt;/p&gt;
&lt;h3&gt;Processes&lt;/h3&gt;
&lt;p&gt;Processes send messages to other processes without needing to care what the receiver process is or even what it does as long as it knows how to accept and deal with the message it was sent. The common interface here is how processes communicate with each other via the common contract that is message passing. Elixir has no way to document these messages as code, therefore making this form of polymorphism &lt;em&gt;implicit&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Modules&lt;/h3&gt;
&lt;p&gt;Modules hold a group a functions in a namespace. Code which calls a specific module doesn't really care about which module it is calling other than having the expectation that it contains a function of the desired arity and that it accepts the arguments being passed to it. Therefore if a module was to mimic another one and define exactly the same functions with the same signatures then it can be used interchangeably by the calling code.&lt;/p&gt;
&lt;p&gt;Actually, you could walk away from this post right now and write code that does that - but the result would be an implicit contract, your 2 modules would not be contractually linked in any other way than their circumstantial shared interface (this may sound familiar to gophers..). And this my friend is where Behaviours come in.&lt;/p&gt;
&lt;p&gt;A Behaviour is simply a module that defines a spec which other modules can implement; this allows our Elixir code to document the polymorphic contract and make it &lt;em&gt;explicit&lt;/em&gt;; it also allows our calling code to be not care one iota about the underlying implementation. Behaviours exist like a specification or a rule book allowing other modules that want to enact that Behaviour to follow the rules word for word.&lt;/p&gt;
&lt;h3&gt;Data&lt;/h3&gt;
&lt;p&gt;Data refers to the types which hold our information and flow around a system. Functions in Elixir can express that they are willing to work with certain data types by using pattern matching and guard statements against their arguments. But what happens when we want to write a function that works with a myriad of different data types?&lt;/p&gt;
&lt;p&gt;You might answer this with the fact that we could just define multiple functions of the same name and use pattern matching along with guards to provide the different implementation for all the data types. and you'd be right! We can totally do that. And it's even a great solution in many cases when you're only dealing with your own code or a specific subset of data types.&lt;/p&gt;
&lt;p&gt;But what happens when we're writing a library that we want to be really extensible? How does another developer take your code and use your implementations against their own data types of which you knew nothing about at the time of writing? This is where Protocols shine. By defining an interface that different data types can have different implementations of, another developer can come along and easily write their own implementation of your Protocol for their own data type.&lt;/p&gt;
&lt;p&gt;A Protocol is defined with the &lt;code&gt;defprotocol&lt;/code&gt; macro and is simply a group of function headers that a data type must implement if it is considered to be implementing that protocol. A data type then goes on to implement a Protocol by using the &lt;code&gt;defimpl ProtocolName, for: DataType&lt;/code&gt; line where &lt;code&gt;ProtocolName&lt;/code&gt; is the name of the Protocol being implemented and &lt;code&gt;DataType&lt;/code&gt; is the data type it is being implemented for.&lt;/p&gt;
&lt;h2&gt;To summarise&lt;/h2&gt;
&lt;p&gt;Protocols handle polymorphism at the data/type level whereas Behaviours provide it at the module level. While they seem similar it is because they both provide polymorphism rather than the fact they get used for the same things. Lets cement that knowledge by taking a little further look at those use cases.&lt;/p&gt;
&lt;p&gt;Behaviours answer the questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&quot;How can I define a public contract/spec for my modules to implement?&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&quot;How can I write code that can be extended by others?&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&quot;How would I go about writing a plugin/adapter based system?&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&quot;How can I write calling code to work with many swappable modules?&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Protocols answer the questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&quot;How can I have different implementations of the same function based on the different types I'm working with?&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&quot;How can I write code that can be extended to work with new data types I don't know about yet?&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Valid use cases&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Behaviours&lt;/strong&gt;: imagine you wanted to send an email but didn't particularly care how you did it. One day you might need to send it via a local SMTP server, another day via a paid online service (e.g Sendgrid). What do we need to do to make this happen without writing custom code which interacts with both methods of delivery? We need a common interface. If the function that sends email via an SMTP server accepts exactly the same arguments as the function that sends email via Sendgrid then we can switch out the functions easily. They become pluggable, and this is where Behaviours come in. With Behaviours we can define a module that documents the signature of this function (what it takes and what it returns) and then our SMTP and Sendgrid modules can both &quot;implement&quot; this behaviour and provide their own implementations of that function which match the one defined in the Behaviour. This way everything is explicit and our intentions are made known via code.&lt;/p&gt;
&lt;p&gt;This is a &lt;em&gt;real use case&lt;/em&gt;™ and can be viewed in both the &lt;a href=&quot;https://github.com/swoosh/swoosh/blob/47d7a0e8b7b1bb0d4d6054c7bf01f61235c7c8a9/lib/swoosh/adapter.ex#L15&quot;&gt;Swoosh&lt;/a&gt; and &lt;a href=&quot;https://github.com/thoughtbot/bamboo/blob/34bc93a96132794a2f9de0b47ffead5059a55e9b/lib/bamboo/adapter.ex#L36&quot;&gt;Bamboo&lt;/a&gt; email libraries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Protocols&lt;/strong&gt;: imagine a scenario where you have a series of varying data types that you need to print information about. Each data type stores its data in a unique way and has unique properties, and you also want the function to be able to work with data types that other developers may bring to the table. Here is where we would write a Protocol, perhaps named &lt;code&gt;Info&lt;/code&gt; which contains a function called &lt;code&gt;info&lt;/code&gt; that takes one argument - the data type instance to print information about. The various data types would then implement the &lt;code&gt;Info&lt;/code&gt; protocol by defining their own implementations of the &lt;code&gt;info&lt;/code&gt; function which each print information about the type instance that is helpful to the user.&lt;/p&gt;
&lt;p&gt;This is also a &lt;em&gt;real use case&lt;/em&gt;™ and is actually built in to Elixir as &lt;a href=&quot;https://github.com/elixir-lang/elixir/blob/a8547c43c75595630383f592f6fb03cd1d999466/lib/iex/lib/iex/info.ex#L1&quot;&gt;&lt;code&gt;IEx.Info&lt;/code&gt;&lt;/a&gt;. Whenever you use &lt;code&gt;i &amp;lt;data-variable&amp;gt;&lt;/code&gt; in iex, this protocol will be being invoked in the background to display the information.&lt;/p&gt;
&lt;h2&gt;Self documentation is power to the reader&lt;/h2&gt;
&lt;p&gt;While these constructs allow us to write extensible Elixir, they are also self documenting. When writing code, there is a common misconception that you are writing it for a machine to read but this is not the sole reality. A machine will eat whatever you chuck at it, it does not care for your coding style. No, you are writing code for whoever is going to read it next, even when that person is you in 6 months time.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://i.imgur.com/UPvQeEz.jpg&quot;&gt;Polymorphism can be a dangerous beast&lt;/a&gt; in other languages as it is often implicit by design: if it quacks like a duck then it must be a duck, right? Wrong, and this leads to confusion. Over in Elixir lang we prefer explicitness over implicitness.&lt;/p&gt;
&lt;p&gt;By providing Behaviours &amp;amp; Protocols, Elixir allows us to define and therefore document our interfaces as code. Because we explicitly define the contracts and explicitly link them via code that gets committed it means the next reader is not left guessing as to what was going on in the mind of the developer that wrote it: the desired intention is quite literally written in plain English in front of them.&lt;/p&gt;
&lt;p&gt;On top of this, because we have these things defined in code we can &quot;lean on&quot; (rely on) the compiler to check that our code is covering all the bases it should and is actually complying with the contracts that it has explicitly stated it should. With Behaviours: need another function and want it implemented across the board? Just do it and the compiler will have your back, ensuring that all the modules that implemented the original Behaviour are updated.&lt;/p&gt;
&lt;p&gt;And we get all this without writing actual documentation or comments which have a terrible tendency to get out of date. Proper ace.&lt;/p&gt;
&lt;h2&gt;So in conclusion..&lt;/h2&gt;
&lt;p&gt;Both of these language features are designed to being polymorphic attributes to Elixir; Behaviours bring polymorphism at the module level and Protocols bring it at the type/data level.&lt;/p&gt;
&lt;p&gt;If you would like to read a more in depth about Behaviours in particular, you can read my earlier post which delves further into &lt;a href=&quot;../../posts/writing-extensible-elixir-with-behaviours-adapters-pluggable-backends/&quot;&gt;what Elixir's Behaviours are, what they look like, what they do and when you'd use them&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This post has taken many explanations from across the web and amalgamated them, so I'd like to say thanks to José Valim, Saša Jurić, Eric Meadows-Jönsson &amp;amp; Alexander Songe. And of course you for reading this far, nice one.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/writing-extensible-elixir-with-behaviours-adapters-pluggable-backends/">
    <title type="text">Writing extensible Elixir with Behaviours</title>
    <id>urn:uuid:3da5d812-42be-3d9a-a00f-6f55e908466a</id>
    <updated>2016-04-09T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/writing-extensible-elixir-with-behaviours-adapters-pluggable-backends/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;Let's set the scene. You've written a piece of code that you would like to work with a variety of different &quot;things&quot; – yeah, we're getting properly scientific here, bare with me. These various things share a common trait in that they achieve the same high-level result; but the way they each go about working towards that result may be slightly or—more likely—completely different.&lt;/p&gt;
&lt;p&gt;Often your code only needs to use one of these things at a time, but you don't want to put all your eggs in one basket and leave code specific to that thing throughout your entire codebase. That would be nasty. And wouldn't it be ace if other people could bring more &quot;things&quot; to the table and extend your software without you even lifting a finger?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&quot;I don't have all day mate. Can't I just pick one and go with it?&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You definitely could. But what happens if you change your mind about the thing you'd like to use? What if the thing you thought was a gleaming unicorn actually turns out to be a squashed toad, or worse: what if the thing magically &lt;em&gt;disappears&lt;/em&gt; in a puff of VC-farted air? In such a horrific circumstance it would be great if we could simply &lt;del&gt;murder the founders&lt;/del&gt; swap out our thing for another thing or just rewrite a new thing without having to change &lt;em&gt;everything&lt;/em&gt; we've already written. Right?&lt;/p&gt;
&lt;h2&gt;Enough about things already..&lt;/h2&gt;
&lt;p&gt;By now you may have grasped what I'm getting at. &quot;Things&quot; come in millions of flavours but let's stop with the vagueness and give some proper real world examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;a messaging app that needs to send an email but has a number of delivery options open to it: SMTP, Mandrill, Sendgrid, Postmark, [future SaaS product], etc. With this first example, the &quot;things&quot; are the delivery methods, they all accept &amp;amp; deliver an email but they differ in how they achieve it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a CV generator that takes input from a web form and renders the given data in HTML, PDF, Markdown, LaTeX, [insert format yet to be invented], etc. The &quot;things&quot; here are the differing document formats, they all accept the same input but they each do different things with it to achieve the same high-level result, which is a document the user can take away.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a storage engine that takes data and stores it in a database: PostgreSQL, MySQL, SQLite etc. Here the &quot;things&quot; are the databases, they can all accept queries to store data but they each handle them in varying ways. And yup, this just described &lt;a href=&quot;https://github.com/elixir-lang/ecto&quot;&gt;Ecto&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these scenarios pose a serious problem for us as we want to work with these damn things but the differences between them present a daunting barrier. Many languages have a solution to this and Elixir is no different: enter the &lt;em&gt;Behaviour&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Elixir's Behaviours&lt;/h2&gt;
&lt;p&gt;The hint is in the name. To interface with multiple things as if they were one: we need to define their common &lt;em&gt;behaviours&lt;/em&gt; in an abstraction. And that is exactly what an Elixir &lt;a href=&quot;http://elixir-lang.org/getting-started/typespecs-and-behaviours.html#behaviours&quot;&gt;Behaviour&lt;/a&gt; is: the definition of said abstraction. Behaviours exist like a specification or a rule book allowing other modules that want to enact that Behaviour to follow the rules word for word. This allows your calling code to only care about the common interface and therefore it can be blissfully unaware of the horror that lies beneath. Need to swap services? Just do it! Your calling code won't care.&lt;/p&gt;
&lt;p&gt;But what does one look like? A Behaviour is defined as a normal module, inside which you define a group of function specs that &lt;em&gt;must&lt;/em&gt; be implemented by any modules adopting that Behaviour. Each function spec is defined by using the &lt;code&gt;@callback&lt;/code&gt; directive and a &lt;a href=&quot;http://elixir-lang.org/getting-started/typespecs-and-behaviours.html#types-and-specs&quot;&gt;typespec&lt;/a&gt; signature, which is a way of defining what each function receives and returns. Without further ado:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Parser&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;@callback&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;@callback&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All modules that wish to adopt this Behaviour must:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Explicitly state they wish to do so by using: &lt;code&gt;@behaviour Parser&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;parse/1&lt;/code&gt; which takes a string and returns any term.&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;extensions/0&lt;/code&gt; which takes zilch and returns a list of strings.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Behaviour usage is explicit and therefore any modules adopting the Behaviour must actively state that fact by using the &lt;code&gt;@behaviour SomeModule&lt;/code&gt; module attribute; this is incredibly handy for you as it means you can lean on the compiler to warn you when your modules are not following the spec. If you update the Behaviour with new signatures, you can be sure as hell that the compiler will be on your tail to make sure the adopters follow suit.&lt;/p&gt;
&lt;h2&gt;Delving deeper&lt;/h2&gt;
&lt;p&gt;If you don't quite grok it, it may help to look at other languages. If you're versed in Python, this post on &lt;a href=&quot;http://charlesleifer.com/blog/django-patterns-pluggable-backends/&quot;&gt;Pluggable Backends&lt;/a&gt;  by Charles Leifer is a great explanation of the general pattern. If you're from Ruby, you can read it too - the philosophy is the same (inherit a base adapter and hope for the best, eek). And for Gophers, you will find some similarities (with some key differences) in &lt;a href=&quot;http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go&quot;&gt;Interfaces&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Having said that - it's much easier to show how Behaviours can help you write extensible code with a live working example and so we're going to go deeper with the email case I explained earlier and in particular, &lt;a href=&quot;https://twitter.com/stevedomin&quot;&gt;Steve Domin&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://twitter.com/BarisBalic&quot;&gt;Baris Balic&lt;/a&gt;'s &lt;a href=&quot;https://github.com/swoosh/swoosh&quot;&gt;Swoosh&lt;/a&gt; email library which utilises Behaviours to provide a stack of email delivery methods, while also allowing extra ones created by others to be plugged in.&lt;/p&gt;
&lt;h2&gt;Defining a Behaviour's public contract&lt;/h2&gt;
&lt;p&gt;We've been through the &lt;em&gt;why&lt;/em&gt; so let's skip to the real world and take a look at a library that needed it: &lt;a href=&quot;https://github.com/swoosh/swoosh&quot;&gt;Swoosh&lt;/a&gt;. Swoosh allows you to create an email and send it via a bunch of delivery options. It needed to abstract the common behaviour of delivering an email so let's have a look at how it does so in &lt;a href=&quot;https://github.com/swoosh/swoosh/blob/ba3af6753171f7010bf3ed826d4156b8fa57df6f/lib/swoosh/adapter.ex&quot;&gt;&lt;code&gt;Swoosh.Adapter&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Swoosh.Adapter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;@moduledoc&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;~S&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;  Specification of the email delivery adapter.&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;  &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;@type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;@type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Swoosh.Email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;@typep&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Keyword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;@doc&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;  Delivers an email with the given config.&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;  &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;@callback&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deliver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, the example is slightly longer than the one from the documentation as Swoosh defines a bunch of types for extra readability &amp;amp; clarity (e.g &lt;code&gt;config&lt;/code&gt; is used as an alias to be more descriptive than &lt;code&gt;Keyword.t&lt;/code&gt;). We can ignore that for now though, we care about the &lt;code&gt;@callback&lt;/code&gt; directive which sets the rules for the one and only function on the delivery abstraction: to &lt;code&gt;deliver&lt;/code&gt; email. The &lt;code&gt;deliver/2&lt;/code&gt; specification tells us that it takes two arguments: a &lt;code&gt;Swoosh.Email&lt;/code&gt; struct and a config as a keyword list; it can then &quot;do something&quot;; and in return it gives back an idiomatic ok/error tuple.&lt;/p&gt;
&lt;h2&gt;Adopting a behaviour&lt;/h2&gt;
&lt;p&gt;It's time to define the &quot;does something&quot;. We'll take a look at 2 adapters that adopt the Behaviour and ship with Swoosh. First we'll take a simple one: the &lt;code&gt;Local&lt;/code&gt; client which simply delivers email to an in-memory inbox.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Swoosh.Adapters.Local&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;@behaviour&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Swoosh.Adapter&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deliver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(%&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Swoosh.Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Swoosh.Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;%{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Message-ID&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Swoosh.InMemoryMailbox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;%{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There's not really much to explain here thankfully. First up the adapter explicitly says that it is adopting the &lt;code&gt;Swoosh.Adapter&lt;/code&gt; Behaviour. It then goes on to define the &lt;code&gt;deliver/2&lt;/code&gt; function with exactly the same signature as was found in the Behaviour definition. Remember, the explicit statement of adoption is there to let the compiler do the hard work. If the Swoosh devs were to add an extra function to their mail delivery Behaviour, all modules that adopt that Behaviour would have to be updated too, otherwise the application would simply not compile, it's a fantastic safety net.&lt;/p&gt;
&lt;p&gt;The next client, for sending an email via &lt;code&gt;Sendgrid&lt;/code&gt;, is too long to copy here but you can &lt;a href=&quot;https://github.com/swoosh/swoosh/blob/4f3ed760aa8c6bd3c6e8f2d952ecea9575a6fddd/lib/swoosh/adapters/sendgrid.ex#L28&quot;&gt;reference it on GitHub&lt;/a&gt;. You will note that the module is a lot more complex and defines other functions along with the one it must do: &lt;code&gt;deliver/2&lt;/code&gt;. This is worth noting: the Behaviour contract does not care what else is defined in the module. The functions do not have to map 1:1; the adopter must simply implement the functions defined in the Behaviour and then it is free to do what it likes. This allows for more complex adapters as the functions common to the Behaviour can call out to other functions in the same module or elsewhere to increase readability &amp;amp; maintainability.&lt;/p&gt;
&lt;h2&gt;Adding the extensibility&lt;/h2&gt;
&lt;p&gt;We've learnt how to define a Behaviour, and how to adopt it but how does this help us when we actually want to use them in the calling code of our application? There are a number of ways to go about using Behaviours, all of varying complexity. We'll start with the easiest and work our way up.&lt;/p&gt;
&lt;h3&gt;Dependency injection via a function head&lt;/h3&gt;
&lt;p&gt;Going back to the earlier Parser Behaviour example from the docs:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;@default_parser&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;XMLParser&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;defstruct&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(%&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Keyword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;@default_parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; 
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we use a contrived &lt;code&gt;Document&lt;/code&gt; module which has created a function-based wrapper for our parsing Behaviour so that we can easily switch out parsers. Let's run it..&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We pass just one argument and no options, this causes the &lt;code&gt;:parser&lt;/code&gt; options key to be unavailable leaving the &lt;code&gt;Keyword.pop&lt;/code&gt; to fall back to the &lt;code&gt;@default_parser&lt;/code&gt; module that we supplied as a module attribute. The &lt;code&gt;parse/1&lt;/code&gt; function of that parser then gets executed, being sent the string of the document body.&lt;/p&gt;
&lt;p&gt;Great, but what if we don't want to use the &lt;code&gt;XMLParser&lt;/code&gt;?&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JSONParser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because both the &lt;code&gt;XMLParser&lt;/code&gt; and &lt;code&gt;JSONParser&lt;/code&gt; adopted the &lt;code&gt;Parser&lt;/code&gt; Behaviour, they both support the &lt;code&gt;parse/1&lt;/code&gt; function called within the parsing wrapper and thus swapping the parser out becomes as simple as injecting the new dependency into the wrapper function. This way of handling behaviours is very malleable and powerful for the programmer, it even allows different parts of the code base to use different parsers for example, but there are downsides. This method means you have to rely on the user knowing &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;where&lt;/em&gt; to inject the dependency which will require more intricate documenting. On top of that, what if the user wants to use different dependencies in different environments? Your calling code will get lumped with the effort of working out which module to use and when – wouldn't it be nicer if we could set the desired adapter once and forget about it?&lt;/p&gt;
&lt;h3&gt;Dependency injection via Mix Config&lt;/h3&gt;
&lt;p&gt;Thanks to &lt;code&gt;Mix&lt;/code&gt;'s project configuration, this is a solved problem. If we take the Parser example again:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;@default_parser&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;XMLParser&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;defstruct&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(%&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:parser_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;@default_parser&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; 
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, our &lt;code&gt;parse&lt;/code&gt; function wrapper has lost the options argument and instead is calculating which parser to use based on the current OTP application's Mix configuration. So, given a Mix config that looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# config/config.exs&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:parser_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JSONParser&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;..our &lt;code&gt;Document.parse&lt;/code&gt; wrapper will know to use the &lt;code&gt;JSONParser&lt;/code&gt; for parsing. This helps us a great deal as our adapter choice is no longer anchored to the calling code and therefore a simple update to the Mix config, or an environment-specific config can swap the parser used in the future. Again though, this method has its downsides: the configuration is very much tied to the &lt;code&gt;Document&lt;/code&gt; module due to the use of &lt;code&gt;__MODULE__&lt;/code&gt; (the module name) in the config/env lookup. This means that we've gone from being able to use multiple different parsers to just one throughout all our code that uses the &lt;code&gt;Document&lt;/code&gt; module. While in most instances one adapter is likely enough for the entire project, what if we come across a situation where we need to use different adapters with the same bit of code? What if a segment of your codebase needs to send email via Sendgrid but another part is required to interact with your legacy SMTP server? Let's go back to Swoosh..&lt;/p&gt;
&lt;h3&gt;Achieving the advantages of both...&lt;/h3&gt;
&lt;p&gt;Luckily for us, Swoosh replicates how Ecto handles this problem. As the programmer, you are required to define your own Module somewhere in your codebase which then specifies &lt;code&gt;use Swoosh.Mailer&lt;/code&gt;. Your calling code then uses this module as a wrapper to the underlying &lt;code&gt;Swoosh.Mailer&lt;/code&gt;. Details on how this patterns works is out of scope for this article but for basics: the &lt;code&gt;use&lt;/code&gt; builtin in Elixir tells the compiler to run the macro named &lt;code&gt;__using__&lt;/code&gt; in the file the module wishes to use. You can see exactly what the &lt;code&gt;Swoosh.Mailer.__using__&lt;/code&gt; macro includes in your wrapper module by &lt;a href=&quot;https://github.com/swoosh/swoosh/blob/4f3ed760aa8c6bd3c6e8f2d952ecea9575a6fddd/lib/swoosh/mailer.ex#L60&quot;&gt;taking a look on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This means the project configuration of Swoosh exists in two places:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# In your config/config.exs file&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Sample.Mailer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Swoosh.Adapters.Sendgrid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;SG.x.x&amp;quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# In your application code&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Sample.Mailer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Swoosh.Mailer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;otp_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sample&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By doing it this way, each created wrapper module can have it's own settings in the Mix config. To create the ability to use Swoosh multiple times with different adapters in the same codebase, all the developer has to do is define two or more of their own modules which all &lt;code&gt;use Swoosh.Mailer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;..and that is that! You now know how to create some very publicly extensible code so you totally won't have to resort to murder when the service you so heavily rely on pulls the plug. Before we end, just a few more things to wrap up...&lt;/p&gt;
&lt;h2&gt;More examples of Behaviours in the wild&lt;/h2&gt;
&lt;p&gt;Reading already existing code will help cement your understanding of Behaviours and when to use them. Here's two to get you started:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/elixir-lang/plug&quot;&gt;Plug&lt;/a&gt; - Elixir's spec for composable web app modules is actually a Behaviour itself. When someone says they have created a Plug, they are in fact saying that they have adopted the Plug Behaviour which is incredible simple: a module must simply implement 2 functions: &lt;code&gt;init/1&lt;/code&gt; and &lt;code&gt;call/2&lt;/code&gt;. The use of Behaviours here actually allow for the composability of Plugs, as their public API is known it allows them to be easily &quot;plugged together&quot; in to pipelines, as seen in Phoenix.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/elixir-lang/ecto&quot;&gt;Ecto&lt;/a&gt; - uses them for a myriad of things including the storage adapters, custom field types, associations, changeset relations, database connections, postgrex extensions, migration adapters and the repo itself.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Things to watch out for&lt;/h2&gt;
&lt;p&gt;To conclude &amp;amp; summarise the benefits of this approach: it allows for loosely coupled code that adheres to an explicit public contract. It enables programmers to extend the current functionality by explicitly detailing in advance the interactions that occur. The fact the public contract is explicit makes it much easier to test without &lt;a href=&quot;http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/&quot;&gt;resorting to &quot;mocking as a verb&quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That being said, this approach is not perfect for all problems. By defining a common set of interactions between all plugins you are essentially saying that all plugins provide the same functionality and that is obviously not always true: in situations like these you can find yourself coding for the lowest common denominator. For an even-further reading exercise I would recommend nosy-ing around the Ecto codebase, and in particular how they handle the fact that only certain database backends provide &lt;a href=&quot;https://github.com/elixir-lang/ecto/blob/a75ae3aafacfb05a5c123e9fe1b8be19cd5eef96/lib/ecto/migrator.ex#L111&quot;&gt;DDL transactions&lt;/a&gt; by providing a &lt;a href=&quot;https://github.com/elixir-lang/ecto/blob/a45390e1dead49574d1f1c72ebaf8b539a78e1d4/lib/ecto/adapter/migration.ex#L39&quot;&gt;common feature-test callback&lt;/a&gt; as part of the Behaviour.&lt;/p&gt;
&lt;h2&gt;Finishing up&lt;/h2&gt;
&lt;p&gt;That turned into a bit of a &lt;strong&gt;mammoth&lt;/strong&gt; post. Well, thanks for getting this far &amp;amp; hopefully something clicked if you did. If you'd like to add anything, feel free to shoot me an &lt;a href=&quot;mailto:mail@djm.org.uk&quot;&gt;email&lt;/a&gt; or catch me on &lt;a href=&quot;https://twitter.com/djm_&quot;&gt;twitter&lt;/a&gt;, otherwise share away and spread the Elixir love!&lt;/p&gt;
&lt;p&gt;Special thanks to &lt;a href=&quot;https://twitter.com/BarisBalic&quot;&gt;Baris&lt;/a&gt; for reading the draft through. Big ups.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/elixir-keyword-lists-function-parameters/">
    <title type="text">Elixir's keyword lists as option parameters</title>
    <id>urn:uuid:4ae5cd8a-5a1f-3cce-a8af-d88c704871c6</id>
    <updated>2015-03-22T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/elixir-keyword-lists-function-parameters/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;This article also offers an intro to the Keyword List type in Elixir; non-beginners can almost certainly skip to the last section.&lt;/p&gt;
&lt;h2&gt;An intro to Elixir's Keyword Lists&lt;/h2&gt;
&lt;p&gt;Keyword lists in Elixir are simply a special case of a list, their contents being made up entirely of 2-item &quot;pair&quot; tuples with the first item of each being an Elixir &lt;code&gt;:atom&lt;/code&gt;. Unlike maps, they are ordered and may contain multiple values for the same key. Due to their prevalence in the language, a lot of syntactic sugar has been created to make working with them easier and more idiomatic. For example, during creation:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:dogs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;cats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;dogs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can see that the two ways of defining them are one and the same, the one on the right obviously being the syntactically sugared version.&lt;/p&gt;
&lt;h2&gt;Passing an optional set of options to a function&lt;/h2&gt;
&lt;p&gt;Other than creating small k:v stores, this is their primary use case in both Elixir &amp;amp; Erlang. By allowing a client to pass in a keyword list full of options, the function can conditionally change its logic. The keyword list is commonly optional and passed as the last parameter, so common in fact that Elixir has provided more syntactic sugar which allows you to leave off the keyword lists square brackets when it is being passed as the last parameter. For example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func_with_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;\\&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;..and the function can be called as follows:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# With no options at all..&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;func_with_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;arg1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# With options, the non-sugared way.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;func_with_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;arg1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# With options, with syntactic sugar.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;func_with_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;arg1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that in the last instance the function signature is still &lt;code&gt;func_with_options/2&lt;/code&gt;; despite the keyword list having 2 elements they are contained inside one list, the arity of the function does not change.&lt;/p&gt;
&lt;p&gt;And that leads us on to the main point of this article: what if a function accepts only one parameter and it is a keyword list?&lt;/p&gt;
&lt;h2&gt;Retrieving the same return for different input&lt;/h2&gt;
&lt;p&gt;I'm sure there is a much better way of putting that but I do currently know it; this is better showcased by an example. First, let's set the scene:&lt;/p&gt;
&lt;p&gt;You have user account functionality in your app and the record for each user contains, amongst others, the fields: &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt; &amp;amp; &lt;code&gt;ni_number&lt;/code&gt;; the user's username, email address, and National Insurance number respectively - all unique, indexed and all strings. You'd like to create some form of a shortcut to retrieve a user record from your data store using any of the aforementioned fields; as they are all unique to the user, only one is required to get a hit.&lt;/p&gt;
&lt;p&gt;In quite a few languages, we suffer a problem here as all 3 lookups are string based, we therefore cannot rely on type to allow our helper function to do different things based on the input. If it was just &lt;code&gt;username&lt;/code&gt; &amp;amp; &lt;code&gt;email&lt;/code&gt; perhaps we could do a check to see if the string contains an '@' sign but that would be a flimsy solution at best, and completely falls apart when we also want to allow lookup by &lt;code&gt;ni_number&lt;/code&gt; which like username, is just an alphanumerical string. Thus, a solution to this that I have often seen in various languages is multiple helper methods:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Pseudo-code&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;get_user_by_username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;harry&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;get_user_by_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;harry@example.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;get_user_by_ni_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;JN032185D&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# or even:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_by_username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;harry&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_by_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;harry@example.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_by_ni_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;JN032185D&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Fine, both ways get the job done but that is about all you can say about them.&lt;/p&gt;
&lt;p&gt;In Python, another common pattern is to pass keyword arguments as a form of lookup dictionary:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SomeORM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;get_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;harry&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;get_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;harry@example.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;get_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ni_number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;JN032185D&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is an improvement but in this instance it tightly couples the logic of your wrapper with that of the ORM or underlying data store, as the client must know the field names or the lookup dict might even have a special format (e.g Django's &lt;code&gt;fieldname__iexact&lt;/code&gt; lookup filters). This makes the wrapper less useful from an abstraction perspective.&lt;/p&gt;
&lt;p&gt;Now, back to Elixir. As we've already said, when the last parameter to a function is a keyword list, you can leave off the square brackets; this also applies when the parameter is also the first and only one. Therefore we can combine multiple function clauses with Elixir's pattern matching to allow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the handling code to split up the differing lookups without using conditional logic. Our brains are not perfect at following conditional branches, following linear code is much less bug-prone.&lt;/li&gt;
&lt;li&gt;our clients to have a nice API, where they simply hint at the type of lookup they wish for.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;do&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Do lookup with username&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Do lookup with email&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ni_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ni_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Do lookup with ni_number&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Which gives us a the following API..&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;harry&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;harry@example.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ni_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;JN032185D&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that is the power that can be achieved by combining multiple function clauses with pattern matching. As with any powerful thing, it will be likely be abused - so only use this pattern in cases where it completely makes sense: if in doubt, multiple parameters to a function is the normal way to go.&lt;/p&gt;
&lt;p&gt;This pattern is in fact already in use in the code powering &lt;a href=&quot;http://hex.pm&quot;&gt;hex.pm&lt;/a&gt;; you can see the code base over at the &lt;a href=&quot;https://github.com/hexpm/hex_web/blob/9ba0e119564e56ff0a57a575ba5e9d30f8aaf9e4/lib/hex_web/user.ex#L143&quot;&gt;hex_web repository on github&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/cryptographic-hash-functions-elixir-generating-hex-digests-md5-sha1-sha2/">
    <title type="text">Cryptographic hash functions in Elixir</title>
    <id>urn:uuid:f34cc06d-6d6c-37a5-a59f-5370359ef294</id>
    <updated>2015-02-23T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/cryptographic-hash-functions-elixir-generating-hex-digests-md5-sha1-sha2/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;First off, the &lt;code&gt;md5&lt;/code&gt; and &lt;code&gt;sha1&lt;/code&gt; cryptographic hash functions should only be used when security is not a requirement or when compatibility with legacy applications is needed. &lt;code&gt;md5&lt;/code&gt; was physically broken a very long time ago, and &lt;code&gt;sha1&lt;/code&gt; was theoretically broken back in 2005. When you need a hash for secure purposes, use a hash from the &lt;code&gt;sha2&lt;/code&gt; set (at least until &lt;code&gt;sha3&lt;/code&gt; starts appearing in libraries).&lt;/p&gt;
&lt;h2&gt;Versioning&lt;/h2&gt;
&lt;p&gt;This post applies to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elixir: v1.0.3&lt;/li&gt;
&lt;li&gt;Erlang: OTP 17&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Dropping down into Erlang&lt;/h2&gt;
&lt;p&gt;Now that is out of the way, the title is rather incorrect! To get access to these functions in Elixir we need to drop down into Erlang - however, that is incredibly easy. Most Erlang modules can be accessed from Elixir by simply using a colon in front of their lowercase module name. In this instance, we want &lt;code&gt;:crypto&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Where &lt;code&gt;:sha256&lt;/code&gt; is used below, it can be swapped out for the following hash algorithms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:md5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:ripemd160&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:sha&lt;/code&gt; (SHA-1)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:sha224&lt;/code&gt; (SHA-2)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:sha256&lt;/code&gt; (SHA-2)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:sha384&lt;/code&gt; (SHA-2)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:sha512&lt;/code&gt; (SHA-2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more information, please see the &lt;a href=&quot;http://www.erlang.org/doc/man/crypto.html&quot;&gt;Erlang Crypto module documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Non-streaming hashing&lt;/h2&gt;
&lt;p&gt;Erlang offers up the &lt;code&gt;crypto.hash/2&lt;/code&gt; function for hashing when you have all the values you want to hash ready to go. In the following examples, we are calculating the &lt;code&gt;sha256&lt;/code&gt; hash of the binary string &lt;code&gt;&quot;whatever&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To get the binary hash:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:crypto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;whatever&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And to get the hex digest from that:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:crypto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sha256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;whatever&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode16&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want it in lowercase, carry on the piping to &lt;code&gt;String.downcase&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And finally, to show an example of hashing multiple things in a list:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:crypto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sha256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;things&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode16&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Streaming hashing&lt;/h2&gt;
&lt;p&gt;Erlang also allows us to build up a hash from multiple items when perhaps all the items are not available to you yet using the functions: &lt;code&gt;crypto.hash_init/1&lt;/code&gt;, &lt;code&gt;crypto.hash_update/2&lt;/code&gt; &amp;amp; &lt;code&gt;crypto.hash_final/1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The following it how you use the functions together procedurally (and is for example only, this is not proper Elixir form by any means):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sha&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:crypto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sha256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sha&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:crypto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash_update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sha&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:crypto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash_update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;things&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sha_binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:crypto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash_final&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sha_hex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sha_binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;downcase&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, we create a hash &quot;context&quot; using &lt;code&gt;crypto.hash_init/1&lt;/code&gt;, and then pass that context into subsequent &lt;code&gt;crypto.hash_update/2&lt;/code&gt; calls along with the extra value to add to the hash. When we have finished adding all the items we want hashed, we simply run &lt;code&gt;crypto.hash_final/1&lt;/code&gt; with our created hash context to receive the hash binary, which can then easily be converted into a hex digest as shown.&lt;/p&gt;
&lt;p&gt;One final thing: &lt;strong&gt;please don't use these for storing passwords&lt;/strong&gt;, hashing algorithms are too fast, what you want is a &lt;em&gt;key derivation function&lt;/em&gt; as they are more suitable for preventing brute forcing attacks - use extensive rounds of bcrypt or PBKDF2 instead.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/protect-yourself-from-non-obvious-dangers-curl-url-pipe-sh/">
    <title type="text">The hidden dangers of piping curl</title>
    <id>urn:uuid:2460805b-2e02-3961-988c-457d2aaccc3c</id>
    <updated>2013-08-17T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/protect-yourself-from-non-obvious-dangers-curl-url-pipe-sh/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;Unless you haven't been installing developer focused 3rd party software recently, you will probably have seen the following command line used as a suggested way of installing a particular software package direct from the web:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;curl -s http://example.com/install.sh &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; sh
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This post is not here to debate whether or not this is a good idea but rather to make those that use this pattern aware of a non-obvious flaw, aside from all the obvious issues with piping 3rd party data directly into your shell. There have been countless discussions on this method and one argument for it has always been &lt;em&gt;transparency&lt;/em&gt; - as in, you can simply check the script by opening it in your browser before piping it to bash via curl.&lt;/p&gt;
&lt;p&gt;This post is here to &lt;em&gt;a)&lt;/em&gt; show that this level of trust can be hijacked and &lt;em&gt;b)&lt;/em&gt; to provide an easy way of protecting yourself when you wish to install via curl.&lt;/p&gt;
&lt;h2&gt;Proof of concept, everything is not as it seems.&lt;/h2&gt;
&lt;p&gt;To cut straight to the chase, this attack works on the theory that the content of the .sh files are easily checked for safety and that the version of the file viewed in a browser window is identical to that which would get downloaded via curl. The problem with this assumption is that a given browser and curl do not send the same user-agent by default and therefore someone with knowledge of this could &lt;a href=&quot;https://github.com/djm/pipe-to-sh-poc/blob/master/proof_of_concept.py#L18-L24&quot;&gt;take advantage of this&lt;/a&gt; and compromise the .sh file (jumping through other loops do to that first obviously).&lt;/p&gt;
&lt;p&gt;For this, a simple proof of concept has been written &amp;amp; hosted: you can view the &lt;a href=&quot;https://github.com/djm/pipe-to-sh-poc&quot;&gt;full source on Github&lt;/a&gt; &amp;amp; see the &lt;a href=&quot;http://pipe-to-sh-poc.herokuapp.com&quot;&gt;POC hosted on Heroku&lt;/a&gt;; the POC is hosted on a single free Heroku dyno so if it's not up, it's most likely keeled over.&lt;/p&gt;
&lt;p&gt;To quickly test it yourself, simply run the following line at your prompt after first checking the URL of the .sh in your browser. The output for both should be different provided you're not sending a custom user-agent with curl.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;curl -s http://pipe-to-sh-poc.herokuapp.com/install.sh &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; sh
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;A simple solution&lt;/h2&gt;
&lt;p&gt;The most simple solution to this is to get back the transparency lost by viewing the file directly before executing it. This post provides two methods, they both work in similar ways by sitting in the middle after curl and before the sh; if you don't like what you see, you can simply quit your editor in a way that causes a non-zero error return code (e.g in Vim, use &lt;code&gt;:cq&lt;/code&gt; to compiler-quit). Which one you use is up to you, option 1 usually requires an install, option 2 is shorter to type.&lt;/p&gt;
&lt;p&gt;1) &lt;em&gt;Vipe&lt;/em&gt; allows you to run your editor in the middle of a unix pipeline and edit the data that is being piped between programs.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;curl -s http://pipe-to-sh-poc.herokuapp.com/install.sh &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; vipe &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; sh
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Vipe is part of the &lt;code&gt;moreutils&lt;/code&gt; package and is installable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on Mac OSX using homebrew: &lt;code&gt;brew install moreutils&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;on Ubuntu by using apt: &lt;code&gt;apt-get install moreutils&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;by using most other *nix package repositories.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2) &lt;em&gt;A bash function&lt;/em&gt;. Simply place this in your .bashrc or source it from somewhere:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Safer curl | sh&amp;#39;ing&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; curlsh &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;mktemp -t curlsh&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Failed creating file&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    curl -s &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt; &amp;gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Failed to curl file&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$EDITOR&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Editor quit with error code&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    sh &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    rm &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It would then be used like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;curlsh http://pipe-to-sh-poc.herokuapp.com/install.sh
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Your $EDITOR of choice would then be used to view the content that is actually going to be run.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/reveal-rss-feed-url-itunes-podcast/">
    <title type="text">Find out the RSS feed for an iTunes podcast</title>
    <id>urn:uuid:93db990b-9aef-371a-9de0-838786f6c5c4</id>
    <updated>2012-12-11T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/reveal-rss-feed-url-itunes-podcast/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;&lt;em&gt;Update, June 2019&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This post was written in 2012 and detailed a way to find the URL. That way doesn't work anymore, but I built a new way:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discover-apple-podcast-rss-feed--darianmoody.repl.co/&quot;&gt;https://discover-apple-podcast-rss-feed--darianmoody.repl.co/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can read more about this update at the end of this post.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;To cut a long story short: I listen to music podcasts a lot and many of the record labels syndicate their content via Apple's iTunes network. Apple seem to go out of their way to make finding the actual original source podcast feed a complete nuisance to find so I wrote this to grab it for me - now you can use it too..&lt;/p&gt;
&lt;h2&gt;Install the bookmarklet&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;June 2019: This no longer works, please see the update below&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Drag the following link to your browser's bookmarks bar: &lt;a href=&quot;javascript:(function(){var%20newScript=document.createElement('script');newScript.src='https://cdn.jsdelivr.net/gh/djm/uncover-itunes-rss-bookmarklet@master/bookmarklet.js';document.body.appendChild(newScript);})();&quot;&gt;itunes-to-rss&lt;/a&gt;. In later versions of Chrome on Mac, this seems to have stopped working but you can still create your own bookmark and use the URL field to input the copied link (right click, &quot;copy link address&quot;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then visit an appropriate iTunes podcast page, e.g: &lt;a href=&quot;https://itunes.apple.com/us/podcast/critical-podcast/id1257717757?mt=2&quot;&gt;The Critical Music podcast&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click the bookmarklet while on the page to reveal the true RSS podcast URL/content feed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rejoice in the fact you no longer have to load up iTunes. For the time being anyway.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Github&lt;/h2&gt;
&lt;p&gt;The project can be found on Github here: &lt;a href=&quot;https://github.com/djm/uncover-itunes-rss-bookmarklet&quot;&gt;uncover-itunes-rss-bookmarklet&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Update - January 2019&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://rawgit.com/&quot;&gt;Rawgit&lt;/a&gt; has been sunset as of late 2018; many thanks to Ryan Grove for keeping it running for so long. The script still works and thus has been moved to its new home at &lt;a href=&quot;https://www.jsdelivr.com&quot;&gt;jsDelivr&lt;/a&gt;, you will need to update your bookmarks by following the same process as above.&lt;/p&gt;
&lt;h3&gt;Update - June 2019&lt;/h3&gt;
&lt;p&gt;Apple have updated how certain requests are served on their domain and implemented a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot;&gt;CORS policy&lt;/a&gt; which disallows scripts from external sources (such as this bookmarklet); it almost certainly wasn't a deliberate attempt to sabotage this, as it is a decent security best practice these days. That said, multiple people emailed me when the bookmarklet stopped working and they were all asking for a solution to the original problem...so I built this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discover-apple-podcast-rss-feed--darianmoody.repl.co/&quot;&gt;Apple Podcast Feed Finder&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The source code is in Python and is open, simply follow the link in the footer. Essentially, CORS is something the browser &lt;em&gt;should&lt;/em&gt; abide by but as we fire off the requests manually, we can avoid the policy and access the information we need.&lt;/p&gt;
&lt;p&gt;Hope it helps.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/duplicate-urls/">
    <title type="text">Duplicate URLs</title>
    <id>urn:uuid:d461253d-3645-387b-bc5b-8dcc2b8cd994</id>
    <updated>2012-04-21T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/duplicate-urls/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;I was in two minds about writing this post: 1) because it pertains somewhat to SEO and the unfortunate things that surround that world and 2) because it seems obvious to me, but then again I see quite a few sites making the same easily-exploitable mistake.&lt;/p&gt;
&lt;h2&gt;The problem&lt;/h2&gt;
&lt;p&gt;Take this URL, see the slug &quot;juno-breakbeat-podcast&quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://itunes.apple.com/gb/podcast/juno-breakbeat-podcast/id341049395
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now &lt;a href=&quot;http://itunes.apple.com/gb/podcast/juno-breakbeat-podcast/id341049395&quot;&gt;visit&lt;/a&gt; it.&lt;/p&gt;
&lt;p&gt;Now take this modified one, see the slug:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://itunes.apple.com/gb/podcast/CRAP-PODCAST/id341049395
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now &lt;a href=&quot;http://itunes.apple.com/gb/podcast/CRAP-PODCAST/id341049395&quot;&gt;visit&lt;/a&gt; it again.&lt;/p&gt;
&lt;p&gt;The second link should either return a HTTP 404 Not Found or a HTTP 301 Redirect to the canonical URL; definitely not a 200 with exactly the same content as the canonical URL.&lt;/p&gt;
&lt;h2&gt;Why is this a problem?&lt;/h2&gt;
&lt;p&gt;Because aside from the fact a user can stick anything they wish in your URL and share it as if it was the canonical URL, it opens up your site to a punitive SEO attack. Google does not like &lt;a href=&quot;http://support.google.com/webmasters/bin/answer.py?hl=en&amp;amp;answer=66359&quot;&gt;duplicate content&lt;/a&gt;, they're pretty clear about this; imagine someone deliberately linking to your &lt;em&gt;one&lt;/em&gt; page with 10,000 or more different cross-domain indexable links...this will inevitably affect your ranking and could even result in the infamous '&lt;a href=&quot;https://www.google.co.uk/search?sugexp=chrome,mod=0&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;q=google+slap&quot;&gt;google slap&lt;/a&gt;'.&lt;/p&gt;
&lt;p&gt;You might say 'who in their right mind would do that' and I certainly would have had I not worked in and around certain industries; however, through work and other projects I've had the pleasure to meet and discuss this with some very intelligent people that used to do this for a living: black hat SEO is a bigger industry than most people think. Finding quirks/exploits like this in a site's structure is only one tool on the black hat's belt, you're &lt;a href=&quot;http://www.justinparks.com/golden-bullet-backlinks-kill-website-100-backlinks/&quot;&gt;welcome&lt;/a&gt; to &lt;a href=&quot;http://www.blackhatworld.com/&quot;&gt;read&lt;/a&gt; more - it's a dirty world out there.&lt;/p&gt;
&lt;p&gt;This is unlikely to affect large sites such as Apple, due to their number of link banks and therefore authority I would be incredibly surprised if an attack such as this had an affect. But your site is unlikely the size of Apple or reddit (also &lt;a href=&quot;http://www.reddit.com/r/motorcycles/comments/v32na/CAN_TYPE_ANYTHING_I_LIKE_SEEEEE/&quot;&gt;guilty&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;How to fix it&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Check&lt;/strong&gt;. Just check the values you're receiving match the object that you're looking up.&lt;/p&gt;
&lt;p&gt;Given the Django framework, if you're doing this in a view:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;post_detail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_object_or_404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Stop it, and do this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;post_detail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_object_or_404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or if you're other fields aren't indexed and you don't want them to be, it may be better to do this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;post_detail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_object_or_404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slug&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Http404&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you find yourself in a position where for you cannot check these constraints, then to stop abuse you should tell GoogleBot and other crawlers what the actual URL for that page should be. This is done with an element Google invented called the &lt;code&gt;rel=&quot;canonical&quot;&lt;/code&gt; tag and you can &lt;a href=&quot;http://support.google.com/webmasters/bin/answer.py?hl=en&amp;amp;answer=139394&quot;&gt;read more about that&lt;/a&gt; over at Google.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/python-multiple-line-conditions-and-all-builtin/">
    <title type="text">On Python's multiple conditionals</title>
    <id>urn:uuid:6e0ed370-1f7e-3135-b10b-c1762648cc51</id>
    <updated>2012-03-12T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/python-multiple-line-conditions-and-all-builtin/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;This post references the 'problem' caused by multiple conditional statements in Python code; it's a frequent question on Stack Overflow with many questions on the topic. e.g &quot;What's the best way to format multiple if conditions in Python?&quot;&lt;/p&gt;
&lt;p&gt;This is a simple example of the issue:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;wrong&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test2&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test3&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test4&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Do something.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Long lines that not only go against PEP8's 80 char rule but are generally hard to read and messy to play with.&lt;/p&gt;
&lt;p&gt;This post is actually about one solution to this which I frequently see being suggested &lt;strong&gt;&lt;em&gt;with no caveats&lt;/em&gt;&lt;/strong&gt;. and that's the only problem really: it has a pretty big caveat. The solutions in question uses the all() built-in (around since Python 2.5) to take in an iterable of pre-defined conditions; the all built-in then loops through each item and will return &lt;code&gt;False&lt;/code&gt; as soon as one of the items evaluates to &lt;code&gt;False&lt;/code&gt;. Sounds great right? Let's see it in action:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rules&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;wrong&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test3&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test4&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Do something.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Short-circuit evaluation&lt;/h2&gt;
&lt;p&gt;You'd be forgiven for thinking the first and second examples here give the same result: mostly because they do. It's how they go about it which differs. The first will test &lt;code&gt;test == 'wrong'&lt;/code&gt; and return &lt;code&gt;False&lt;/code&gt;, it will never evaluate the other conditionals after the &lt;code&gt;and&lt;/code&gt;. This is called &lt;a href=&quot;http://en.wikipedia.org/wiki/Short-circuit_evaluation&quot;&gt;short-circuit evaluation&lt;/a&gt; and is common in many programming languages as a form of optimisation and as a control structure.&lt;/p&gt;
&lt;p&gt;You probably see where I'm going with this now: the second example will evaluate &lt;strong&gt;all&lt;/strong&gt; the conditionals on instantiation of the list and &lt;em&gt;then&lt;/em&gt; loop through them checking for that boolean status. For the example the speed difference is minuscule and can almost be ignored; however, if your conditions were a bit more resource heavy this could quickly become a problem; it also becomes an issue in cases where a conditional should be required before checking another one - usually this is simply sorted by ordering but as all the conditionals are run with this method, that does not work.&lt;/p&gt;
&lt;p&gt;The same obviously applies to replacing &lt;code&gt;or&lt;/code&gt; statements with the &lt;code&gt;any()&lt;/code&gt; built-in in a similar fashion. I hesitated in putting 'gotcha' in the title because I don't think it really classes as such as it's fairly easy to understand why it acts this way - it's just good to point out to anyone new to this pattern.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/how-to-log-file-django-13-and-above/">
    <title type="text">Logging to file in Django &gt; 1.3</title>
    <id>urn:uuid:ed68a4e7-6589-39ac-b58e-a75586cdb2f6</id>
    <updated>2011-08-04T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/how-to-log-file-django-13-and-above/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;As I'm sure you're well aware, &lt;a href=&quot;https://docs.djangoproject.com/en/dev/releases/1.3/#logging&quot;&gt;Django 1.3 brought with it&lt;/a&gt; a unified way of using the Python &lt;a href=&quot;http://docs.python.org/library/logging.html&quot;&gt;logging module&lt;/a&gt; as part of your Django app/project. Before this existed, everyone had their own way to handle logging so it's great to have a pluggable interface which you can guarantee will be there provided the user is using 1.3+.&lt;/p&gt;
&lt;p&gt;Logging to file is actually rarity for me personally these days due a couple of things: 1) using the StreamHandler to output straight to the &lt;code&gt;runserver&lt;/code&gt; command line output and 2) because of the excellent logging &lt;a href=&quot;https://github.com/dcramer/django-sentry&quot;&gt;Sentry&lt;/a&gt; can provide on production servers where you don't get to see the std output.&lt;/p&gt;
&lt;p&gt;However, sometimes you're still in a situation where you can't use either of these or would just simply like to log to a local file because it's quick and easy. The following code in your &lt;code&gt;settings.py&lt;/code&gt; will help with that:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOGGING&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;version&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;disable_existing_loggers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;handlers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;mail_admins&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ERROR&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.utils.log.AdminEmailHandler&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;stream_to_console&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;DEBUG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;logging.StreamHandler&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;DEBUG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;logging.FileHandler&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;filename&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;here&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random_log.log&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;loggers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.request&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;handlers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;mail_admins&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;stream_to_console&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ERROR&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;propagate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;another_random_logger&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;handlers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;DEBUG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;propagate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, there are two new handlers on top of Django's &lt;code&gt;'mail_admin'&lt;/code&gt; default: &lt;code&gt;'stream_to_console'&lt;/code&gt; will log using Python's &lt;code&gt;StreamHandler&lt;/code&gt; and therefore output to the terminal (when using &lt;code&gt;runserver&lt;/code&gt;); and &lt;code&gt;'file'&lt;/code&gt; will use Python's &lt;code&gt;FileHandler&lt;/code&gt; logger to output to the &lt;code&gt;filename&lt;/code&gt; specified. To get your loggers to use these, their name needs to be included in the &lt;code&gt;'handlers'&lt;/code&gt; list of the individual loggers (also defined above - see &lt;code&gt;'another_random_logger'&lt;/code&gt;). I haven't used them here, but the docs detail full usage of &lt;a href=&quot;https://docs.djangoproject.com/en/dev/topics/logging/#topic-logging-parts-filters&quot;&gt;filters&lt;/a&gt; and &lt;a href=&quot;https://docs.djangoproject.com/en/dev/topics/logging/#topic-logging-parts-formatters&quot;&gt;formatters&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You will notice my &lt;code&gt;filename&lt;/code&gt; entry uses a callable to return the correct value; this is so the filename can be specified relative to the project directory as opposed to hard-coding the path in your settings file. The same function gets uses to work out &lt;code&gt;STATIC/MEDIA_ROOT&lt;/code&gt;'s etc; hard-coding that kind of absolute path in your settings is not advised (but may make sense if you're logging somewhere specific, say &lt;code&gt;/var/log/&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The function is below for anyone wishing to use that tactic:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;here&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                               &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;realpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vm&quot;&gt;__file__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Given the file you run this is located in&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# /home/djm/projects/some_project/ this&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# will give you the following:&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;here&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;some_log.log&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;home&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;djm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;projects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some_project&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some_log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;here&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;..&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;..&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;some_log.log&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;home&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;djm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some_log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/using-django-auth-ldap-active-directory-ldaps/">
    <title type="text">Django Auth with an LDAP Active Directory</title>
    <id>urn:uuid:85b931bb-aa25-377d-b63c-a110708082a2</id>
    <updated>2011-07-28T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/using-django-auth-ldap-active-directory-ldaps/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;This is another one of those &lt;em&gt;&quot;I'm putting this here in case I ever have to do it again&quot;&lt;/em&gt; posts because I really hope I never have to. The aim of this post is to get &lt;a href=&quot;http://packages.python.org/django-auth-ldap/&quot;&gt;django_auth_ldap&lt;/a&gt; and therefore the &lt;a href=&quot;http://www.python-ldap.org/&quot;&gt;python-ldap&lt;/a&gt; library working via LDAPS (LDAP over SSL) to port 636. A few internal things we're building at &lt;a href=&quot;http://theteam.co.uk/&quot;&gt;theTeam&lt;/a&gt; involve interfacing with the group's Active Directory installation to provide such features as single sign-on and auto-filling out of profiles based on data stored with AD.&lt;/p&gt;
&lt;p&gt;As with any authentication system, passwords should not be sent unencrypted (especially as plain text as LDAP does normally); thus explaining the decision to do this over an encrypted SSL tunnel. This guide will give a few hints as to how we got &lt;em&gt;the actual SSL connection&lt;/em&gt; working on an Ubuntu 10.04 LTS server; we assume you have already installed the necessary requirements.&lt;/p&gt;
&lt;h2&gt;First off, get your PEMs&lt;/h2&gt;
&lt;p&gt;These are your root certificates, the ones you must &quot;trust&quot; to have a valid SSL encrypted connection. I would love to help more on how to get these from your Active Directory setup but I was simply provided them by the IT department so I'm no help there I'm afraid.&lt;/p&gt;
&lt;p&gt;However, as we're on Ubuntu and using OpenSSL the certificates will work best in PEM format. If you have your CA cert in a different format (such as DER, PKCS#7/P7B or PKCS#12/PFX) then you will need to convert them to PEM to follow this guide. This can be done with CLI tools or just a &lt;a href=&quot;https://confirm.globessl.com/convert.html&quot;&gt;simple website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your key will end up as a raw text file that starts with the line:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-----BEGIN CERTIFICATE-----&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;..followed by your alpha-numerical key and ends with the line..&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-----END CERTIFICATE-----&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If this is not the case, something has gone wrong.&lt;/p&gt;
&lt;h2&gt;Trusting the certificate&lt;/h2&gt;
&lt;p&gt;First of all we need to tell your LDAP installation where to look for trusted CA certificates. To do this, you need to edit the global ldap.conf and set the &lt;code&gt;TLS_CACERT&lt;/code&gt; variable. We'll be using nano for it's simplicity here, but you can use whatever you like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo nano /etc/ldap/ldap.conf
&lt;span class=&quot;c1&quot;&gt;# Add the following line, or edit the current TLS_CACERT entry.&lt;/span&gt;
TLS_CACERT /etc/ssl/certs/ca-certificates.crt
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have it looking for CA certificates we need to add our root cert to that pile. You will need to edit the &lt;code&gt;ca-certificates.crt&lt;/code&gt; file and append your key you found earlier to it. That includes &lt;em&gt;everything&lt;/em&gt; - the beginning and end lines are absolutely key to this working. Paste it at the bottom of this file:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo nano /etc/ssl/certs/ca-certificates.crt
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Testing the connection on the cmd line&lt;/h2&gt;
&lt;p&gt;If you don't have &lt;code&gt;ldapsearch&lt;/code&gt; on your cmd line already then you will need to install the &lt;code&gt;ldap-utils&lt;/code&gt; package:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo apt-get install ldap-utils
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This binary allows us to test our LDAPS connection without delving into python-ldap (although to be honest, you may prefer to do that straight away).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ldapsearch -H ldaps://ldap-x.companygroup.local:636 -D &lt;span class=&quot;s2&quot;&gt;&amp;quot;CN=Something LDAP,OU=Random Group,DC=companygroup,DC=local&amp;quot;&lt;/span&gt; -w &lt;span class=&quot;s2&quot;&gt;&amp;quot;p4ssw0rd&amp;quot;&lt;/span&gt; -v -d &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For more information than I'm about to give, check the &lt;a href=&quot;http://linux.die.net/man/1/ldapsearch&quot;&gt;ldapsearch man page&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-H&lt;/code&gt; is the full URI to the LDAP server, in our case here using &lt;code&gt;ldaps://&lt;/code&gt; and port &lt;code&gt;636&lt;/code&gt; (default for &lt;code&gt;ldaps&lt;/code&gt;). &lt;/li&gt;
&lt;li&gt;&lt;code&gt;-D&lt;/code&gt; is the 'distinguised name' that you need to start the first auth bind (binddn).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-w&lt;/code&gt; is the password for the binddn. Use single qoutes if you have any exclamation marks or other bash key characters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; is for verbose mode and &lt;code&gt;-d 1&lt;/code&gt; set the debug level low; both so we know more about what's happening.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hit enter, and all things going well you should have a valid encrypted connection to the LDAP server. You'll see something like below if it went OK. If not, read on:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# numResponses: 1
ldap_free_connection 1 1
ldap_send_unbind
ber_flush2: 7 bytes to sd 3
ldap_free_connection: actually freed
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Troubleshooting the connection&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ldap_bind: Invalid credentials (49)
additional info: 80090308: LdapErr: DSID-0C0903AA, comment: AcceptSecurityContext error, data 52e, v1772
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you're seeing the above, semi-congrats because at least you've connected fine. You have however failed the first bind authentication and will therefore need to check your 'Distinguished Name' (DN) and bind password (-D &amp;amp; -w flags).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ldap_connect_to_host: Trying x.x.x.x:636
ldap_pvt_connect: fd: 3 tm: -1 async: 0
TLS: hostname (ldap-x) does not match common name in certificate (ldap-x.companygroup.local).
ldap_err2string
ldap_sasl_bind(SIMPLE): Can&amp;#39;t contact LDAP server (-1)
additional info: TLS: hostname does not match CN in peer certificate
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you're getting the above error, the hostname you are using for your connection does not match the common name in the certificate. It should tell you what it should it match and so this is simply a case of editing your /etc/hosts file to point to the right location with that hostname. For example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;127&lt;/span&gt;.0.0.1       localhost
x.x.x.x         ldap-x.companygroup.local &lt;span class=&quot;c1&quot;&gt;# Where x.x.x.x is the server IP.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Applying this all to django-auth-ldap&lt;/h2&gt;
&lt;p&gt;So we've got this far, this is how you convert that to working with &lt;a href=&quot;http://packages.python.org/django-auth-ldap/&quot;&gt;django-auth-ldap&lt;/a&gt; setup. The best way to show this is to simple show the relevant settings file for the project; again, we assume you already have django-auth-ldap setup in your Django project (hint: docs).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# For this, you want to be using the -H flag setting you used above.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;AUTH_LDAP_SERVER_URI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ldaps://ldap-x.companygroup.local:636&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# This is the distinguished name (DN), the -D flag above.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;AUTH_LDAP_BIND_DN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Something LDAP,OU=Random Group,DC=companygroup,DC=local&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# The bing password, the -w flag above.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;AUTH_LDAP_BIND_PASSWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;p4ssw0rd&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# We do lookups on a user by email so this may not work for you&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# but you should get the idea. &lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;AUTH_LDAP_USER_SEARCH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LDAPSearch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;DC=companygroup,DC=local&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ldap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SCOPE_SUBTREE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;(&amp;amp;(objectClass=user)(mail=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(user)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;))&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# The following OPT_REFERRALS option is CRUCIAL for getting this &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# working with MS Active Directory it seems, unfortunately I have&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# no idea why; it just hangs if you don&amp;#39;t set it to 0 for us.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;AUTH_LDAP_CONNECTION_OPTIONS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ldap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OPT_DEBUG_LEVEL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ldap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OPT_REFERRALS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And there you have it, if all went well you should now have a fully working LDAPS Django Authentication Backend.&lt;/p&gt;
&lt;p&gt;If you're having issues with &lt;code&gt;django-auth-ldap&lt;/code&gt;, you'll want to plug into it's logging abilities so that you can debug the connection properly. If you're running Django 1.3 this is a piece of cake with the new &lt;code&gt;dictConfig&lt;/code&gt; logging stuff in &lt;code&gt;settings.py&lt;/code&gt;. Basically just copy this into your &lt;code&gt;settings.py&lt;/code&gt; and you'll retain the default Django loggers + the new &lt;code&gt;django_auth_ldap&lt;/code&gt; one.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOGGING&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;version&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;disable_existing_loggers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;handlers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;mail_admins&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ERROR&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.utils.log.AdminEmailHandler&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;stream_to_console&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;DEBUG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;logging.StreamHandler&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;loggers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.request&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;handlers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;mail_admins&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ERROR&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;propagate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;django_auth_ldap&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;handlers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;stream_to_console&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;level&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;DEBUG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;propagate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/wordpress-nginx-reverse-proxy-caching-setup/">
    <title type="text">NGINX as a reverse caching proxy: part 2</title>
    <id>urn:uuid:0ba50de5-32a0-3244-be83-c8ceae9f617f</id>
    <updated>2011-04-07T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/wordpress-nginx-reverse-proxy-caching-setup/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;Having previously written about the success of using &lt;a href=&quot;../../fauna-flora-nginx-reverse-proxy-results/&quot;&gt;nginx to reverse cache infront of Apache&lt;/a&gt;, I thought I'd follow up with a post on exactly how to tailor that to Wordpress specifically.&lt;/p&gt;
&lt;h2&gt;Part 2 of 2&lt;/h2&gt;
&lt;p&gt;The entire production nginx configuration is &lt;strong&gt;available in one chunk at the end of this post&lt;/strong&gt; but let's go through it bit-by-bit and explain away. This configuration is dumped directly from the main nginx.conf so that it contains everything - this will only work directly in situations where you are running one site of an instance. If you wish to host multiple sites off one server, that is easily possible with a little editing of the nginx and apache config files but that is left as a task to the reader (read about includes).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;apache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;apache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;worker_processes&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;error_log&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/log/nginx/error.log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;events&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;worker_connections&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first line is the user and group you wish to run nginx under, in this case 'apache' and 'apache' due to it being on a Plesk-based machine. This also sets the location of the error log and from this we can calculate the theoretical maximum amount of connections we can support (worker_processes * worker_connections) - in this case ~4000. The worker_processes setting should ideally be equal to the amount of processor cores you have available to you (see the output of &lt;code&gt;cat /proc/cpuinfo | grep processor&lt;/code&gt;).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/nginx/mime.types&lt;/span&gt;;
&lt;span class=&quot;k&quot;&gt;default_type&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;application/octet-stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Defines the cache log format, cache log location&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# and the main access log location.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;***&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$time_local&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$upstream_cache_status&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;Cache-Control:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$upstream_http_cache_control&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;Expires:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$upstream_http_expires&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&amp;quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$status&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$http_user_agent&amp;quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;Args:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$args&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;Wordpress&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Auth&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Cookie:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/log/nginx/cache.log&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/log/nginx/access.log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first line here defines some mime-types and defaults which should exist in most nginx configurations; the following log_format setting funnily enough sets the format for the log: we include a lot of extra information here to make it easier for us to debug later (such as whether the Wordpress Auth cookie has been set, the browser user-agent and request status code etc). Most of the variables used here are part of the global nginx set available to the config files but some (such as the $wordpress_auth one) are custom set later within the file. '&lt;em&gt;cache&lt;/em&gt;' is the name given to this log format so you can use it in the next lines.&lt;/p&gt;
&lt;p&gt;Here we set 2 different access logs, one with the log format we just specified (&lt;em&gt;cache&lt;/em&gt;) and one with the default access log format; this is purely to make debugging easier and is not necessary (although I would advise having at least one access log).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Proxy cache and temp configuration.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;proxy_cache_path&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/www/nginx_cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;levels=1:2&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;keys_zone=main:10m&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;max_size=1g&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;inactive=30m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;proxy_temp_path&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/www/nginx_temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This section requires the pre-requisite caching module I went through earlier; the &lt;a href=&quot;http://wiki.nginx.org/HttpProxyModule#proxy_cache_path&quot;&gt;proxy_cache_path&lt;/a&gt; and &lt;a href=&quot;http://wiki.nginx.org/HttpProxyModule#proxy_temp_path&quot;&gt;proxy_temp_path&lt;/a&gt; are both attached to the &lt;a href=&quot;http://wiki.nginx.org/HttpProxyModule&quot;&gt;HttpProxyModule&lt;/a&gt; we installed earlier which handles the caching of requests.&lt;/p&gt;
&lt;p&gt;Cached request data is stored as simple files where the filename is an MD5 hash of the proxied URL. The proxy_cache_path setting sets the absolute file path to the storage location of each cache while also providing deeper options involving key zones, levels, max cache size and cache invalidation options. A quick explanation of those:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Levels&lt;/strong&gt; - The &lt;em&gt;levels&lt;/em&gt; argument sets the number of subdirectories the cache will delve into it. I'm going to be honest and say I don't know why this is a setting - there's lots of misinformation about and I couldn't find anything decent on it (the docs do not explain it well enough currently). Get in touch if you know and I can update this but for now 1:2 caches the files two directories down and seems to be what most people do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Key Zone&lt;/strong&gt; - This is the name and size of the shared memory allocation for this cache (in memory, not on disk cache). You name it so you can use it in the location directive later and the size is obvious; here we give it 30mb which is actually way more than adequate for a site of this size.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache Size&lt;/strong&gt; - This is the maximum size (&lt;em&gt;max_size&lt;/em&gt;) your cache will take up &lt;em&gt;on disk&lt;/em&gt; before the &lt;del&gt;oldest&lt;/del&gt; least-recently used cached requests start being cleaned up to make room for the new ones.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache Invalidation&lt;/strong&gt; - The setting here is called &lt;em&gt;inactive&lt;/em&gt; and provides the amount of time a cached request should remain 'valid'. This can be set to &lt;em&gt;30m&lt;/em&gt; (30 minutes), &lt;em&gt;2h&lt;/em&gt; (2 hours), &lt;em&gt;3d&lt;/em&gt; (3 days) etc, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Gzip Configuration.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;gzip_disable&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;msie6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;gzip_static&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;gzip_comp_level&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;gzip_proxied&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;gzip_types&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;text/plain&lt;/span&gt;
           &lt;span class=&quot;s&quot;&gt;text/css&lt;/span&gt;
           &lt;span class=&quot;s&quot;&gt;application/x-javascript&lt;/span&gt;
           &lt;span class=&quot;s&quot;&gt;text/xml&lt;/span&gt;
           &lt;span class=&quot;s&quot;&gt;application/xml&lt;/span&gt;
           &lt;span class=&quot;s&quot;&gt;application/xml+rss&lt;/span&gt;
           &lt;span class=&quot;s&quot;&gt;text/javascript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we have some fun with enabling gzip. To go through it quickly line by line: turn compression on; disable compressed serving to IE6 which can't handle it well; compress static media before serving; set the compression level (tradeoffs between bandwidth saved and speed); compress responses returned from proxied material (in this case our response from Apache); and then a list of mimetypes that we will be compressing (mostly plain text here as you can see).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;upstream&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;backend&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Defines backends.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Extracting here makes it easier to load balance&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# in the future. Needs to be specific IP as Plesk&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# doesn&amp;#39;t have Apache listening on localhost.&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;ip_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xxx.xxx.xxx.xxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;81&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# IP goes here.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Defining an upstream handler called &lt;em&gt;backend&lt;/em&gt; allows us to proxy pass to this later easily and also makes it easier for us to add more backend servers in the future. Plesk doesn't have Apache serving on anything but specific IPs so in this case we specify the exact one but &lt;code&gt;localhost:81&lt;/code&gt; or &lt;code&gt;127.0.0.1:81&lt;/code&gt; should work in most cases (provided you have Apache set to run on Port 81 obviously).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xxx.xxx.xxx.xxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# IP goes here..&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;fauna-flora.org&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.fauna-flora.org&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;xxx.xxx.xxx.xxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# IP could go here.&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Set proxy headers for the passthrough&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Host&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Real-IP&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$remote_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Forwarded-For&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Let the Set-Cookie header through.&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;proxy_pass_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Set-Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;listen&lt;/em&gt; tells the nginx to listen on a certain IP address on a certain port (this case 80, the default one for HTTP) for all incoming connections. The &lt;em&gt;server_name&lt;/em&gt; direction is a mixture of ServerName and ServerAlias directions from Apache; you can specify as many domains, wildcards or IPs here and as soon as the HTTP_HOST header of an incoming request matches an alias it will use this configuration to serve the page.&lt;/p&gt;
&lt;p&gt;As NGINX is accepting the incoming connection to the server and passing it to Apache interally, we need to make sure certain headers from the original request 'get through' to Apache; this means specifically setting them via the proxy_set_header method which accepts the name of the header to set as it's first parameter and the value to use as it's second. Here it sets the relevant headers so that Apache can see who the connection originally came from and what it was looking for (so that it can pick the right Apache .conf to use for serving).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;## domain.org -&amp;gt; www.domin.org (301 - Permanent)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;^([a-z0-9]+\.org)&lt;/span&gt;$&lt;span class=&quot;s&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$host_with_www&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;rewrite&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;^(.*)&lt;/span&gt;$
        &lt;span class=&quot;s&quot;&gt;http://&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host_with_www$1&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;permanent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we simply redirect the non-www version of the domain to the www version - this is mainly for SEO so that we don't get a duplicate content hit from Google (as they would technically be two different domains serving the same content).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Max upload size: make sure this matches the php.ini in .htaccess&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;client_max_body_size&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Catch the wordpress cookies.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Must be set to blank first for when they don&amp;#39;t exist.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$http_cookie&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;wordpress_logged_in_[^=]*=([^%]+)%7C&amp;quot;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;wordpress_logged_in_&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We set the &lt;em&gt;client_max_body_size&lt;/em&gt; to match whatever you have the post_max_size &amp;amp; upload_max_filesize in your php.ini set to; this allows large files to be uploaded in the admin without nginx timing out.&lt;/p&gt;
&lt;p&gt;The next bit sets a variable called $wordpress_auth if the wordpress_logged_in cookie is set (meaning a user is logged in); this allows us to conditionally cache later in the location directive.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Set the proxy cache key&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cache_key&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scheme$host$uri$is_args$args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here the cache key is set, this is the string which will end up getting MD5'd and saved on disk as the filename. Here it is made up of the scheme (http/https), the hostname, the $uri - which is the full post-rewrite path without query string, and $is_args which provides the ? and $args which provides the full query string. This allows us to be pretty specific in the page requests we cache.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;^/(wp-content|wp-includes)/(.*)\.(gif|jpg|jpeg|png|ico|bmp|js|css|pdf|doc)&lt;/span&gt;$ &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/www/vhosts/fauna-flora.org/httpdocs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All media (including uploads) is under wp-content/ or wp-includes/ so instead of caching the response from Apache, we just use nginx to serve directly from there for any media paths; this saves Apache serving any static media at all which greatly helps when trying to optimise Apache to serve dynamic requests better.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Don&amp;#39;t cache these pages.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;^/(wp-admin|wp-login.php)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://backend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The problem with caching all responses is that there are some we definitely do not want to cache, such as the admin and the login responses. Here we exclude both of those from the location directive below by defining them first and we pass them directly through to our upstream Apache without doing any caching.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://backend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_cache_key&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cache_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_cache_valid&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 200, 301 and 302 will be cached.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Fallback to stale cache on certain errors.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# 503 is deliberately missing, if we&amp;#39;re down for maintenance&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# we want the page to display.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_cache_use_stale&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;error&lt;/span&gt;
                              &lt;span class=&quot;s&quot;&gt;timeout&lt;/span&gt;
                              &lt;span class=&quot;s&quot;&gt;invalid_header&lt;/span&gt;
                              &lt;span class=&quot;s&quot;&gt;http_500&lt;/span&gt;
                              &lt;span class=&quot;s&quot;&gt;http_502&lt;/span&gt;
                              &lt;span class=&quot;s&quot;&gt;http_504&lt;/span&gt;
                              &lt;span class=&quot;s&quot;&gt;http_404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# 2 rules to dedicate the no caching rule for logged in users.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_cache_bypass&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Do not cache the response.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_no_cache&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Do not serve response from cache.&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the final directive! This one matches all remaining paths that we haven't already caught and caches their response. We'll go through each bit individually:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;proxy_pass&lt;/strong&gt;: This allows us to pass the request through to our upstream Apache.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;proxy_cache&lt;/strong&gt;: This tells nginx which named key_zone cache to use for all requests hitting this location directive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;proxy_cache_key&lt;/strong&gt;: Sets the cache key to use in the MD5 calc; we set this up above.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;proxy_cache_valid&lt;/strong&gt;: Without specifying certain status code responses here (200,404 etc) this provides the default amount of time that the cache's remain valid. Don't set this longer than the inactive parameter in your proxy_cache_path as it will have no effect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;proxy_cache_use_stale&lt;/strong&gt;: Sets when we should fall back to stale (expired) cache if it exists. Here we fall back if required when there has been: an error; an invalid header sent; and for the HTTP status codes 500, 502, 504, and 404. We deliberately don't put 503 (the maintenance code) here as we wish to display that page when we are down for scheduled maintenance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://wiki.nginx.org/HttpProxyModule#proxy_cache_bypass&quot;&gt;proxy_cache_bypass&lt;/a&gt;&lt;/strong&gt;: We set this variable earlier, it basically is true if the Wordpress auth cookie is set, and therefore we do not cache. See the link for a better explanation from the docs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://wiki.nginx.org/HttpProxyModule#proxy_no_cache&quot;&gt;proxy_no_cache&lt;/a&gt;&lt;/strong&gt;: Explained better in the docs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that's about it, the file is left below in it's entirety:&lt;/p&gt;
&lt;h2&gt;The entire file for your pasting desires.&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;apache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;apache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;worker_processes&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;error_log&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/log/nginx/error.log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;events&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;worker_connections&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;http&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/etc/nginx/mime.types&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;default_type&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;application/octet-stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Defines the cache log format, cache log location&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# and the main access log location.&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;***&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$time_local&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$upstream_cache_status&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;Cache-Control:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$upstream_http_cache_control&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;Expires:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$upstream_http_expires&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&amp;quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$status&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$http_user_agent&amp;quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;Args:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$args&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;Wordpress&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Auth&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Cookie:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/log/nginx/cache.log&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/log/nginx/access.log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Proxy cache and temp configuration.&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;proxy_cache_path&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/www/nginx_cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;levels=1:2&lt;/span&gt;
                     &lt;span class=&quot;s&quot;&gt;keys_zone=main:10m&lt;/span&gt;
                     &lt;span class=&quot;s&quot;&gt;max_size=1g&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;inactive=30m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;proxy_temp_path&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/www/nginx_temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Gzip Configuration.&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;gzip_disable&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;msie6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;gzip_static&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;gzip_comp_level&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;gzip_proxied&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;gzip_types&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;text/plain&lt;/span&gt;
               &lt;span class=&quot;s&quot;&gt;text/css&lt;/span&gt;
               &lt;span class=&quot;s&quot;&gt;application/x-javascript&lt;/span&gt;
               &lt;span class=&quot;s&quot;&gt;text/xml&lt;/span&gt;
               &lt;span class=&quot;s&quot;&gt;application/xml&lt;/span&gt;
               &lt;span class=&quot;s&quot;&gt;application/xml+rss&lt;/span&gt;
               &lt;span class=&quot;s&quot;&gt;text/javascript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;upstream&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;backend&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Defines backends.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Extracting here makes it easier to load balance&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# in the future. Needs to be specific IP as Plesk&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# doesn&amp;#39;t have Apache listening on localhost.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;ip_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xxx.xxx.xxx.xxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;81&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# IP goes here.&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xxx.xxx.xxx.xxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# IP goes here.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;fauna-flora.org&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.fauna-flora.org&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;xxx.xxx.xxx.xxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# IP could go here.&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Set proxy headers for the passthrough&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Host&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Real-IP&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$remote_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Forwarded-For&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Let the Set-Cookie header through.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_pass_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Set-Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;## domain.org -&amp;gt; www.domin.org (301 - Permanent)&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;^([a-z0-9]+\.org)&lt;/span&gt;$&lt;span class=&quot;s&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$host_with_www&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;rewrite&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;^(.*)&lt;/span&gt;$
            &lt;span class=&quot;s&quot;&gt;http://&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host_with_www$1&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;permanent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Max upload size: make sure this matches the php.ini in .htaccess&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;client_max_body_size&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Catch the wordpress cookies.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Must be set to blank first for when they don&amp;#39;t exist.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$http_cookie&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;wordpress_logged_in_[^=]*=([^%]+)%7C&amp;quot;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;wordpress_logged_in_&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Set the proxy cache key&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cache_key&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scheme$host$uri$is_args$args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# All media (including uploaded) is under wp-content/ so&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# instead of caching the response from apache, we&amp;#39;re just&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# going to use nginx to serve directly from there.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;^/(wp-content|wp-includes)/(.*)\.(gif|jpg|jpeg|png|ico|bmp|js|css|pdf|doc)&lt;/span&gt;$ &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/www/vhosts/fauna-flora.org/httpdocs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Don&amp;#39;t cache these pages.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;^/(wp-admin|wp-login.php)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://backend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://backend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_cache_key&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cache_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_cache_valid&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 200, 301 and 302 will be cached.&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Fallback to stale cache on certain errors.&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# 503 is deliberately missing, if we&amp;#39;re down for maintenance&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# we want the page to display.&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_cache_use_stale&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;error&lt;/span&gt;
                                  &lt;span class=&quot;s&quot;&gt;timeout&lt;/span&gt;
                                  &lt;span class=&quot;s&quot;&gt;invalid_header&lt;/span&gt;
                                  &lt;span class=&quot;s&quot;&gt;http_500&lt;/span&gt;
                                  &lt;span class=&quot;s&quot;&gt;http_502&lt;/span&gt;
                                  &lt;span class=&quot;s&quot;&gt;http_504&lt;/span&gt;
                                  &lt;span class=&quot;s&quot;&gt;http_404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# 2 rules to dedicate the no caching rule for logged in users.&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_cache_bypass&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Do not serve response from cache.&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_no_cache&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wordpress_auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Do not cache the response.&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Cache purge URL - works in tandem with WP plugin.&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/purge(/.*)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_cache_purge&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$scheme://$host$1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# End server&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# End http&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Edit - May 2017&lt;/em&gt;: with extra thanks to &lt;a href=&quot;https://twitter.com/@pcv57&quot;&gt;@pcv57&lt;/a&gt; for a correction on my proxy_cache_bypass &amp;amp; proxy_no_cache comments, which were the wrong way around for 6 years!&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/fauna-flora-nginx-reverse-proxy-results/">
    <title type="text">NGINX as a reverse caching proxy: part 1</title>
    <id>urn:uuid:94d35a86-f64e-310f-a354-b113ef660f4c</id>
    <updated>2011-04-03T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/fauna-flora-nginx-reverse-proxy-results/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;This is a 2 part article on using Nginx as a reverse proxy in-front of Apache (running Wordpress) while caching all responses; first we show the results and then &lt;a href=&quot;../../wordpress-nginx-reverse-proxy-caching-setup/&quot;&gt;how to replicate them in Part Two&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Part 1 of 2&lt;/h2&gt;
&lt;p&gt;On the 1st November 2010, &lt;a href=&quot;http://www.fauna-flora.org&quot;&gt;Fauna &amp;amp; Flora International&lt;/a&gt; relaunched their new content-managed website design built by &lt;a href=&quot;http://blackrabb.it&quot;&gt;blackrabb.it&lt;/a&gt; and &lt;a href=&quot;http://www.abstraktion.co.uk&quot;&gt;abstraktion&lt;/a&gt; (namely Pete Coles &amp;amp; Chris Garrett). Fauna &amp;amp; Flora are one of the largest charities caring for both plants and animals and as such have a rather large list of celebrities as their Vice Presidents: Stephen Fry, Sir David Attenborough &amp;amp; Dame Judi Dench to name a few. As many of you may know, Stephen Fry is avid twitter user with a rather formidable following of approximately 2 million other twitter users and this rises by the day.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../posts/fauna-flora-nginx-reverse-proxy-results/fauna-flora.png&quot; alt=&quot;Fauna &amp;amp; Flora&quot;&gt;&lt;/p&gt;
&lt;p&gt;See where I'm going with this yet? While the server is way more than capable of happily serving up the site to Fauna &amp;amp; Flora's average daily traffic levels - the sporadic and intense spikes caused by the likes of &lt;a href=&quot;http://twitter.com/stephenfry/status/13773345592&quot;&gt;Stephen Fry's twitter crew&lt;/a&gt; have and continue to wreak havoc on an unexpected basis. &lt;a href=&quot;http://www.petercolesdc.com&quot;&gt;Pete&lt;/a&gt; brought me in at the end of the build to try and get a solution in place for the launch of the new project.&lt;/p&gt;
&lt;h2&gt;Before (a.k.a the untimely death of Apache)&lt;/h2&gt;
&lt;p&gt;The first thing that should always take place before any kind of optimisation is to snapshot and record what it was like before - this applies to many things but particularly in the case of load optimisation; how else do you measure your success?&lt;/p&gt;
&lt;p&gt;With this in mind, and with Apache set up with &lt;a href=&quot;http://www.parallels.com/uk/products/plesk/&quot;&gt;Plesk&lt;/a&gt; and &lt;a href=&quot;http://mediatemple.net/&quot;&gt;MediaTemple&lt;/a&gt;'s default configuration, I ran a load test on the server which at this point had no other traffic visiting it as it was on a development address. The load test was provided by the kind people at &lt;a href=&quot;http://loadimpact.com/&quot;&gt;LoadImpact&lt;/a&gt; and the results can be seen in graph form below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../posts/fauna-flora-nginx-reverse-proxy-results/fauna-flora-pre-nginx.png&quot; alt=&quot;Pre NGINX&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;via &lt;a href=&quot;http://loadimpact.com/&quot;&gt;LoadImpact&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Put simply? Abyssal. But remember, this is a straight out-of-the-box setup.&lt;/p&gt;
&lt;p&gt;As you can see the initial page response times even without any heavy load are incredibly slow; some may say this is down to Wordpress but as we're simply serving generated HTML that doesn't change frequently, there really is no excuse for such performance. The test ran for 13 minutes after which the response time peaked heavily and LoadImpact cancelled the rest of the test so as not to take the site down. During those 13 minutes, Apache managed to serve up close to 13,000 page requests and just about handle ~25 simultaneous clients; however, we needed more.&lt;/p&gt;
&lt;p&gt;The next step was either to optimise the out-of-the-box Apache configuration or, as we chose, to change the service architecture to let another HTTP server handle the connections and hopefully caching.&lt;/p&gt;
&lt;h2&gt;After (with nginx set up to reverse proxy)&lt;/h2&gt;
&lt;p&gt;After about an hour of configuring nginx and X hours of getting Plesk to run Apache on port 81 instead of 80 (it absolutely loves rewriting over the hard work you put into changing the configs) we were set up with nginx sitting on port 80 talking to Apache on localhost:81. This way nginx handles all the connections for both dynamic and static media and only talks to Apache when it needs data to fill the current request (any dynamic pages). With caching enabled it will check the cache first to check if there is a non-expired key to use as the response, and thus we cut down the actual amount of connections hitting Apache considerably. There will be more talk of that in the more technical post later; for now, check the results:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../posts/fauna-flora-nginx-reverse-proxy-results/fauna-flora-post-nginx.png&quot; alt=&quot;Post NGINX&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;via &lt;a href=&quot;http://loadimpact.com/&quot;&gt;LoadImpact&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first thing to note is the vastly reduced access times (considering LoadImpact are in Stockholm and MediaTemple are state-side), down to a constant 3.5s instead of the 5-6s we had before. The second thing to note, and probably the first you thing you realise, is the flatness of the graph - extra clients made exactly &quot;sod all difference&quot; (that's the scientific term). It managed to handle 50 simultaneous clients without the actual server load (monitored via SSH) even rising above 0.1; this far surpasses Apache which died after about 25 but more importantly, the flatness here and the load via SSH show that it can in fact handle handle far more than that - how much more I would love to know but as this was for a charity I couldn't afford the outlay of paying more to LoadImpact. Overall, it handled over 52,000 requests in 15 minutes which is a much better 60-ish requests per second without even shedding so much as a tear.&lt;/p&gt;
&lt;h2&gt;The Nginx setup&lt;/h2&gt;
&lt;p&gt;This post would be incredibly long had it have entailed that also, so I've split the more technical specs of the module and configuration required to get nginx &lt;a href=&quot;../../posts/wordpress-nginx-reverse-proxy-caching-setup/&quot;&gt;reverse proxy-ing infront of Apache into a separate post&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/django-contextual/">
    <title type="text">Introducing django-contextual</title>
    <id>urn:uuid:450fa8d0-cd84-3cd4-8ef8-a39038136305</id>
    <updated>2011-02-21T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/django-contextual/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;div class=&quot;admonition admonition-warning&quot;&gt;&lt;p&gt;&lt;strong&gt;DEPRECATED&lt;/strong&gt;: This project will remain on Github but development is no longer active and indeed, has not been for a considerable time (2011, circa Django 1.2). If you wish to do similar nowadays, this is definitely not how you should go about it. Please take a look at the new TemplateResponse objects instead.&lt;/p&gt;&lt;/div&gt;&lt;p&gt;When working with SEO agencies you tend to get a few requests related to analytics and tracking; having said that, anyone that has actually worked with an SEO agency is probably screaming that that's a savage understatement. In a world where every conversion counts, the metrics need to be spot on so that the SEO agency can justify the amount they charge the client. Unfortunately for developers - this means a lot of time taken away from perhaps more exciting tasks and I hope this app release makes it easier in at least a few use cases (especially off-line tracking).&lt;/p&gt;
&lt;p&gt;You can check out &lt;a href=&quot;https://github.com/djm/django-contextual&quot;&gt;django-contextual on Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;General Use Case&lt;/h2&gt;
&lt;p&gt;Many companies still need to track off-line sales/requests so they can better judge if their campaigns are working. A common way to do this is to have a bank of phone numbers (companies we work with have over 500+ for the same call centre) with each one being used when the user came from a specific destination or action. Therefore developers are left with the requirement of flipping out phone numbers on a given website based upon the request variables (such as &lt;code&gt;HTTP_REFERER&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This app makes that a whole load simpler: first you add in a tag called &lt;code&gt;[PHONE]&lt;/code&gt; and you can place this within your templates &lt;em&gt;or&lt;/em&gt; any data that that returns as plain text (such as a news post in the database for example). As long as the tag is in the plain text response sent back to the client it will get replaced either by replacement data from a matching request test &lt;em&gt;or&lt;/em&gt; by the default you provide when settings the tag up.&lt;/p&gt;
&lt;p&gt;At its raw level it can handle the replacement of ANY tag (&lt;code&gt;[PHONE]&lt;/code&gt; etc) in the plain text response, the contextual tests (and associated models) work in a pluggable way such that only those that are required are actually 'installed'. These tests return matches when passed the standard Django request object or None if they do not find a match. An example of a match could be matching hostnames, matching referrers, query strings which fit a pattern etc, etc - this all depends on the test used. The dynamic loading also comes with the great advantage that you can write your own contextual tests to cover cases which the standard built-in tests do not cover and &quot;install&quot; them simply by including their path in the &lt;code&gt;CONTEXTUAL_TESTS&lt;/code&gt; setting.&lt;/p&gt;
&lt;h2&gt;How it works&lt;/h2&gt;
&lt;p&gt;This isn't an explanation of how to install or a full run down of the built in tests; that will be coming with the docs shortly (hopefully) but for now you can read the README on Github. This is the general gist of the flow.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONTEXTUAL_TESTS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;contextual.contextual_tests.RefererTest&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;contextual.contextual_tests.QueryStringTest&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;get_key&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;s&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;contextual.contextual_tests.HostnameTest&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Given the project-level setting above &lt;code&gt;(path_to_test_class, priority, config dictionary)&lt;/code&gt;, django-contextual on first load will dynamically instantiate all the tests and make them available on the app's module as &lt;code&gt;LOADED_TESTS&lt;/code&gt;. The priorities are required because we can only find one match on the test (we can't and don't want to replace the tags multiple times). Due to this the tests have to be carried out sequentially and so the priority allows us to place the instantiated tests into the &lt;code&gt;LOADED_TESTS&lt;/code&gt; list in the order that they should be run against. The 3rd parameter per test setting is a configuration dictionary to be passed on instantiation - whether this is required or not is dependent on the test.&lt;/p&gt;
&lt;p&gt;On instantiating a test, a number of special things happen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any configuration dictionary provided is made available to the rest of the test class as an attribute.&lt;/li&gt;
&lt;li&gt;The configuration dictionary is checked against the &lt;code&gt;requires_config_keys&lt;/code&gt; attribute on the test class to make sure that all required settings have been satisfied (in the sense that they exist, no more than that).&lt;/li&gt;
&lt;li&gt;Any models listed in the &lt;code&gt;required_models&lt;/code&gt; attribute (&lt;em&gt;default&lt;/em&gt;: empty list) are registered with Django's internal model registration system &lt;em&gt;and&lt;/em&gt; with Django's internal admin model registration system (&lt;code&gt;admin.site.register&lt;/code&gt;). This allows us to only install the models for the tests that we are actually going to use and goes a long way to not cluttering up the admin interface unnecessarily (future dev will entail making the admin class definable).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the request comes in, the middleware runs the request against the test method of each test class, if the test returns a match instance then it is attached to the request so that the response middleware can use it to apply the linked replacements to the response. If no match is found, then the next loaded test is carried out. It is not a problem if no matches are found as the response middleware will apply the &quot;default&quot; replacements for all the available tags in that case. The test is &quot;remembered&quot; on the session for future requests, both for speed and functionality - it is unlikely the phone number in this case will want to swap again on the next request (as it would have likely lost its referrer data etc).&lt;/p&gt;
&lt;h2&gt;The future&lt;/h2&gt;
&lt;p&gt;Still to do are some further tests to increase coverage; have a look at implementing more than just session storage for persistence (cookies, cache etc); better caching or stored and retrieved contextual 'matches'; and an implementation of &quot;request&quot; priorities is also in the pipeline which will allow certain requests to override whatever replacements were already set on the session.&lt;/p&gt;
&lt;div class=&quot;admonition admonition-warning&quot;&gt;&lt;p&gt;&lt;strong&gt;DEPRECATED&lt;/strong&gt;: This project will remain on Github but development is no longer active and indeed, has not been for a considerable time (2011, circa Django 1.2). If you wish to do similar nowadays, this is definitely not how you should go about it. Please take a look at the new TemplateResponse objects instead.&lt;/p&gt;&lt;/div&gt;</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/djangos-little-protections-word-redirect-dangers/">
    <title type="text">On redirect dangers</title>
    <id>urn:uuid:01c96fe3-38ed-39a2-ab14-a7fb9f77ff51</id>
    <updated>2010-12-09T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/djangos-little-protections-word-redirect-dangers/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;I think it goes without argument that &lt;a href=&quot;http://www.djangoproject.com&quot;&gt;Django&lt;/a&gt; does every little bit it can to prevent you from inserting security holes into your application; that may in the form of auto-escaping all template variables by default, sanitising all database input or the CSRF protection that came with v1.2. Under the hood however it does many other checks to prevent things you perhaps had no idea about and today I'll be covering just one of those, so that you can also implement the feature safely in any code you have to write yourself.&lt;/p&gt;
&lt;h2&gt;The problem: trusting client data for use in redirects&lt;/h2&gt;
&lt;p&gt;A common use case for doing redirects in the view is after a successful POST form submission (to reduce the chance of resubmitting POST data among other things). When you mix this with the need to redirect to &quot;somewhere&quot; afterwards you often will get the case where you're either taking in a the &quot;somewhere&quot; variable in via either a GET or POST dictionary and this is where the problem arises as this data is sent from the client and can therefore be edited client-side or via interception (man-in-the-middle).&lt;/p&gt;
&lt;p&gt;How does this affect redirects? Imagine the scenario where you provide a link to a form page with a &lt;code&gt;next&lt;/code&gt; GET variable. e.g &lt;code&gt;http://www.example.com/submit/?next=/success/&lt;/code&gt;. This variable is then added as the value of a hidden input on rendering the template for the form page; this then gets POST'd to the server on submission of the form. You then redirect to the given URL and break the number one web commandment: &lt;em&gt;never&lt;/em&gt; trust external data.&lt;/p&gt;
&lt;p&gt;The problem here is that anyone can simply redirect an oblivious user to any URL by simply changing the &lt;code&gt;next&lt;/code&gt; get variable when they use the link to the form submission page. e.g &lt;code&gt;http://www.example.com/submit/?next=http://www.google.com&lt;/code&gt; will redirect to Google on successful submission which, while harmless in this case, can be used for very effective spoofing/fishing attacks.&lt;/p&gt;
&lt;p&gt;Imagine doing this on a login form; an unscrupulous user could clone the look of your login page, host it somewhere and then hand out URLs such as &lt;code&gt;http://www.example.com/login/?next=http://www.somewhere-nasty.com/login/&lt;/code&gt;. On initial look, the URL looks perfectly friendly, but if you're view code is set up to redirect on success without checking the variable, the user will get redirected to the cloned page which could host a message such as &quot;incorrect user/pass&quot; causing the user to re-enter their credentials on a foreign site.&lt;/p&gt;
&lt;p&gt;This is a very good trick for people wishing to take advantage of it as the media and net on general has been quite tight on telling people to always check the URL they are visiting, and it has become a very ingrained part of the user experience that if the URL is correct, the site is safe.&lt;/p&gt;
&lt;h2&gt;The solution: sanitising the redirect variable&lt;/h2&gt;
&lt;p&gt;Those of you familiar with Django's &lt;code&gt;contrib.auth&lt;/code&gt; module will recognise the use case as Django's default login view provides the ability to redirect based on a incoming variable. Django however takes a precautionary step again the above problem so that you don't have to and the code is pasted below so we can see how with a couple of lines you can prevent yourself from the same kind of flaw if building something yourself.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Heavier security check -- redirects to http://example.com should&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# not be allowed, but things like /view/?param=http://example.com&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# should be allowed. This regex checks if there is a &amp;#39;//&amp;#39; *before* a&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# question mark.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;//&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;[^\?]*//&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOGIN_REDIRECT_URL&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;via &lt;a href=&quot;http://code.djangoproject.com/browser/django/tags/releases/1.2.3/django/contrib/auth/views.py#L37&quot;&gt;djangoproject.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can read the comments which pretty much explains what I'm about to say but this line effectively checks that the URL does not contain a &lt;code&gt;//&lt;/code&gt; (as in http:&lt;strong&gt;//&lt;/strong&gt;) and if it does, it uses the default &lt;code&gt;LOGIN_REDIRECT_URL&lt;/code&gt; provided in the settings file. If it doesn't, it does another check to make sure the &lt;code&gt;//&lt;/code&gt; occurs after the query string denoter &lt;code&gt;?&lt;/code&gt; before letting it through. If you were being lazy you could just check the variable starts with a&lt;code&gt;/&lt;/code&gt; but as the comment says this would rule out cases where you want to redirect to a URL that has another URL as part of its query string (this may actually be desired, up to you).&lt;/p&gt;
&lt;p&gt;Anyway, that's it - I'll try and write about more of Django's lesser known security features sometime soon.&lt;/p&gt;
&lt;h2&gt;Update 6th March 2011&lt;/h2&gt;
&lt;p&gt;Django trunk's way of handling this has changed and so I thought I'd quickly update this post to showcase the new better way. It basically now uses the urlparse module to check the hostname of the redirect is the same as that of the current request (as opposed to the regex based check above).&lt;/p&gt;
&lt;p&gt;For ease, the code is pasted here:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;netloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urlparse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlparse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Use default setting if redirect_to is empty&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOGIN_REDIRECT_URL&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Security check -- don&amp;#39;t allow redirection to a different&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# host.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;netloc&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;netloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOGIN_REDIRECT_URL&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;via &lt;a href=&quot;http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/views.py#L37&quot;&gt;djangoproject.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Update 26th June 2013&lt;/h2&gt;
&lt;p&gt;I thought I'd update as this article still attracts hits. Django has made it even easier to handle this as a patch landed on Dec 10, 2012 that extracted the checking code out into it's own method in &lt;code&gt;django.utils.http&lt;/code&gt; called is_safe_url. This landed in v1.3 so it's available in that and 1.4 &amp;amp; 1.5. You can see it below for ease, follow the link to view it on Github.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_safe_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    Return ``True`` if the url is a safe redirection (i.e. &lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    it doesn&amp;#39;t point to a different host).&lt;/span&gt;

&lt;span class=&quot;sd&quot;&gt;    Always returns ``False`` on an empty url.&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;netloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urllib_parse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlparse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;netloc&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;netloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;via &lt;a href=&quot;https://github.com/django/django/blob/d1b7bd030b1db111e1a3505b1fc029ab964382cc/django/utils/http.py#L231&quot;&gt;github.com/django/django&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Update 18th August 2013&lt;/h2&gt;
&lt;p&gt;This particular method has attracted attention recently due to latest &lt;a href=&quot;https://www.djangoproject.com/weblog/2013/aug/13/security-releases-issued/&quot;&gt;Django security advisory&lt;/a&gt; which caused the release of Django 1.4.6, 1.5.2 &amp;amp; 1.6 beta2 to fix the issue. The vulnerability found was related to an XSS flaw in utilising the &lt;code&gt;is_safe_url&lt;/code&gt; method to guarantee a safe redirect.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The is_safe_url() function works as intended for HTTP and HTTPS URLs, but due to the manner in which it parses the URL, will permit redirects to other schemes, such as javascript:. While the Django project is unaware of any demonstrated ability to perform cross-site scripting attacks via this mechanism, the potential for such is sufficient to trigger a security response.&lt;/p&gt;
&lt;p&gt;To remedy this issue, the is_safe_url() function has been modified to properly recognize and reject URLs which specify a scheme other than HTTP or HTTPS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;via &lt;a href=&quot;https://www.djangoproject.com/weblog/2013/aug/13/security-releases-issued/&quot;&gt;djangoproject.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For your perusal, the updated code is included:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_safe_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    Return ``True`` if the url is a safe redirection (i.e. it doesn&amp;#39;t point to&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    a different host and uses a safe scheme).&lt;/span&gt;

&lt;span class=&quot;sd&quot;&gt;    Always returns ``False`` on an empty url.&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;url_info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urllib_parse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlparse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url_info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;netloc&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url_info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;netloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; \
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url_info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url_info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;http&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;https&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;via &lt;a href=&quot;https://github.com/django/django/blob/d1b7bd030b1db111e1a3505b1fc029ab964382cc/django/utils/http.py#L231&quot;&gt;github.com/django/django&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/enhance-pdb-debugging-ipdb-ipython/">
    <title type="text">Enhancing Python Breakpoint Debugging</title>
    <id>urn:uuid:db22c7cb-1249-329b-a4fa-85aae5615c91</id>
    <updated>2010-12-01T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/enhance-pdb-debugging-ipdb-ipython/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://docs.python.org/library/pdb.html&quot;&gt;pdb&lt;/a&gt; is Python's brilliant interactive source code debugger which allows you set a point to &quot;jump into&quot; your code and use the standard shell for introspection and navigating up and down your code. &lt;a href=&quot;http://ipython.scipy.org/moin/FrontPage&quot;&gt;IPython&lt;/a&gt; is a 3rd-party package (part of SciPy) that adds serious enhancements to Python's interactive shell.&lt;/p&gt;
&lt;p&gt;A great tip I learnt about a year ago is that the two can be brought together to make debugging even easier than it already was. ipdb brings all of IPythons greatness including tab completion, syntax highlighting, better tracebacks, better introspection and more to the standard pdb debugger so that when you set your break point, instead of getting the standard Python shell, you receive the IPython one and then effectively carry on as usual. and it's a cinch to install.&lt;/p&gt;
&lt;h2&gt;Installation and use of ipdb&lt;/h2&gt;
&lt;p&gt;Prerequisites: the &lt;a href=&quot;http://pypi.python.org/pypi/ipython/&quot;&gt;ipython package&lt;/a&gt; is required; all methods listed below will install this for you if the requirement is not found.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://pypi.python.org/pypi/ipdb&quot;&gt;ipdb is available in the cheeseshop&lt;/a&gt; and as such is a standard Python package that can be downloaded and installed with &lt;code&gt;python setup.py install&lt;/code&gt;. Or, take the quicker route and install with either &lt;code&gt;easy_install&lt;/code&gt; or &lt;code&gt;pip&lt;/code&gt; (recommended) with one of the following commands:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    easy_install ipdb
    pip install ipdb
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then in your code, instead of importing pdb you simply import and use ipdb instead as follows:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ipdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipdb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This comes in particular handy when using Django's runserver command as the process will &quot;halt&quot; (until you quit out of IPython with &lt;code&gt;Ctrl + D&lt;/code&gt;, or 'carry on' with &lt;code&gt;continue&lt;/code&gt;) allowing you to use IPython's advanced tab completion, history, tracebacks and syntax highlighting for better object introspection and for jumping forward or backward through code, among other things (see &lt;a href=&quot;http://ipython.scipy.org/moin/Documentation&quot;&gt;IPython's documentation&lt;/a&gt;.)&lt;/p&gt;
</content>
  </entry>
  <entry xml:base="https://www.djm.org.uk/posts/radio-tray-perfect-example-do-one-thing-do-it-well/">
    <title type="text">Do one thing and do it well</title>
    <id>urn:uuid:dfce5646-6fd4-36e9-a199-7744f2639d67</id>
    <updated>2010-11-16T00:00:00Z</updated>
    <link href="https://www.djm.org.uk/posts/radio-tray-perfect-example-do-one-thing-do-it-well/" />
    <author>
      <name></name>
    </author>
    <content type="html">&lt;p&gt;The shortened &lt;a href=&quot;http://en.wikipedia.org/wiki/Unix_philosophy&quot;&gt;Unix philosophy&lt;/a&gt; of &quot;Write programs that do one thing and do it well&quot; by Doug McIlroy is something that is quite often ignored in and out of the Unix software world. There are obviously cases where it definitely cannot apply but for most things I do on Linux these days, I like having a specific tool for a specific job.&lt;/p&gt;
&lt;h2&gt;The job: streaming radio&lt;/h2&gt;
&lt;p&gt;Such a simple task right? Before I found &lt;a href=&quot;http://radiotray.sourceforge.net/&quot;&gt;Radio Tray&lt;/a&gt; it would always be a rather large hassle using a bigger piece of software such as Rhythmbox or VLC to do what is effectively an incredibly simple task that requires no play controls whatsoever except from '&lt;em&gt;select&lt;/em&gt;' and '&lt;em&gt;volume&lt;/em&gt;'.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;a href=&quot;http://radiotray.sourceforge.net/&quot;&gt;Radio Tray&lt;/a&gt; is not a full featured music player, there are plenty of excellent music players already. However, there was a need for a simple application with minimal interface just to listen to online radios. And that's the sole purpose of Radio Tray. - via &lt;a href=&quot;http://radiotray.sourceforge.net/&quot;&gt;Radio Tray @ SourceForge&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://radiotray.sourceforge.net/&quot;&gt;Radio Tray&lt;/a&gt; handles the task beautifully while keeping the configuration simple and the interface out of the way. It has no detached windows in common use and is controlled solely from the task tray in Gnome or KDE with a simple left click giving a nicely separated list of your online streaming radio stations, grouped in whatever fashion you please with simple separators or drop-downs. A right click allows configuration of the radio stations (which in itself it simple, only name and URL for each station) and a scroll of the mouse wheel while hovering over the icon will change the volume level.&lt;/p&gt;
&lt;p&gt;It's simplicity at it's best and what's more is the notifications you get thanks to the likes of &lt;code&gt;python-notify&lt;/code&gt; and the fact it seems to handle anything you chuck at it including PLS, M3U, ASX, WAX &amp;amp; WVX as it's based on gstreamer.&lt;/p&gt;
&lt;h2&gt;Take your stations anywhere&lt;/h2&gt;
&lt;p&gt;Another philosophy the program abides by is to &quot;store data in flat text files&quot; - the program stores both it's config file (&lt;code&gt;config.xml&lt;/code&gt;) and it's bookmarks file (&lt;code&gt;bookmarks.xml&lt;/code&gt;) in your home folder under &lt;code&gt;~/.local/share/radiotray/&lt;/code&gt;. This makes it incredibly easy to backup and keep your configuration and list of radio stations portable, either by simply copying them to a USB stick or by keeping the files in some kind of central repository. For those that know how to use &lt;code&gt;git&lt;/code&gt;, you can find my list of &lt;a href=&quot;https://github.com/djm/dotfiles&quot;&gt;bookmarks on Github&lt;/a&gt;. On setting up a new pc, all I have to do is checkout the repo, and then symlink the location of where it expects the bookmarks file to the one in the checkout (&lt;code&gt;ln -s /path/to/repo/bookmarks.xml ~/.local/share/radiotray/bookmarks.xml&lt;/code&gt;) and that's it - all my additions and changes to bookmarks will be synced everywhere (with a quick push and pull from the repo).&lt;/p&gt;
&lt;p&gt;Oh, and did I mention it's all coded in Python?&lt;/p&gt;
</content>
  </entry>
</feed>
