banが謎のマッチになっていたのを修正

banが謎のマッチになっていたのを修正

#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and https://www.varnish-cache.org/trac/wiki/VCLExamples for more examples.

# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

import directors;

# Default backend definition. Set this to point to your content server.
backend localhost {
    .host = "127.0.0.1";
    .port = "5000";
}

sub vcl_init {
    new backend = directors.round_robin();

    backend.add_backend(localhost);
}

sub vcl_recv {
  set req.backend_hint = backend.backend();

  if (req.method == "INVALIDATE") {
     ban("obj.http.Keyword = " + req.http.X-Invalidated-Keyword);
    return(synth(200, req.http.X-Invalidated-Keyword + " Purged. Success !!"));
  }

  # if (req.http.Cookie) {
  #     return(pass);
  # }

  if (req.method != "GET" && req.method != "HEAD") {
      return(pass);
  }

  return(hash);
}

sub vcl_hash {
  hash_data(req.url);
  if (req.http.host) {
    hash_data(req.http.host);
  } else {
    hash_data(server.ip);
  }
  return (lookup);
}

sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }

    return(deliver);
}

sub vcl_backend_response {

  set beresp.do_esi = true;
  # this is same as builtin vcl_backend_response
  # https://www.varnish-cache.org/trac/browser/bin/varnishd/builtin.vcl?rev=ae548683b8f91d0a92799f6c746b80773a4c9f05
  if (beresp.ttl <= 0s ||
    beresp.http.Set-Cookie ||
    beresp.http.Surrogate-control ~ "no-store" ||
    beresp.http.Cache-Control ~ "no-cache" ||
    (!beresp.http.Surrogate-Control &&
      beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
    beresp.http.Vary == "*") {
      /*
      * Mark as "Hit-For-Pass" for the next 2 minutes
      */
      set beresp.uncacheable = true;
  }

  # this is hatena original config
  if (beresp.ttl > 0s && ! beresp.uncacheable) {
      set beresp.grace = 1m;
  }
  return (deliver);
}

sub vcl_synth {
    set resp.http.Content-Type = "text/html; charset=utf-8";
    set resp.http.Retry-After = "5";
    synthetic( {"<!DOCTYPE html>

    <title>"} + resp.status + " " + resp.reason + {"</title>

"} + resp.status + " " + resp.reason + {"

"} + resp.reason + {"

XID: "} + req.xid + {"

"} );
    return (deliver);
}

#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and https://www.varnish-cache.org/trac/wiki/VCLExamples for more examples.

# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

import directors;

# Default backend definition. Set this to point to your content server.
backend localhost {
    .host = "127.0.0.1";
    .port = "5000";
}

sub vcl_init {
    new backend = directors.round_robin();

    backend.add_backend(localhost);
}

sub vcl_recv {
  set req.backend_hint = backend.backend();

  if (req.method == "INVALIDATE") {
     ban("obj.http.Keyword = ^.*" + req.http.X-Invalidated-Keyword + ".*$");
    return(synth(200, req.http.X-Invalidated-Keyword + " Purged. Success !!"));
  }

  # if (req.http.Cookie) {
  #     return(pass);
  # }

  if (req.method != "GET" && req.method != "HEAD") {
      return(pass);
  }

  return(hash);
}

sub vcl_hash {
  hash_data(req.url);
  if (req.http.host) {
    hash_data(req.http.host);
  } else {
    hash_data(server.ip);
  }
  return (lookup);
}

sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }

    return(deliver);
}

sub vcl_backend_response {

  set beresp.do_esi = true;
  # this is same as builtin vcl_backend_response
  # https://www.varnish-cache.org/trac/browser/bin/varnishd/builtin.vcl?rev=ae548683b8f91d0a92799f6c746b80773a4c9f05
  if (beresp.ttl <= 0s ||
    beresp.http.Set-Cookie ||
    beresp.http.Surrogate-control ~ "no-store" ||
    beresp.http.Cache-Control ~ "no-cache" ||
    (!beresp.http.Surrogate-Control &&
      beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
    beresp.http.Vary == "*") {
      /*
      * Mark as "Hit-For-Pass" for the next 2 minutes
      */
      set beresp.uncacheable = true;
  }

  # this is hatena original config
  if (beresp.ttl > 0s && ! beresp.uncacheable) {
      set beresp.grace = 1m;
  }
  return (deliver);
}

sub vcl_synth {
    set resp.http.Content-Type = "text/html; charset=utf-8";
    set resp.http.Retry-After = "5";
    synthetic( {"<!DOCTYPE html>

    <title>"} + resp.status + " " + resp.reason + {"</title>

"} + resp.status + " " + resp.reason + {"

"} + resp.reason + {"

XID: "} + req.xid + {"

"} );
    return (deliver);
}


Add command for nonblank space

Add command for nonblank space

# Voice commands for atom

Test Command = "This Is a Test Command";  # see if working on laptop and on my desktop at work

include folders.vch;
include letters.vch;

# Commands for developing D3: D3 visualizations, D3 Sandwiches
Save and Reload =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}")  {Ctrl+r};
Save and Really Reload =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}") {Ctrl+Shift+r};
Save and Run =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}")  {Up}{Enter};

# File commands
Find (File | Document) = {Ctrl+t};
Save As = {Ctrl+Shift+s};
Next Window = {Ctrl+Tab};
Last Window = {Ctrl+Shift+Tab};
Latest File = {Ctrl+Shift+t};
(Tree View | List Files) = {Alt+o};	# NOTE: to make this work, I had to create a new keyboard shortcut in Atom (my personal keymap.cson)

# --- Text navigation commands ------------------------------------
<delimiters> := (Quote = '"' | 'Double Quote' = '"' | 'Single Quote' = "'" | Comma = ',' | 'Equal Sign' = '=' | Equals = '='
	| Period = '.' | Colon = ':' | 'Semi-Colon' = ';' | Hyphen = '-' |  Underscore = '_' | Slash = '/'
	| Paren = "(" | "Close Paren" = ")" | Parentheses = "(" | "Open Parenthesis" = "(" | "Close Parentheses" = ")"
	| Bracket = '[' | "Close Bracket" = ']' | Brace = '{' | 'Close Brace' = '}'	);

Line 1..200 = {Ctrl+g} $1 {Enter};
(Left = 'b' | Right = 'f') Word = {Alt+$1};
Top = {Ctrl+Home};
Bottom = {Ctrl+End};
(Find = 'Right' | 'Insert After' = 'Right' | 'Insert Before' = 'Left') (Next = 'Enter' | Last = 'Shift+F3') <delimiters>
		= {Ctrl+f} $3 {$2} {Esc}   Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') <delimiters> =  {Ctrl+f} $2 {Enter} {Esc}   Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') 1..20 <delimiters> =  {Ctrl+f} $3 {Enter} {Esc}   Wait(100) {F3_$2} {Shift+F3} Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') Enda <delimiters> = {End} {Ctrl+f} $2 {Enter} {Esc} {Shift+F3}  Wait(100) {$1};

Fine Alpha <letters> = {Ctrl+f} $1 {Enter} {Esc}   Wait(100) {Left};
Insert (Before = 'Left' | After = 'Right') Alpha <letters> =  {Ctrl+f} $2 {Enter} {Esc}   Wait(100) {$1};
Fine Number 0..9 = {Ctrl+f} $1 {Enter} {Esc} Wait(100) {Right};
(Find | Insert) Again = {F3} {Right};
(Find | Insert) Again 1..20 Times = {F3_$1} {Right};

(Set | Add | Clear | Hide | Delete) Bookmark = {Ctrl+Alt+F2};
(Next = 'F2' | Last = 'Shift+F2') Bookmark = {$1};

# --- Editing commands ----------------------------------------
Select Line = {Ctrl+l};
Select (Next = 'Down' | Forward = 'Down' | Last = 'Up' | Back = 'Up' | Previous = 'Up') 1..20 Lines = {Home} {Shift+$1_$2};
Move Line (Up | Down) 1..20  = {Ctrl+$1_$2};
Add 1..20 (Lines = 'Down' | Line = 'Down' | Pages = 'PgDn' | Page = 'PgDn') = {Shift+$2_$1};
Start Adding 1..20 Lines = {Home}{Shift+Down_$1};

Select between (Delimiters | Brackets | Tags) ={Ctrl+m} {Ctrl+Alt+m};
Delete between Tags = {Ctrl+m} {Ctrl+Alt+m}  {Del};
Delete Tags = {Ctrl+Alt+F4};
Replace With (Header | Heading) 1..7 = {Ctrl+Alt+F4}  '<h' $2 '>' {End} '</h' $2 '>' {Home};
Replace With (para = 'p') = {Ctrl+Alt+F4} '<' $1 '>' {End} '</' $1 '>';

Delete Word = {Ctrl+Del};
Delete 1..20 Words = {Ctrl+Del_$1};
Delete (Back | Last) Word = {Ctrl+Backspace};
Delete (Back | Last) 1..20 Words = {Ctrl+Backspace_$2};
Delete Enda Word = {End} {Ctrl+Backspace};
Kill Word = {Ctrl+Backspace}{Ctrl+Del};

(Delete Line | Dede) = {Ctrl+Shift+k};
Delete 1..20 Lines = {Ctrl+Shift+k_$1};
(Cut = 'x' | Paste = 'v' | Copy = 'c') That = {Ctrl+$1};

Comment (That | Line) = {Ctrl+/};
Comment 1..20 Lines = {Home} {Shift+Down_$1} {Ctrl+/};

Replace = {Ctrl+f};
Replace All = {Ctrl+Enter};

(Join = 'j' | Indent = ']' | Dedent = '[')  That = {Ctrl+$1};

# --- Commands to create code/tags -------------------------------------------
# NOTE: basic HTML commands are stored in my global Vocala commands

Start (	# HTML commands
	'HTML page' = 'html' | pre = "pre" | 'Comment' = 'comment-html'
	| div = 'div'
	| 'class example' = 'class-example'		# Used in A Taste of D3

	# D3 Recipe commands
	| 'Recipe Page' = 'recipe-page' | 'Recipe Row' = 'recipe-row'
	| 'Recipe Toy' = 'recipe-toy' | Toy = 'recipe-toy'
	| 'Bold ID'

	# D3 and JavaScript commands
	| Console = 'console' | Log = 'console'
	| Var = 'variable' | Variable = 'variable'
	# Coffeescript commands
	| Snippet = 'my-snippet'
	| 'Fix Line' = 'fix-current-line' | 'Fix Current Line' = 'fix-current-line'
) = $1 {Tab};

Stop (	#HTML commands
	'div comment' = 'comment-div-end' |  Comment = 'comment-html-end' | 'div' = 'div-end'
) = $1 {Tab};

# HTML commands
Start (Nibs | Non-Blank Space) = ' ';
Dot HTML = '.html';
Start (Header | Heading) 1..7 = h $2 {Tab};
Add (Header | Heading) 1..7 =  '<h' $2 '>' {End} '</h' $2 '>';
Add (para = 'p') =  '<' $1 '>' {End} '</' $1 '>';

# D3 Recipe commands
Pre-Format Code =  {Ctrl+Alt+F5};
Reload Atom = {Ctrl+s} Wait(100)  {Shift+Ctrl+Alt+F5};
Command Palette = {Ctrl+Shift+p};
Keyboard Shortcuts = {Ctrl+.};
Run Specs = {Ctrl+Alt+p};
Show Console = {Ctrl+Alt+i};

# D3 commands
Paste Function = 'function ' {Ctrl+v} ' {' {Enter} {Enter} '};' {Up};

# Coffeescript commands

# Python commands

# --- D3 commands -------------------------------------------

# --- Python commands -------------------------------------------

# --- Coffeescript commands -------------------------------------------

# Voice commands for atom

Test Command = "This Is a Test Command";  # see if working on laptop and on my desktop at work

include folders.vch;
include letters.vch;

# Commands for developing D3: D3 visualizations, D3 Sandwiches
Save and Reload =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}")  {Ctrl+r};
Save and Really Reload =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}") {Ctrl+Shift+r};
Save and Run =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}")  {Up}{Enter};

# File commands
Find (File | Document) = {Ctrl+t};
Save As = {Ctrl+Shift+s};
Next Window = {Ctrl+Tab};
Last Window = {Ctrl+Shift+Tab};
Latest File = {Ctrl+Shift+t};
(Tree View | List Files) = {Alt+o};	# NOTE: to make this work, I had to create a new keyboard shortcut in Atom (my personal keymap.cson)

# --- Text navigation commands ------------------------------------
<delimiters> := (Quote = '"' | 'Double Quote' = '"' | 'Single Quote' = "'" | Comma = ',' | 'Equal Sign' = '=' | Equals = '='
	| Period = '.' | Colon = ':' | 'Semi-Colon' = ';' | Hyphen = '-' |  Underscore = '_' | Slash = '/'
	| Paren = "(" | "Close Paren" = ")" | Parentheses = "(" | "Open Parenthesis" = "(" | "Close Parentheses" = ")"
	| Bracket = '[' | "Close Bracket" = ']' | Brace = '{' | 'Close Brace' = '}'	);

Line 1..200 = {Ctrl+g} $1 {Enter};
(Left = 'b' | Right = 'f') Word = {Alt+$1};
Top = {Ctrl+Home};
Bottom = {Ctrl+End};
(Find = 'Right' | 'Insert After' = 'Right' | 'Insert Before' = 'Left') (Next = 'Enter' | Last = 'Shift+F3') <delimiters>
		= {Ctrl+f} $3 {$2} {Esc}   Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') <delimiters> =  {Ctrl+f} $2 {Enter} {Esc}   Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') 1..20 <delimiters> =  {Ctrl+f} $3 {Enter} {Esc}   Wait(100) {F3_$2} {Shift+F3} Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') Enda <delimiters> = {End} {Ctrl+f} $2 {Enter} {Esc} {Shift+F3}  Wait(100) {$1};

Fine Alpha <letters> = {Ctrl+f} $1 {Enter} {Esc}   Wait(100) {Left};
Insert (Before = 'Left' | After = 'Right') Alpha <letters> =  {Ctrl+f} $2 {Enter} {Esc}   Wait(100) {$1};
Fine Number 0..9 = {Ctrl+f} $1 {Enter} {Esc} Wait(100) {Right};
(Find | Insert) Again = {F3} {Right};
(Find | Insert) Again 1..20 Times = {F3_$1} {Right};

(Set | Add | Clear | Hide | Delete) Bookmark = {Ctrl+Alt+F2};
(Next = 'F2' | Last = 'Shift+F2') Bookmark = {$1};

# --- Editing commands ----------------------------------------
Select Line = {Ctrl+l};
Select (Next = 'Down' | Forward = 'Down' | Last = 'Up' | Back = 'Up' | Previous = 'Up') 1..20 Lines = {Home} {Shift+$1_$2};
Move Line (Up | Down) 1..20  = {Ctrl+$1_$2};
Add 1..20 (Lines = 'Down' | Line = 'Down' | Pages = 'PgDn' | Page = 'PgDn') = {Shift+$2_$1};
Start Adding 1..20 Lines = {Home}{Shift+Down_$1};

Select between (Delimiters | Brackets | Tags) ={Ctrl+m} {Ctrl+Alt+m};
Delete between Tags = {Ctrl+m} {Ctrl+Alt+m}  {Del};
Delete Tags = {Ctrl+Alt+F4};
Replace With (Header | Heading) 1..7 = {Ctrl+Alt+F4}  '<h' $2 '>' {End} '</h' $2 '>' {Home};
Replace With (para = 'p') = {Ctrl+Alt+F4} '<' $1 '>' {End} '</' $1 '>';

Delete Word = {Ctrl+Del};
Delete 1..20 Words = {Ctrl+Del_$1};
Delete (Back | Last) Word = {Ctrl+Backspace};
Delete (Back | Last) 1..20 Words = {Ctrl+Backspace_$2};
Delete Enda Word = {End} {Ctrl+Backspace};
Kill Word = {Ctrl+Backspace}{Ctrl+Del};

(Delete Line | Dede) = {Ctrl+Shift+k};
Delete 1..20 Lines = {Ctrl+Shift+k_$1};
(Cut = 'x' | Paste = 'v' | Copy = 'c') That = {Ctrl+$1};

Comment (That | Line) = {Ctrl+/};
Comment 1..20 Lines = {Home} {Shift+Down_$1} {Ctrl+/};

Replace = {Ctrl+f};
Replace All = {Ctrl+Enter};

(Join = 'j' | Indent = ']' | Dedent = '[')  That = {Ctrl+$1};

# --- Commands to create code/tags -------------------------------------------
# NOTE: basic HTML commands are stored in my global Vocala commands

Start (	# HTML commands
	'HTML page' = 'html' | pre = "pre" | 'Comment' = 'comment-html'
	| div = 'div'
	| 'class example' = 'class-example'		# Used in A Taste of D3

	# D3 Recipe commands
	| 'Recipe Page' = 'recipe-page' | 'Recipe Row' = 'recipe-row'
	| 'Recipe Toy' = 'recipe-toy' | Toy = 'recipe-toy'
	| 'Bold ID'

	# D3 and JavaScript commands
	| Console = 'console' | Log = 'console'
	| Var = 'variable' | Variable = 'variable'
	# Coffeescript commands
	| Snippet = 'my-snippet'
	| 'Fix Line' = 'fix-current-line' | 'Fix Current Line' = 'fix-current-line'
) = $1 {Tab};

Stop (	#HTML commands
	'div comment' = 'comment-div-end' |  Comment = 'comment-html-end' | 'div' = 'div-end'
) = $1 {Tab};

# HTML commands
Dot HTML = '.html';
Start (Header | Heading) 1..7 = h $2 {Tab};
Add (Header | Heading) 1..7 =  '<h' $2 '>' {End} '</h' $2 '>';
Add (para = 'p') =  '<' $1 '>' {End} '</' $1 '>';

# D3 Recipe commands
Pre-Format Code =  {Ctrl+Alt+F5};
Reload Atom = {Ctrl+s} Wait(100)  {Shift+Ctrl+Alt+F5};
Command Palette = {Ctrl+Shift+p};
Keyboard Shortcuts = {Ctrl+.};
Run Specs = {Ctrl+Alt+p};
Show Console = {Ctrl+Alt+i};

# D3 commands
Paste Function = 'function ' {Ctrl+v} ' {' {Enter} {Enter} '};' {Up};

# Coffeescript commands

# Python commands

# --- D3 commands -------------------------------------------

# --- Python commands -------------------------------------------

# --- Coffeescript commands -------------------------------------------


Support v2 API endpoints in Fastly config

sub vcl_recv {
#FASTLY recv

	if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
		return(pass);
	}

	if (req.url ~ "^/v\d/polyfill\." && req.url !~ "[\?\&]ua=") {
		set req.http.X-Orig-URL = req.url;
		set req.url = "/v2/normalizeUa?ua=" urlencode(req.http.User-Agent);
	}

	return(lookup);
}

sub vcl_deliver {
#FASTLY deliver

	# If the response is to a normalise request and there's a parked "original request", use the normalised UA response to modify the original request and restart it
	if (req.url ~ "^/v\d/normalizeUa" && resp.status == 200 && req.http.X-Orig-URL) {
		set req.http.Fastly-force-Shield = "1";
		if (req.http.X-Orig-URL ~ "\?") {
			set req.url = req.http.X-Orig-URL "&ua=" resp.http.Normalized-User-Agent;
		} else {
			set req.url = req.http.X-Orig-URL "?ua=" resp.http.Normalized-User-Agent;
		}
		restart;

	# If the original request didn't specify a UA override, and we added one when the request was sent to the backend, the backend won't have included a Vary:user-agent header (correctly) but we need to add one
	} else if (req.url ~ "^/v\d/polyfill\..*[\?\&]ua=" && req.http.X-Orig-URL && req.http.X-Orig-URL !~ "[\?\&]ua=") {
		set resp.http.Vary = "Accept-Encoding, User-Agent";
	}
	return(deliver);
}

sub vcl_recv {
#FASTLY recv

	if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
		return(pass);
	}

	if (req.url ~ "^/v1/polyfill\." && req.url !~ "[\?\&]ua=") {
		set req.http.X-Orig-URL = req.url;
		set req.url = "/v1/normalizeUa?ua=" urlencode(req.http.User-Agent);
	}

	return(lookup);
}

sub vcl_deliver {
#FASTLY deliver

	# If the response is to a normalise request and there's a parked "original request", use the normalised UA response to modify the original request and restart it
	if (req.url ~ "^/v1/normalizeUa" && resp.status == 200 && req.http.X-Orig-URL) {
		set req.http.Fastly-force-Shield = "1";
		if (req.http.X-Orig-URL ~ "\?") {
			set req.url = req.http.X-Orig-URL "&ua=" resp.http.Normalized-User-Agent;
		} else {
			set req.url = req.http.X-Orig-URL "?ua=" resp.http.Normalized-User-Agent;
		}
		restart;

	# If the original request didn't specify a UA override, and we added one when the request was sent to the backend, the backend won't have included a Vary:user-agent header (correctly) but we need to add one
	} else if (req.url ~ "^/v1/polyfill\..*[\?\&]ua=" && req.http.X-Orig-URL && req.http.X-Orig-URL !~ "[\?\&]ua=") {
		set resp.http.Vary = "Accept-Encoding, User-Agent";
	}
	return(deliver);
}


Support polyfills.io with redirect to polyfill.io

import boltsort;

sub vcl_recv {
#FASTLY recv
	if ( req.request == "FASTLYPURGE" ) {
		set req.http.Fastly-Purge-Requires-Auth = "1";
	}

	if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
		return(pass);
	}

	if (!req.http.Fastly-SSL && (req.http.Host == "cdn.polyfill.io" || req.http.Host == "polyfill.io")) {
		error 751 "Canonicalise";
	}

	if (req.http.Host ~ "polyfills.io") {
		error 751 "Canonicalise";
	}

	if (req.url ~ "^/v2/(polyfill\.|recordRumData)" && req.url !~ "[\?\&]ua=") {
		set req.http.X-Orig-URL = req.url;
		set req.url = "/v2/normalizeUa?ua=" urlencode(req.http.User-Agent);
	}

	if (req.url ~ "^/v2/recordRumData" && req.http.Normalized-User-Agent) {
		set req.http.Log = regsub(req.url, "^.*?\?(.*)$", "\1") "&ip=" client.ip "&refer_domain=" regsub(req.http.Referer, "^(https?\:\/\/)?(www\.)?(.+?)(\:\d+)?([\/\?].*)?$", "\3") "&country=" geoip.country_code "&data_center=" if(req.http.Cookie:FastlyDC, req.http.Cookie:FastlyDC, server.datacenter);
		error 204 "No Content";
	}

	set req.url = boltsort.sort(req.url);

	return(lookup);
}

sub vcl_deliver {
#FASTLY deliver

	# If the response is to a normalise request and there's a parked "original request", use the normalised UA response to modify the original request and restart it
	if (req.url ~ "^/v\d/normalizeUa" && resp.status == 200 && req.http.X-Orig-URL ~ "^/v2/(polyfill\.|recordRumData)") {
		set req.http.Fastly-force-Shield = "1";
		set req.http.Normalized-User-Agent = resp.http.Normalized-User-Agent;
		if (req.http.X-Orig-URL ~ "\?") {
			set req.url = req.http.X-Orig-URL "&ua=" resp.http.Normalized-User-Agent;
		} else {
			set req.url = req.http.X-Orig-URL "?ua=" resp.http.Normalized-User-Agent;
		}
		restart;

	# If the original request didn't specify a UA override, and we added one when the request was sent to the backend, the backend won't have included a Vary:user-agent header (correctly) but we need to add one
	} else if (req.url ~ "^/v\d/polyfill\..*[\?\&]ua=" && req.http.X-Orig-URL && req.http.X-Orig-URL !~ "[\?\&]ua=") {
		add resp.http.Vary = "User-Agent";
	}

	if (req.url ~ "[\&\?]rum=1") {
		add resp.http.Set-Cookie = "FastlyDC=" server.datacenter "; Path=/; HttpOnly; max-age=60";
	}

	return(deliver);
}

sub vcl_error {

	# Redirect to SSL
	if (obj.status == 751) {
		set obj.status = 301;
		set obj.response = "Moved Permanently";
		set obj.http.Location = "https://polyfill.io" req.url;
		synthetic {""};
		return (deliver);
	}
}

import boltsort;

sub vcl_recv {
#FASTLY recv
	if ( req.request == "FASTLYPURGE" ) {
		set req.http.Fastly-Purge-Requires-Auth = "1";
	}

	if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
		return(pass);
	}

	if (!req.http.Fastly-SSL && (req.http.Host == "cdn.polyfill.io" || req.http.Host == "polyfill.io")) {
		error 751 "Force TLS";
	}

	if (req.url ~ "^/v2/(polyfill\.|recordRumData)" && req.url !~ "[\?\&]ua=") {
		set req.http.X-Orig-URL = req.url;
		set req.url = "/v2/normalizeUa?ua=" urlencode(req.http.User-Agent);
	}

	if (req.url ~ "^/v2/recordRumData" && req.http.Normalized-User-Agent) {
		set req.http.Log = regsub(req.url, "^.*?\?(.*)$", "\1") "&ip=" client.ip "&refer_domain=" regsub(req.http.Referer, "^(https?\:\/\/)?(www\.)?(.+?)(\:\d+)?([\/\?].*)?$", "\3") "&country=" geoip.country_code "&data_center=" if(req.http.Cookie:FastlyDC, req.http.Cookie:FastlyDC, server.datacenter);
		error 204 "No Content";
	}

	set req.url = boltsort.sort(req.url);

	return(lookup);
}

sub vcl_deliver {
#FASTLY deliver

	# If the response is to a normalise request and there's a parked "original request", use the normalised UA response to modify the original request and restart it
	if (req.url ~ "^/v\d/normalizeUa" && resp.status == 200 && req.http.X-Orig-URL ~ "^/v2/(polyfill\.|recordRumData)") {
		set req.http.Fastly-force-Shield = "1";
		set req.http.Normalized-User-Agent = resp.http.Normalized-User-Agent;
		if (req.http.X-Orig-URL ~ "\?") {
			set req.url = req.http.X-Orig-URL "&ua=" resp.http.Normalized-User-Agent;
		} else {
			set req.url = req.http.X-Orig-URL "?ua=" resp.http.Normalized-User-Agent;
		}
		restart;

	# If the original request didn't specify a UA override, and we added one when the request was sent to the backend, the backend won't have included a Vary:user-agent header (correctly) but we need to add one
	} else if (req.url ~ "^/v\d/polyfill\..*[\?\&]ua=" && req.http.X-Orig-URL && req.http.X-Orig-URL !~ "[\?\&]ua=") {
		add resp.http.Vary = "User-Agent";
	}

	if (req.url ~ "[\&\?]rum=1") {
		add resp.http.Set-Cookie = "FastlyDC=" server.datacenter "; Path=/; HttpOnly; max-age=60";
	}

	return(deliver);
}

sub vcl_error {

	# Redirect to SSL
	if (obj.status == 751) {
		set obj.status = 301;
		set obj.response = "Moved Permanently";
		set obj.http.Location = "https://" req.http.host req.url;
		synthetic {""};
		return (deliver);
	}
}


#85: Don't remove etags in vcl_backend_response

vcl 4.0;

# This Varnish configuration is a very basic template to get started with caching Joomla sites.
# In no way is this configuration complete: every site is unique and needs customisation!
# For demonstration purposes this VCL will cache all front-end pages (including pages with cookies).

import std;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = {
      .url = "/varnish-enabled";
      .interval = 1s;
      .timeout = 1s;
    }
}

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

sub vcl_recv {
        # Forward client's IP to backend
        unset req.http.X-Forwarded-For;
        set req.http.X-Forwarded-For = client.ip;

        set req.http.X-Forwarded-By = server.ip;
        set req.http.X-Forwarded-Port = 80;

        # Check if we've still enabled Varnish, if not, passthrough every request
        set req.http.backend = "default";
        if (! std.healthy(req.backend_hint))
        {
            set req.backend_hint = alternative;
            set req.http.backend = "alternative";
            return (pass);
        }

        # Do not cache phpmyadmin
        if (req.http.host == "phpmyadmin.joomla.box") {
            return (pass);
        }

        # Do not cache system tools on joomla.box:
        if (req.http.host == "joomla.box")
        {
            if (req.url ~ "^/apc" || req.url ~ "^/phpinfo" || req.url ~ "^/pimpmylog" || req.url ~ "^/dashboard") {
                return (pass);
            }
        }

        # Do not cache ZendServer endpoint
        if (req.url ~ "^/ZendServer") {
            return (pass);
        }

        # Do not cache POST requests
        if (req.method == "POST") {
            return (pass);
        }

        # Proxy (pass) any request that goes to the backend admin, the banner component links, ..
        if(req.url ~ "/administrator" || req.url ~ "/component/banners" || req.url ~ "/component/users" || req.url ~ "/installation") {
            return (pass);
        }

        # Do not cache if user is logged in
        if (req.http.Authorization || req.http.Authenticate) {
            return (pass);
        }

        # Don't cache ajax requests
        if(req.http.X-Requested-With == "XMLHttpRequest" || req.url ~ "nocache") {
            return (pass);
        }

        # Properly handle different encoding types
        if (req.http.Accept-Encoding) {
          if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf)$") {
            # No point in compressing these
            unset req.http.Accept-Encoding;
          } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
          } elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
          } else {
            # unknown algorithm (aka crappy browser)
            unset req.http.Accept-Encoding;
          }
        }

        return (hash);
}

sub vcl_backend_response {
        if(bereq.http.backend == "alternative")
        {
            set beresp.uncacheable = true;

            return(deliver);
        }

        # This is Joomla! specific: fix stupid "no-cache" header sent by Joomla! even
        # when caching is on - make sure to replace 300 with the number of seconds that
        # you want the browser to cache content
        if(beresp.http.Cache-Control ~ "no-cache" || beresp.http.Cache-Control == ""){
            set beresp.http.Cache-Control = "max-age=300, public, must-revalidate";
        }

        # Check for the custom "x-Logged-In" header to identify if the visitor is a guest,
        # then unset any cookie (including session cookies) provided it's not a POST request.
        if(bereq.method != "POST" && beresp.http.X-Logged-In == "false") {
            unset beresp.http.Set-Cookie;
        }

        # This is how long Varnish will cache content
        set beresp.ttl = 1w;

        return (deliver);
}

sub vcl_hash
{
    hash_data(req.url);

    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }

    # Hash cookies for requests that have them
    if (req.http.Cookie) {
        hash_data(req.http.Cookie);
    }
}

sub vcl_deliver {
        if (resp.http.x-varnish ~ " ") {
            set resp.http.X-Varnish-Status = "HIT";
        } else {
            set resp.http.X-Varnish-Status = "MISS";
        }

        # Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object
        # and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for details.
        # So take hits with a grain of salt
        set resp.http.X-Varnish-Hits = obj.hits;
}

vcl 4.0;

# This Varnish configuration is a very basic template to get started with caching Joomla sites.
# In no way is this configuration complete: every site is unique and needs customisation!
# For demonstration purposes this VCL will cache all front-end pages (including pages with cookies).

import std;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = {
      .url = "/varnish-enabled";
      .interval = 1s;
      .timeout = 1s;
    }
}

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

sub vcl_recv {
        # Forward client's IP to backend
        unset req.http.X-Forwarded-For;
        set req.http.X-Forwarded-For = client.ip;

        set req.http.X-Forwarded-By = server.ip;
        set req.http.X-Forwarded-Port = 80;

        # Check if we've still enabled Varnish, if not, passthrough every request
        set req.http.backend = "default";
        if (! std.healthy(req.backend_hint))
        {
            set req.backend_hint = alternative;
            set req.http.backend = "alternative";
            return (pass);
        }

        # Do not cache phpmyadmin
        if (req.http.host == "phpmyadmin.joomla.box") {
            return (pass);
        }

        # Do not cache system tools on joomla.box:
        if (req.http.host == "joomla.box")
        {
            if (req.url ~ "^/apc" || req.url ~ "^/phpinfo" || req.url ~ "^/pimpmylog" || req.url ~ "^/dashboard") {
                return (pass);
            }
        }

        # Do not cache ZendServer endpoint
        if (req.url ~ "^/ZendServer") {
            return (pass);
        }

        # Do not cache POST requests
        if (req.method == "POST") {
            return (pass);
        }

        # Proxy (pass) any request that goes to the backend admin, the banner component links, ..
        if(req.url ~ "/administrator" || req.url ~ "/component/banners" || req.url ~ "/component/users" || req.url ~ "/installation") {
            return (pass);
        }

        # Do not cache if user is logged in
        if (req.http.Authorization || req.http.Authenticate) {
            return (pass);
        }

        # Don't cache ajax requests
        if(req.http.X-Requested-With == "XMLHttpRequest" || req.url ~ "nocache") {
            return (pass);
        }

        # Properly handle different encoding types
        if (req.http.Accept-Encoding) {
          if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf)$") {
            # No point in compressing these
            unset req.http.Accept-Encoding;
          } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
          } elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
          } else {
            # unknown algorithm (aka crappy browser)
            unset req.http.Accept-Encoding;
          }
        }

        return (hash);
}

sub vcl_backend_response {
        if(bereq.http.backend == "alternative")
        {
            set beresp.uncacheable = true;

            return(deliver);
        }

        # Unset the "etag" header (suggested)
        unset beresp.http.etag;

        # This is Joomla! specific: fix stupid "no-cache" header sent by Joomla! even
        # when caching is on - make sure to replace 300 with the number of seconds that
        # you want the browser to cache content
        if(beresp.http.Cache-Control ~ "no-cache" || beresp.http.Cache-Control == ""){
            set beresp.http.Cache-Control = "max-age=300, public, must-revalidate";
        }

        # Check for the custom "x-Logged-In" header to identify if the visitor is a guest,
        # then unset any cookie (including session cookies) provided it's not a POST request.
        if(bereq.method != "POST" && beresp.http.X-Logged-In == "false") {
            unset beresp.http.Set-Cookie;
        }

        # This is how long Varnish will cache content
        set beresp.ttl = 1w;

        return (deliver);
}

sub vcl_hash
{
    hash_data(req.url);

    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }

    # Hash cookies for requests that have them
    if (req.http.Cookie) {
        hash_data(req.http.Cookie);
    }
}

sub vcl_deliver {
        if (resp.http.x-varnish ~ " ") {
            set resp.http.X-Varnish-Status = "HIT";
        } else {
            set resp.http.X-Varnish-Status = "MISS";
        }

        # Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object
        # and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for details.
        # So take hits with a grain of salt
        set resp.http.X-Varnish-Hits = obj.hits;
}


Renamed variables; fixed unset bug

Renamed variables; fixed unset bug

table consumer_secrets {
	"foo": "super_secret"
}

table access_tokens {
	"bar": "token_secret"
}

sub vcl_recv {
#FASTLY recv
#DEPLOY recv
	set req.http.X-OAuth-Consumer-Key = if(req.url ~ "(?i)oauth_consumer_key=([^&]*)", urldecode(re.group.1), "");
	if(req.http.X-OAuth-Consumer-Key == "") {
		error 401 "Missing Consumer Key";
	}
	set req.http.X-OAuth-Consumer-Secret = table.lookup(consumer_secrets, req.http.X-OAuth-Consumer-Key);
	if(!req.http.X-OAuth-Consumer-Secret) {
		error 401 "Invalid Consumer Key";
	}
	set req.http.X-OAuth-Access-Token = if(req.url ~ "(?i)oauth_token=([^&]*)", urldecode(re.group.1), "");
	if(req.http.X-OAuth-Access-Token != "") {
		set req.http.X-OAuth-Access-Token-Secret = table.lookup(access_tokens, req.http.X-OAuth-Access-Token);
		if(!req.http.X-OAuth-Access-Token-Secret) {
			error 401 "Invalid Access Token";
		}
	} else {
		set req.http.X-OAuth-Access-Token-Secret = "";
	}
	set req.http.X-OAuth-Provided-Signature = if(req.url ~ "(?i)oauth_signature=([^&]*)", urldecode(re.group.1), "");
	if(req.http.X-OAuth-Provided-Signature == "") {
		error 401 "Missing Signature";
	}
	set req.http.X-OAuth-Ordered-Url = boltsort.sort(req.url);
	set req.http.X-OAuth-Parameters = regsub(regsub(req.http.X-OAuth-Ordered-Url, ".*\?", ""), "&oauth_signature=[^&]*", "");
	set req.http.X-OAuth-Base-String-Uri =
		if(req.http.Fastly-SSL, "https", "http")
		"://"
		std.tolower(req.http.host)
		req.url.path;
	set req.http.X-OAuth-Signature-Base-String =
		req.request
		"&"
		urlencode(req.http.X-OAuth-Base-String-Uri)
		"&"
		urlencode(req.http.X-OAuth-Parameters);

	set req.http.X-OAuth-Calculated-Signature = digest.hmac_sha1_base64(
			req.http.X-OAuth-Consumer-Secret "&" req.http.X-OAuth-Access-Token-Secret,
			req.http.X-OAuth-Signature-Base-String);

	unset req.http.X-OAuth-Consumer-Secret;
	unset req.http.X-OAuth-Access-Token-Secret;
	unset req.http.X-OAuth-Base-String-Uri;

	if(req.http.X-OAuth-Provided-Signature != req.http.X-OAuth-Calculated-Signature) {
		error 401 "Invalid OAuth Signature";
	}

	error 200 "Authenticated!";

	return(lookup);
}

sub vcl_fetch {
#FASTLY fetch
	return(deliver);
}

sub vcl_hit {
#FASTLY hit
	if (!obj.cacheable) {
		return(pass);
	}
	return(deliver);
}

sub vcl_miss {
#FASTLY miss
	return(fetch);
}

sub vcl_deliver{
#FASTLY deliver
	# Expose variables for debugging
	set resp.http.X-OAuth-Consumer-Key = req.http.X-OAuth-Consumer-Key;
	set resp.http.X-OAuth-Access-Token = req.http.X-OAuth-Access-Token;
	set resp.http.X-OAuth-Provided-Signature = req.http.X-OAuth-Provided-Signature;
	set resp.http.X-OAuth-Calculated-Signature = req.http.X-OAuth-Calculated-Signature;
	set resp.http.X-OAuth-Parameters = req.http.X-OAuth-Parameters;
	set resp.http.X-OAuth-Signature-Base-String = req.http.X-OAuth-Signature-Base-String;
	return(deliver);
}

sub vcl_error {
#FASTLY error
#DEPLOY error
}

sub vcl_pass {
#FASTLY pass
}

table consumer_secrets {
	"foo": "super_secret"
}

table access_tokens {
	"bar": "token_secret"
}

sub vcl_recv {
#FASTLY recv
#DEPLOY recv
	set req.http.X-Consumer-Key = if(req.url ~ "(?i)oauth_consumer_key=([^&]*)", urldecode(re.group.1), "");
	if(req.http.X-Consumer-Key == "") {
		error 401 "Missing Consumer Key";
	}
	set req.http.X-Consumer-Secret = table.lookup(consumer_secrets, req.http.X-Consumer-Key);
	if(!req.http.X-Consumer-Secret) {
		error 401 "Invalid Consumer Key";
	}
	set req.http.X-Access-Token = if(req.url ~ "(?i)oauth_token=([^&]*)", urldecode(re.group.1), "");
	if(req.http.X-Access-Token != "") {
		set req.http.X-Access-Token-Secret = table.lookup(access_tokens, req.http.X-Access-Token);
		if(!req.http.X-Access-Token-Secret) {
			error 401 "Invalid Access Token";
		}
	} else {
		set req.http.X-Access-Token-Secret = "";
	}
	set req.http.X-Provided-Signature = if(req.url ~ "(?i)oauth_signature=([^&]*)", urldecode(re.group.1), "");
	if(req.http.X-Provided-Signature == "") {
		error 401 "Missing Signature";
	}
	set req.http.X-Ordered-Url = boltsort.sort(req.url);
	set req.http.X-Parameters = regsub(regsub(req.http.X-Ordered-Url, ".*\?", ""), "&oauth_signature=[^&]*", "");
	set req.http.X-Base-String-Uri =
		if(req.http.Fastly-SSL, "https", "http")
		"://"
		std.tolower(req.http.host)
		req.url.path;
	set req.http.X-Signature-Base-String =
		req.request
		"&"
		urlencode(req.http.X-Base-String-Uri)
		"&"
		urlencode(req.http.X-Parameters);

	set req.http.X-Calculated-Signature = digest.hmac_sha1_base64(
			req.http.X-Consumer-Secret "&" req.http.X-Access-Token-Secret,
			req.http.X-Signature-Base-String);

	unset req.http.X-Consumer-Secret;
	unset req.http.X-Access-Token-Scret;
	unset req.http.X-Base-String-Uri;

	if(req.http.X-Provided-Signature != req.http.X-Calculated-Signature) {
		error 401 "Invalid OAuth Signature";
	}

	error 200 "Authenticated!";

	return(lookup);
}

sub vcl_fetch {
#FASTLY fetch
	return(deliver);
}

sub vcl_hit {
#FASTLY hit
	if (!obj.cacheable) {
		return(pass);
	}
	return(deliver);
}

sub vcl_miss {
#FASTLY miss
	return(fetch);
}

sub vcl_deliver{
#FASTLY deliver
	set resp.http.X-Consumer-Key = req.http.X-Consumer-Key;
	set resp.http.X-Access-Token = req.http.X-Access-Token;
	set resp.http.X-Provided-Signature = req.http.X-Provided-Signature;
	set resp.http.X-Calculated-Signature = req.http.X-Calculated-Signature;
	set resp.http.X-Parameters = req.http.X-Parameters;
	set resp.http.X-Signature-Base-String = req.http.X-Signature-Base-String;
	return(deliver);
}

sub vcl_error {
#FASTLY error
#DEPLOY error
}

sub vcl_pass {
#FASTLY pass
}