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

Comment utiliser les meilleures pratiques d’HTT...

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for Thijs Feryn Thijs Feryn
November 16, 2017

Comment utiliser les meilleures pratiques d’HTTP pour mettre en cache votre site web - LaFéWeb 17

My very first presentation in French, delivered at a La FéWeb meetup in Louvain-la-Neuve.

More info: https://feryn.eu/speaking/comment-utiliser-les-meilleures-pratiques-dhttp-pour-mettre-en-cache-votre-site-web/

Avatar for Thijs Feryn

Thijs Feryn

November 16, 2017
Tweet

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. HTTP caching mechanisms Expires: Sat, 09 Sep 2017 14:30:00 GMT

    Cache-control: public, max-age=3600, s-maxage=86400 Cache-control: private, no-cache, no-store
  2. <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/html">
 <head>
 <title>{% block title %}{% endblock

    %} - Developing cacheable websites</title>
 <meta name="viewport" content="width=device-width, initial-scale=1.0” />
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <link rel="stylesheet" href="/css/bootstrap.min.css" />
 <script src=“/js/jquery.min.js"></script>
 </head>
 <body>
 <div class="container-fluid">
 {{ include('header.twig') }}
 <div class="row">
 <div class="col-sm-3 col-lg-2">
 {{ include('nav.twig') }}
 </div>
 <div class="col-sm-9 col-lg-10">
 {% block content %}{% endblock %}
 </div>
 </div>
 {{ include('footer.twig') }}
 </div>
 </body>
 </html> Base template
  3. Conditional requests HTTP/1.1 200 OK Host: localhost Etag: 7c9d70604c6061da9bb9377d3f00eb27 Content-type:

    text/html; charset=UTF-8 Hello world output GET / HTTP/1.1 Host: localhost User-Agent: curl/7.48.0
  4. Conditional requests HTTP/1.0 304 Not Modified Host: localhost Etag: 7c9d70604c6061da9bb9377d3f00eb27

    GET / HTTP/1.1 Host: localhost User-Agent: curl/7.48.0 If-None-Match: 7c9d70604c6061da9bb9377d3f00eb27
  5. Conditional requests HTTP/1.1 200 OK Host: localhost Last-Modified: Fri, 22

    Jul 2016 10:11:16 GMT Content-type: text/html; charset=UTF-8 Hello world output GET / HTTP/1.1 Host: localhost User-Agent: curl/7.48.0
  6. Conditional requests HTTP/1.0 304 Not Modified Host: localhost Last-Modified: Fri,

    22 Jul 2016 10:11:16 GMT GET / HTTP/1.1 Host: localhost User-Agent: curl/7.48.0 If-Last-Modified: Fri, 22 Jul 2016 10:11:16 GMT
  7. <esi:include src="/header" /> Edge Side Includes ✓Placeholder ✓Parsed by Varnish

    ✓Output is a composition of blocks ✓State per block ✓TTL per block
  8. ✓ Server-side ✓ Standardized ✓ Processed on the “edge”, no

    in the browser ✓ Generally faster Edge-Side Includes - Sequential - One fails, all fail - Limited implementation in Varnish
  9. ✓ Client-side ✓ Common knowledge ✓ Parallel processing ✓ Graceful

    degradation AJAX - Processed by the browser - Extra roundtrips - Somewhat slower
  10. <div class="container-fluid">
 {{ include('header.twig') }}
 <div class="row">
 <div class="col-sm-3 col-lg-2">


    {{ include('nav.twig') }}
 </div>
 <div class="col-sm-9 col-lg-10">
 {% block content %}{% endblock %}
 </div>
 </div>
 {{ include('footer.twig') }}
 </div> <div class="container-fluid">
 {{ render_esi(url('header')) }}
 <div class="row">
 <div class="col-sm-3 col-lg-2">
 {{ render_esi(url('nav')) }}
 </div>
 <div class="col-sm-9 col-lg-10">
 {% block content %}{% endblock %}
 </div>
 </div>
 {{ render_hinclude(url('footer')) }}
 </div>
  11. <div class="container-fluid"> <esi:include src="/header" /> <div class="row"> <div class="col-sm-3 col-lg-2">

    <esi:include src="/nav" /> </div> <div class="col-sm-9 col-lg-10"> <div class="page-header"> <h1>An example page <small>Rendered at 2017-05-17 16:57:14</small></h1> </div> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris consequat orci eget libero sollicitudin,…</p> </div> </div> <hx:include src="/footer"></hx:include> </div>
  12. eyJzdWIiOiJhZG1pbiIsIm V4cCI6MTQ5NTUyODc1Niwi bG9naW4iOnRydWV9 { "alg": "HS256", "typ": "JWT" } {

    "sub": "admin", "exp": 1495528756, "login": true } HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret ) eyJhbGciOiJIUzI1NiIsI nR5cCI6IkpXVCJ9 u4Idy- SYnrFdnH1h9_sNc4OasOR BJcrh2fPo1EOTre8
  13. sub jwt { std.log("Ready to perform some JWT magic"); if(cookie.isset("jwt_cookie"))

    { #Extract header data from JWT var.set("token", cookie.get("jwt_cookie")); var.set("header", regsub(var.get("token"),"([^\.]+)\.[^\.]+\.[^\.]+","\1")); var.set("type", regsub(digest.base64url_decode(var.get("header")),{"^.*?"typ"\s*:\s*"(\w+)".*?$"},"\1")); var.set("algorithm", regsub(digest.base64url_decode(var.get("header")),{"^.*?"alg"\s*:\s*"(\w+)".*?$"},"\1")); #Don't allow invalid JWT header if(var.get("type") == "JWT" && var.get("algorithm") == "HS256") { #Extract signature & payload data from JWT var.set("rawPayload",regsub(var.get("token"),"[^\.]+\.([^\.]+)\.[^\.]+$","\1")); var.set("signature",regsub(var.get("token"),"^[^\.]+\.[^\.]+\.([^\.]+)$","\1")); var.set("currentSignature",digest.base64url_nopad_hex(digest.hmac_sha256(var.get("key"),var.get("header") + "." + var.get("rawPayload")))); var.set("payload", digest.base64url_decode(var.get("rawPayload"))); var.set("exp",regsub(var.get("payload"),{"^.*?"exp"\s*:\s*([0-9]+).*?$"},"\1")); var.set("jti",regsub(var.get("payload"),{"^.*?"jti"\s*:\s*"([a-z0-9A-Z_\-]+)".*?$"},"\1")); var.set("userId",regsub(var.get("payload"),{"^.*?"uid"\s*:\s*"([0-9]+)".*?$"},"\1")); var.set("roles",regsub(var.get("payload"),{"^.*?"roles"\s*:\s*"([a-z0-9A-Z_\-, ]+)".*?$"},"\1")); #Only allow valid userId if(var.get("userId") ~ "^\d+$") { #Don't allow expired JWT if(std.time(var.get("exp"),now) >= now) { #SessionId should match JTI value from JWT if(cookie.get(var.get("sessionCookie")) == var.get("jti")) { #Don't allow invalid JWT signature if(var.get("signature") == var.get("currentSignature")) { #The sweet spot set req.http.X-login="true"; } else { std.log("JWT: signature doesn't match. Received: " + var.get("signature") + ", expected: " + var.get("currentSignature")); } } else { std.log("JWT: session cookie doesn't match JTI." + var.get("sessionCookie") + ": " + cookie.get(var.get("sessionCookie")) + ", JTI:" + var.get("jti")); } } else { std.log("JWT: token has expired"); } } else { std.log("UserId '"+ var.get("userId") +"', is not numeric"); } } else { std.log("JWT: type is not JWT or algorithm is not HS256"); } std.log("JWT processing finished. UserId: " + var.get("userId") + ". X-Login: " + req.http.X-login); } #Look for full private content if(req.url ~ "/node/2" && req.url !~ "^/user/login") { if(req.http.X-login != "true") { return(synth(302,"/user/login?destination=" + req.url)); } } } Insert incomprehensible Varnish VCL code here …
  14. <script language="JavaScript">
 function getCookie(name) {
 var value = "; "

    + document.cookie;
 var parts = value.split("; " + name + "=");
 if (parts.length == 2) return parts.pop().split(";").shift();
 }
 function parseJwt (token) {
 var base64Url = token.split('.')[1];
 var base64 = base64Url.replace('-', '+').replace('_', '/');
 return JSON.parse(window.atob(base64));
 };
 $(document).ready(function(){
 if ($.cookie('token') != null ){
 var token = parseJwt($.cookie("token"));
 $("#usernameLabel").html(', ' + token.sub);
 }
 });
 </script> Parse JWT in Javascript