Browse code

webkernel: add etag support (so the the browser can use cached pages)

Dario Rodriguez authored on 16/07/2014 13:27:49
Showing 2 changed files
... ...
@@ -31,6 +31,7 @@
31 31
 #define BUFBLOCKBLOCK 256
32 32
 #define POSTBLOCK 16
33 33
 #define ALIVETIMEOUT 15
34
+#define MAXETAGSIZE 127
34 35
 
35 36
 typedef struct wk_post {
36 37
         char *name;
... ...
@@ -67,6 +68,7 @@ typedef struct wk_client {
67 68
         int pendingpost;
68 69
         int inpostvar;
69 70
         int cookiebufid;
71
+        char etag[MAXETAGSIZE+1];
70 72
         time_t lastio;
71 73
 } wk_client;
72 74
 
... ...
@@ -117,6 +119,7 @@ static int wk_postadd(_wk *web, wk_client *client,char *varname, char *tofile);
117 119
 static int wk_postset(_wk *web, wk_client *client,char *varname, char *data, int datalen);
118 120
 static char *wk_postget(_wk *web, wk_client *client,char *varname, int *isfile);
119 121
 static int wk_postfree(_wk *web, wk_client *client);
122
+static int wk_etagnotmodified(_wk *web, wk_client *client);
120 123
 
121 124
 #ifdef WK_DEBUG_IO
122 125
 #define DEBUG_IN_PRE { int sbp=sbuf_count(in);
... ...
@@ -438,6 +441,22 @@ wk_serve_cookieadd(wk *paramweb, int connid, char *cookiename, char *value, char
438 441
         return(0);
439 442
 }
440 443
 
444
+int
445
+wk_serve_etagset(wk *paramweb, int connid, char *etag)
446
+{
447
+        _wk *web=(_wk *)paramweb;
448
+        wk_client *client;
449
+        if(web==NULL)
450
+                return(-1);
451
+        if((client=wk_clientget(web,connid))==NULL)
452
+                return(-1);
453
+        if(etag!=NULL) {
454
+                strncpy(client->etag,etag,sizeof(client->etag));
455
+                client->etag[sizeof(client->etag)-1]='\0';
456
+        } else
457
+                client->etag[0]='\0';
458
+        return(0);
459
+}
441 460
 
442 461
 int
443 462
 wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const char *mime)
... ...
@@ -447,28 +466,44 @@ wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const
447 466
         wk_client *client;
448 467
         char buf[256];
449 468
         sbuf *cookiebuf;
469
+        int cachedetag;
450 470
         if(web==NULL)
451 471
                 return(-1);
452 472
         if((client=wk_clientget(web,connid))==NULL)
453 473
                 return(-1);
454
-        wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n");
474
+        cachedetag=(wk_etagnotmodified(web,client)==0)?1:0;
475
+        if(!cachedetag)
476
+                wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n");
477
+        else
478
+                wk_writestr((wk *)web,connid,"HTTP/1.1 304 Not modified\r\n");
455 479
         if(client->cookiebufid!=-1 && (cookiebuf=wk_sbufget((wk *)web,client->cookiebufid))!=NULL) {
456 480
                 if(wk_write((wk *)web,connid,sbuf_getbytes(cookiebuf,sbuf_count(cookiebuf)),sbuf_count(cookiebuf))==-1 ||
457 481
                   sbuf_count(cookiebuf)!=0)
458 482
                         return(-1); /* insufficient memory */
459 483
                 wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1;
460 484
         }
461
-        sprintf(buf,"Content-Length: %i\r\n",datalen);
462
-        wk_writestr((wk *)web,connid,buf);
463
-        if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3))
464
-                sprintf(buf,"%s%s\r\n",strcontenttype,mime);
465
-        else
466
-                sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream");
467
-        wk_writestr((wk *)web,connid,buf);
485
+        if(!cachedetag) {
486
+                if(client->etag[0]!='\0') {
487
+                        sprintf(buf,"ETag: \"%s\"\r\n",client->etag);
488
+                        client->etag[0]='\0';
489
+                        wk_writestr((wk *)web,connid,buf);
490
+                }
491
+                sprintf(buf,"Content-Length: %i\r\n",datalen);
492
+                wk_writestr((wk *)web,connid,buf);
493
+                if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3))
494
+                        sprintf(buf,"%s%s\r\n",strcontenttype,mime);
495
+                else
496
+                        sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream");
497
+                wk_writestr((wk *)web,connid,buf);
498
+        } else {
499
+                wk_writestr((wk *)web,connid,"Content-Length: 0\r\n");
500
+        }
468 501
         if(client->keepalive)
469 502
                 wk_writestr((wk *)web,connid,"Connection: keep-alive\r\n");
470 503
         wk_writestr((wk *)web,connid,"\r\n");
471
-        return(wk_write((wk *)web,connid,data,datalen));
504
+        if(!cachedetag)
505
+                return(wk_write((wk *)web,connid,data,datalen));
506
+        return(0);
472 507
 }
473 508
 
474 509
 int
... ...
@@ -480,33 +515,47 @@ wk_serve_file(wk *paramweb, int connid, char *filename, const char *mime)
480 515
         char buf[256];
481 516
         sbuf *cookiebuf;
482 517
         struct stat st;
518
+        int cachedetag;
483 519
         if(web==NULL || filename==NULL)
484 520
                 return(-1);
485 521
         if((client=wk_clientget(web,connid))==NULL)
486 522
                 return(-1);
487 523
         if(client->fdtoserve!=-1)
488 524
                 close(client->fdtoserve),client->fdtoserve=-1;
489
-        if((client->fdtoserve=open(filename,O_RDONLY))==-1) {
490
-                wk_serve_error((wk *)web,connid,wkerr_notfound);
491
-                return(-1);
492
-        }
493
-        wk_writestr((wk *)web,connid,"HTTP/1.1 200 OK\r\n");
525
+        cachedetag=(wk_etagnotmodified(web,client)==0)?1:0;
526
+        if(!cachedetag) {
527
+                if((client->fdtoserve=open(filename,O_RDONLY))==-1) {
528
+                        wk_serve_error((wk *)web,connid,wkerr_notfound);
529
+                        return(-1);
530
+                }
531
+                wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n");
532
+        } else
533
+                wk_writestr((wk *)web,connid,"HTTP/1.1 304 Not modified\r\n");
494 534
         if(client->cookiebufid!=-1 && (cookiebuf=wk_sbufget((wk *)web,client->cookiebufid))!=NULL) {
495 535
                 if(wk_write((wk *)web,connid,sbuf_getbytes(cookiebuf,sbuf_count(cookiebuf)),sbuf_count(cookiebuf))==-1 ||
496 536
                   sbuf_count(cookiebuf)!=0)
497 537
                         return(-1); /* insufficient memory */
498 538
                 wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1;
499 539
         }
500
-        if(fstat(client->fdtoserve,&st)==0) {
501
-                sprintf(buf,"Content-Length: %lld\r\n",(long long)st.st_size);
540
+        if(!cachedetag) {
541
+                if(client->etag[0]!='\0') {
542
+                        sprintf(buf,"ETag: \"%s\"\r\n",client->etag);
543
+                        client->etag[0]='\0';
544
+                        wk_writestr((wk *)web,connid,buf);
545
+                }
546
+                if(fstat(client->fdtoserve,&st)==0) {
547
+                        sprintf(buf,"Content-Length: %lld\r\n",(long long)st.st_size);
548
+                        wk_writestr((wk *)web,connid,buf);
549
+                } else
550
+                        client->keepalive=0;
551
+                if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3))
552
+                        sprintf(buf,"%s%s\r\n",strcontenttype,mime);
553
+                else
554
+                        sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream");
502 555
                 wk_writestr((wk *)web,connid,buf);
503
-        } else
504
-                client->keepalive=0;
505
-        if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3))
506
-                sprintf(buf,"%s%s\r\n",strcontenttype,mime);
507
-        else
508
-                sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream");
509
-        wk_writestr((wk *)web,connid,buf);
556
+        } else {
557
+                wk_writestr((wk *)web,connid,"Content-Length: 0\r\n");
558
+        }
510 559
         if(client->keepalive)
511 560
                 wk_writestr((wk *)web,connid,"Connection: keep-alive\r\n");
512 561
         wk_writestr((wk *)web,connid,"\r\n");
... ...
@@ -1051,6 +1100,7 @@ wk_clientacquire(_wk *web)
1051 1100
         client->fdtoserve=-1;
1052 1101
         client->headerbufid=-1;
1053 1102
         client->cookiebufid=-1;
1103
+        client->etag[0]='\0';
1054 1104
         return(client);
1055 1105
 }
1056 1106
 
... ...
@@ -1225,6 +1275,9 @@ wk_clientservicereadheader(_wk *web, wk_client *client)
1225 1275
                 client->uriready=1;
1226 1276
                 client->continuationactive=0;
1227 1277
                 client->status=wkc_header;
1278
+                if(client->cookiebufid!=-1)
1279
+                        wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1;
1280
+                client->etag[0]='\0';
1228 1281
         }
1229 1282
         return(0);
1230 1283
 }
... ...
@@ -1431,4 +1484,21 @@ wk_postfree(_wk *web, wk_client *client)
1431 1484
         return(0);
1432 1485
 }
1433 1486
 
1487
+static int
1488
+wk_etagnotmodified(_wk *web, wk_client *client)
1489
+{
1490
+        char *h;
1491
+        int len;
1492
+        int etaglen;
1493
+        if(client->etag[0]=='\0')
1494
+                return(-1);
1495
+        if((h=wk_uri_getheader(&(client->uri),"If-None-Match",NULL))==NULL)
1496
+                return(-1);
1497
+        etaglen=strlen(client->etag);
1498
+        if((len=strlen(h))<2 || h[0]!='\"' || h[len-1]!='\"')
1499
+                return(-1);
1500
+        if((len-2)!=etaglen || memcmp(h+1,client->etag,etaglen)!=0)
1501
+                return(-1);
1502
+        return(0);
1503
+}
1434 1504
 
... ...
@@ -52,6 +52,7 @@ wk_uri *wk_geturi(wk *web, int connid); /* for use in callback_event() when wke_
52 52
 int wk_service(wk *web); /* To be called after sselelect_wait() but before sselect_getXXX() */
53 53
 
54 54
 int wk_serve_cookieadd(wk *web, int connid, char *cookiename, char *value, char *domain, int maxage, char *attributes);
55
+int wk_serve_etagset(wk *web, int connid, char *etag);
55 56
 int wk_serve_buffer_as_file(wk *web, int connid, void *data, int datalen, const char *mime);
56 57
 int wk_serve_file(wk *web, int connid, char *filename, const char *mime);
57 58
 int wk_serve_error(wk *web, int connid, wk_error wkerror);