Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Advanced fiddle workshop

Avatar for Andrew Betts Andrew Betts
September 15, 2020

Advanced fiddle workshop

Avatar for Andrew Betts

Andrew Betts

September 15, 2020
Tweet

More Decks by Andrew Betts

Other Decks in Technology

Transcript

  1. 3 ©2019 VCL state machine Your programmable journey through Fastly's

    varnish RECV MISS HIT PASS FETCH DELIVER ERROR Receive request Deliver response Cache lookup Backend fetch LOG
  2. 4 ©2019 We're working to bring WASM to Fastly Maintaining

    the speed of native code at the edge VCL TypeScript sub vcl_recv { if (!req.http.flags) { set req.http.tmpOrigUrl = req.url; set req.backend = F_PREFLIGHT_ORIGIN; set req.url = "/api/flags"; } else { set req.backend = F_CONTENT_ORIGIN; } } sub vcl_deliver { if (resp.http.flags) { set req.http.flags = resp.http.flags; set req.url = req.http.tmpOrigUrl; unset req.http.tmpOrigUrl; restart; } } function recv(req: Request): Response { let pfReq = new Request("GET", F_PREFLIGHT_ORIGIN + "/api/flags" ); let pfResp = pfReq.send(); let req = new Request("GET", F_CONTENT_ORIGIN + req.url ); req.set_header("flags", pfResp.get_header("flags") ); let resp = bereq.send(); return resp; }
  3. 6 ©2019 Solution Fiddle features Vanilla service (no edge logic)

    Instrumentation; Server identification; Insights Image optimisation Shielding; Image output Geofencing Autocomplete; Header highlighting A/B testing Multiple requests; Cookie jar; Logging Conditional revalidation Surrogate keys; Clustering; timing metrics Threat intelligence Restarts; Synthetic responses; POST to GET rewriting GCS backend Follow redirects; Unit tests Solutions we will build today Learn about Fiddle, learn about cool things to do with Fastly too
  4. 7 ©2019 Warning: • Everything you enter into Fiddle is

    public • Deploying code to thousands of servers is not instantaneous. Please be patient! • We suggest you do each exercise in a different tab, so you still have them all to refer to at the end. • Ask Fastly helpers if you get stuck
  5. 9 ©2019 Vanilla service What does Fastly do just by

    default? 1. Open fiddle.fastlydemo.net in a new tab 2. Give it a title, eg "Exercise 1: Vanilla" 3. When the RUN button goes blue, click it
  6. 11 ©2019 Image optimisation Use the Fastly IO service to

    transform your images automatically Cache transformed image Process into desired format Cache original image
  7. 12 ©2019 Image optimisation Use the Fastly IO service to

    transform your images automatically 1. Open fiddle.fastlydemo.net in a new tab 2. Give it a title, eg "Exercise 2: Image optimisation" 3. Set the origin server to https://triblondon.github.io 4. Set the request path to /fastly-fiddle-examples/images/obama2.jpg 5. Enable Shielding in the Options menu 6. Add the following VCL to RECV: set req.http.X-Fastly-Imageopto-Api = "fastly"; 7. When the RUN button lights up, click it!
  8. 13 ©2019 Image optimisation Use the Fastly IO service to

    transform your images automatically 8. Add ?width=300 to the query string and RUN again 9. Add &crop=16:9 to the query string and RUN again 10. Change crop=16:9 to crop=16:9,smart and RUN again
  9. 16 ©2019 Geolocation Add Fastly-provided geolocation variables to a request

    1. Open fiddle.fastlydemo.net in a new tab 2. Give it a title, eg "Exercise 3: Geolocation" 3. Add the following VCL to RECV: set req.http.client-geo-continent = client.geo.continent_code; set req.http.client-geo-country = client.geo.country_code; set req.http.edge-geo-datacenter = server.datacenter; set req.http.client-source-network = client.as.number; 4. Set the request path to: /response-headers?Vary=client-geo-country 5. When the RUN button lights up, click it!
  10. 18 ©2019 A/B testing Select and assign buckets at the

    edge to cache test variations + added test bucket info + Vary on response
  11. 19 ©2019 A/B testing Select and assign buckets at the

    edge to cache test variations 0 100 0 100 hash(<userid> + "header") = 53 hash(<userid> + "buttonSize") = 87 "small" "medium" "large" "normal" "cute" buttonSize = "large"; header = "cute"
  12. 20 ©2019 A/B testing Select and assign buckets at the

    edge to cache test variations 1. Open fiddle.fastlydemo.net 2. Add a title, eg "Exercise 4: A/B testing" 3. Set origin server (replacing httpbin) to: https://fiddle-ab.glitch.me 4. Set the request path to: /article/kittens 5. In VCL_RECV, assign a User ID: set req.http.ab = if ( req.http.Cookie:ab, req.http.Cookie:ab, uuid.version4() ); 6. In VCL_DELIVER, save the User ID into a cookie: if (!req.http.Cookie:ab) { add resp.http.Set-Cookie = "" "ab=" req.http.ab "; " "max-age=31536000; " "path=/; secure" ; set resp.http.Cache-Control = "" "no-store" ; } 7. Click and choose "Add another" to copy the request
  13. 22 ©2019 A/B testing Select and assign buckets at the

    edge to cache test variations 7. In VCL_RECV, calculate the first bucket assignment: declare local var.testKey STRING; declare local var.userTestSlot INTEGER; set var.testKey = req.http.ab "header"; set var.userTestSlot = fastly.hash(var.testKey, 0, 1, 100); set req.http.ab-header = if ( var.userTestSlot <= 50, "normal", "cute" );
  14. 23 ©2019 A/B testing Select and assign buckets at the

    edge to cache test variations 8. In VCL_RECV, add a second bucket assignment: set var.testKey = req.http.ab "buttonSize"; set var.userTestSlot = fastly.hash(var.testKey, 0, 1, 100); set req.http.ab-buttonSize = if (var.userTestSlot <= 20, "small", if (var.userTestSlot <= 30, "medium", "large" ));
  15. 25 ©2019 Conditional revalidations Minimize traffic to origin Conditional GET

    304 Not Modified GET /thing GET /thing GET /thing 200 OK Normal GET HIT
  16. 26 ©2019 Conditional revalidation Keep a stale object in cache

    but revalidate with origin 1. Open fiddle.fastlydemo.net in a new tab 2. Give it a title, eg "Exercise 5: Conditional revalidation" 3. Set the request path to: /cache 4. Add the following VCL to FETCH: set beresp.ttl = 1s; return(deliver); 5. When the RUN button lights up, click it! 6. Wait a couple of seconds, and run it again.
  17. 28 ©2019 Conditional revalidation Fastly Edge can revalidate with a

    Fastly shield 7. Enable Shielding in the Options menu 8. Remove line 1 of FETCH and replace with a TTL based on whether we are on the edge or the shield: set beresp.ttl = 1s; if (req.backend.is_shield) { set beresp.ttl = 1s; } else { set beresp.ttl = 10s; } 9. When the RUN button lights up, SHIFT+click it (to run with empty cache) 10. Wait a couple of seconds (no more than that), and run it again.
  18. 31 ©2019 Wrapping up Like a gift parcel of VCL

    goodness • Explore more solutions at fastly.com/demos • Try Fiddle yourself at fiddle.fastlydemo.net • Got something good? Let us know in community.fastly.com or email me: [email protected].
  19. 32 ©2019 Thank you! Andrew Betts Tweet me at @triblondon

    [email protected] These slides are published at fastly.us/advanced-fiddle
  20. 33 ©2019 GCS backend Use Google Cloud Storage to host

    your website more flexibly /resources /resources 404 Not Found /resources/index.html 200 OK 308 Redirect /resources/ 200 OK /resources/index.html
  21. 34 ©2019 GCS Backend Use Google Cloud Storage to host

    your website more flexibly 1. Open fiddle.fastlydemo.net in a new tab 2. Give it a title, eg "Exercise 7: GCS backend" 3. Replace the origin with: https://storage.googleapis.com 4. Change the request path to: /resources 5. Under request options, enable Follow Redirects 6. Add the bucket prefix in RECV: if (req.restarts == 0) { set req.http.orig-req-url = req.url; set req.url = "/betts-gcp-gcs-fastly-tutorial" req.url; }
  22. 35 ©2019 GCS Backend Use Google Cloud Storage to host

    your website more flexibly 7. Still in RECV, add the index file suffix if the requested path is a directory: if (req.url ~ "\/$") { set req.url = req.url "index.html"; } 8. In DELIVER, detect when GCS says 'not found' for a non-directory path: if (resp.status == 404 && req.url !~ "\/index.html$") { set req.http.retry-for-dir = "1"; restart; } 9. Back in the middle of RECV, try appending a / to paths if we're retrying for a directory if (req.http.retry-for-dir) { set req.url = req.url "/"; }
  23. 36 ©2019 GCS Backend Use Google Cloud Storage to host

    your website more flexibly 10. In FETCH, detect a successful response for a retry if (beresp.status == 200 && req.url ~ "\/index.html$" && req.http.retry-for-dir) { error 901; } 11. In ERROR, create the appropriate redirect if the retry succeeded: if (obj.status == 901) { set obj.status = 308; set obj.response = "Permanent redirect"; set obj.http.Location = req.http.orig-req-url "/"; synthetic ""; return(deliver); }
  24. 38 ©2019 Threat intelligence Call out to an API to

    assess a risky request before sending it to origin Check with threat intel API Receive verdict Send request to normal origin
  25. 39 ©2019 Threat intelligence Call out to an API to

    assess a risky request before sending it to origin 1. Open fiddle.fastlydemo.net in a new tab 2. Give it a title, eg "Exercise 6: Threat intelligence" 3. Add an extra origin (in addition to httpbin): https://us-central1-rd---product.cloudfunctions.net 4. Change the request path to: /post 5. Set the request method to POST 6. Add the following to the body data: username=andrew&password=apple
  26. 40 ©2019 Threat intelligence Call out to an API to

    assess a risky request before sending it to origin 7. Intercept risky requests in RECV and divert to the threat intel API: declare local var.cred STRING; set var.cred = subfield(req.postbody, "password", "&"); if (req.method == "POST" && var.cred && !req.http.TI-Result) { set req.backend = F_origin_1; set req.http.Orig-URL = req.url; set req.http.Orig-Method = req.method; set req.http.TI-Key = digest.hash_sha1(var.cred); set req.url = "/threatIntelPOC?key=" substr(req.http.TI-Key, 0, 6); set req.method = "GET"; log "Cred: " var.cred ", key: " req.http.TI-Key; }
  27. 41 ©2019 Threat intelligence Call out to an API to

    assess a risky request before sending it to origin 8. Capture the threat response in DELIVER: if (req.http.TI-Key && req.restarts == 0) { if (std.strstr(resp.http.Result, substr(req.http.TI-Key, 6))) { log "Credential is a known threat"; set req.http.TI-Result = "FAIL"; } else { log "Credential is OK"; set req.http.TI-Result = "PASS"; } restart; }
  28. 42 ©2019 Threat intelligence Call out to an API to

    assess a risky request before sending it to origin 9. Back in RECV, deal with restarted requests: if (req.http.TI-Result) { if (req.http.TI-Result != "PASS") { error 603; } else { set req.url = req.http.Orig-URL; set req.method = req.http.Orig-Method; } return (lookup); }
  29. 43 ©2019 Threat intelligence Call out to an API to

    assess a risky request before sending it to origin 10. Create the appropriate failure response synthetically in ERROR: if (obj.status == 603) { set obj.status = 403; set obj.response = "Forbidden"; set obj.http.content-type = "text/plain"; synthetic "Please contact us for assistance logging in"; return (deliver); } 11. Cleanup temporary headers in MISS: unset bereq.http.TI-Result; unset bereq.http.TI-Key; unset bereq.http.Orig-URL; unset bereq.http.Orig-Method;
  30. 45 ©2019 Threat intelligence Call out to an API to

    assess a risky request before sending it to origin 12. Try changing password to something that isn't compromised username=andrew&password=apple-horse-coffee-tulip 13. Try changing the request so it does not contain a password field: username=andrew