niccolox

niccolox

hi, thanks for this

can I Route on cookies, similar to this question: Is it possible to modify Router matches based on cookies like in Varnish? - #3 by dimitarvp

I want to be able to present a static cached page using http_cache | Hex if no cookies and if there are cookies I want to route to a non cached cookied page


in Varnish you can do:

sub vcl_hash {
  if (req.http.cookie ~ "wordpress_logged_in_") {
    hash_data("wordpress_logged_in");
  }
  # the builtin.vcl will take care of also varying cache on Host/IP and URL 
}

or better

import cookie;
import directors;
import std;
import kvstore;

sub vcl_init {
    kvstore.init(0, 1000);
}

sub vcl_backend_response {
    set beresp.http.x-tmp = regsub(header.get(beresp.http.set-cookie,"JSESSIONID=", " *;.*", "");
    if (beresp.http.x-tmp != "") {
        kvstore.set(0, cookie.get("id"), beresp.backend, 15m);
    }
    unset beresp.http.x-tmp;
}

sub vcl_recv {
    cookie.parse(req.http.cookie);
    set req.http.server = kvstore.get(0, cookie.get("id"), "none");

    if (req.http.server == "s1") {
        set req.backend_hint = s1;
    } else if (req.http.server == "s2") {
        set req.backend_hint = s2;
    } else {
        if (std.rand(0, 100) < 50) {
            req.backend_hint = s1;
        } else {
            req.backend_hint = s2;
        }
    }
    return (pass);
}

or in Nginx, you can define a map in http section:

map $cookie_proxy_override $my_upstream {
  default default-server-or-upstream;
  ~^(?P<name>[\w-]+) $name;
}

Then you simply use $my_upstream in location section(s):

location /original-request {
  proxy_pass http://$my_upstream$uri;
}

Nginx evaluates map variables lazily, only once (per request) and when you are using them.

server {
    ...
    set $upstream "default-server-or-upstream";
    if ($http_cookie ~ "proxy_override=([\w-]+)") {
        set $upstream $1;                                   
    }

    location /original-request {
        proxy_pass http://$upstream/original-application
    }
}

I asked Brave search AI and it gave me:

defmodule MyApp.Router do
  use Plug.Router

  plug :match
  plug :dispatch

  get "/hello" do
    case get_req_header(conn, "cookie") do
      [{"cookie_value"}] -> send_resp(conn, 200, "Cookie matched")
      _ -> send_resp(conn, 400, "Cookie not matched")
    end
  end
end

or

defmodule MyApp.Router do
  use Plug.Router

  plug :match
  plug :dispatch

  get "/set-cookie" do
    domain = PublicSuffix.registrable_domain(conn.host)
    opts = [store: :cookie, key: "_myapp_key", signing_salt: "asdadl", domain: domain, max_age: max_age, http_only: true]
    opts = Plug.Session.init(opts)
    conn = Plug.Session.call(conn, opts)
    send_resp(conn, 200, "Cookie set")
  end
end

@tangui

Showing Posts 1 to 4

BartOtten

BartOtten

Hi @niccolox,

First of all thank you for showing interest in Routex.

What you are requesting is imho not in scope of Routex itself. Let me try to explain with an analogy:

Consider this analogy…

You are a real estate entrepreneur wanting to build a few houses. You have some global ideas about what houses (route definitions in route.ex) and how they should look (Routex configuration).

Routex would be the architect which takes your ideas (route definitions) and wishes (Routex config) and designs the blueprints. Routex extension are the tools the architect uses to change the blueprints in an efficient manner.

Once the architect has finalized the blueprints, the blueprints are passed to construction company Phoenix.Router to construct the actual houses (routes) following the blueprints. The blueprints are exactly how Phoenix.Router expects them to be. As if they were made for it!

This is the first part: Routex generates blueprints using route definitions and Routex config for Phoenix.Router to build.


The second part is almost a side-effect: As Routex is the architect, it also knows all specifications of the houses produced and so it can produce a few accessories (helper functions) for the houses being build by Phoenix.Router Contruction and co. A fancy electronic door lock, a perfect matching sunscreen and so on. It’s all additional functionality next to all functionality of Phoenix already build, but it makes life a bit easier.

Given this analogy…
What you are asking is a split in the road that leads to the houses so you can route to different houses upfront (before router logic kicks in [1]) OR a split in the hallway once a house entered leading visitors to different rooms (after the router did it’s job [2]).

[1] Varnish, Nginx, Plug
[2] Inside the controller of (Live)View.

Hope this makes sense,
Let me know.

tangui

tangui

Using plug_http_cache, you can always refuse a cached version to be served by setting the request cache-control: no-cache header.

The spec states that:

The no-cache request directive indicates that the client prefers a stored response not be used to satisfy the request without successful validation on the origin server.

Luckily, plug_http_cache doesn’t support revalidation* and doesn’t return a cached version in this case, so what you have to do is just to write a Plug before plug_http_cache that

  • reads if there is a specific cookie / cookie value (user authenticated for instance)
  • set this cache-control: no-cache request header if so

Cheers

* You should have a test for this, since plug_http_cache might support revalidation in the future, although it is not very likely

EDIT: might even be better to set the request header cache-control: max-age=0

niccolox

niccolox OP

Thanks guys

I think I am going to pattern a plug on the Phx.auth.gen code such that the plug checks for cookie and then does redirects etc

I want some solution that is very close to core

niccolox

niccolox OP

havent tested this, and obviously its incomplete, but this is the direction

  Used for routes that require the user has no cookies and is probably a first time visitor.
  """
  defp no_cookies_path(_conn), do: "/static"

  def redirect_if_user_no_cookies(conn, _opts) do
    conn = fetch_cookies(conn, signed: [@remember_me_cookie])
    if conn.cookies[@remember_me_cookie] == nil do
      conn
      |> redirect(to: no_cookies_path(conn))
      |> halt()
    else
      conn
    end
  end
— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews