1

I'm looking for a way to configure Varnish to handle HTTP request within Varnish.

More specifically, for specific paths(say under */foo/** ), I want Varnish to respond with 200 HTTP status code and empty(or fixed message) body, rather than forwarding requests to backend servers.

1
  • 3
    I think you could abuse vcl_error to do this. May 28, 2014 at 16:43

2 Answers 2

5

I agree to Michael's short response to abuse/use vcl_error for this purpose and like to show you what we meant in the example code below.

To abuse vcl_error I have used here error codes outside of the HTTP standard and implement a special treatment for this kind of errors.

Example in VCL_RECV:

sub vcl_recv {
  ...
  # respond HTTP 200 to /ping requests
  if (req.url ~ "^/ping") {
    error 700;
  }
  # return a 301 redirect
  if (req.url ~ "^/wrong-target") {
    error 751 "http://www.example.com/correct-target";
  }
}

Example in VCL_ERROR:

sub vcl_error {
  # send response "Pong" (HTTP 200)
  if (obj.status == 700) {
    set obj.status = 200;
    set obj.response = "OK";
    set obj.http.Content-Type = "text/plain";
    synthetic {"Pong"};
    return (deliver);
  }
  # send empty response (HTTP 204)
  if (obj.status == 701) {
    set obj.status = 204;
    set obj.response = "No Content";
    synthetic {""};
    return (deliver);
  }
  # redirect 301
  if (obj.status == 751) {
    set obj.http.Location = obj.response;
    set obj.status = 301;
    set obj.response = "Moved Permanently";
    return (deliver);
  }
  # redirect 302
  if (obj.status == 752) {
    set obj.http.Location = obj.response;
    set obj.status = 302;
    set obj.response = "Found";
    return (deliver);
  }
  # Fall through to default behavior for all other exceptions
}
4
  • 2
    This is the correct answer, and also the official way (per Varnish docs) to handle this. However, both your answer and the Varnish docs have an omission: if you don't set obj.response to something sane, then you'll get HTTP/1.1 200 Unknown Error or even HTTP/1.1 200 http://www.example.com/correct-target in your response! Simple fix: obj.response = "OK" for 200, or other appropriate code for the others.
    – BMDan
    May 30, 2014 at 21:20
  • @BMDan: Thank you for this important hint. I have updated the pasted code to set proper HTTP status messages. May 31, 2014 at 8:58
  • Thanks @jens-bradler, this was exactly what I wanted, and I didn't know there's a HTTP status code as "204:No Content"!
    – quiver
    May 31, 2014 at 18:06
  • Sorry to be a pain, but you very much don't want return(deliver) at the very bottom of your vcl_error! If it doesn't satisfy any of the conditionals, you want it to fall through to the default behavior of constructing a "Guru Meditation" page (by not returning at all).
    – BMDan
    Jun 9, 2014 at 15:03
3

For future readers of this question, I ported @jens-bradler 's vcl to Varnish 4. (Serverfault doesn't allow me to post multiple line code as comments, so I post here as another answer)

vcl 4.0;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    if (req.url ~ "^/ping") {
        return (synth(700, "Ping"));
    }

    if (req.url ~ "^/wrong-target") {
        return (synth(751, "http://www.example.com/correct-target"));
    }
}

sub vcl_synth {
    set resp.http.Retry-After = "5";
    if (resp.status == 700) {
        set resp.status = 200;
        set resp.reason = "OK";
        set resp.http.Content-Type = "text/plain;";
        synthetic( {"Pong"} );
        return (deliver);
    }
    if (resp.status == 701) {
        set resp.status = 204;
        set resp.reason = "No Content";
        set resp.http.Content-Type = "text/plain;";
        synthetic( {""} );
        return (deliver);
    }
    if (resp.status == 751) {
        set resp.http.Location = resp.reason;
        set resp.status = 301;
        set resp.reason = "Moved Permanently";
        return (deliver);
    }

    if (resp.status == 752) {
        set resp.http.Location = resp.reason;
        set resp.status = 302;
        set resp.reason = "Found";
        return (deliver);
    }

    return (deliver);
}

sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.
}

sub vcl_deliver {
    # Happens when we have all the pieces we need, and are about to send the
    # response to the client.
    #
    # You can do accounting or modifying the final object here.
}
3
  • You probably want to delete the return(deliver); from the bottom of vcl_synth, lest you fail to run this code from builtin.vcl (née default.vcl): varnish-cache.org/trac/browser/bin/varnishd/… .
    – BMDan
    Jun 23, 2014 at 4:21
  • @BMDan - perhaps you can type here what to write instead of "return (deliver);" Plus the URL you typed here is invalid.
    – hB0
    Jul 4, 2017 at 8:41
  • @hB0 it looks like Varnish has moved their code. github.com/varnishcache/varnish-cache/blob/… appears to be a current link.
    – BMDan
    Jul 13, 2017 at 22:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .