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.

  • 3
    I think you could abuse vcl_error to do this. – Michael Hampton May 28 '14 at 16:43
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
}
  • 1
    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 '14 at 21:20
  • @BMDan: Thank you for this important hint. I have updated the pasted code to set proper HTTP status messages. – Jens Bradler May 31 '14 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 '14 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 '14 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.
}
  • 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 '14 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 '17 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 '17 at 22:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.