@@ -14,8 +14,10 @@ import (
14
14
"log"
15
15
"mime"
16
16
"mime/multipart"
17
+ "net/http"
17
18
"net/url"
18
19
"path/filepath"
20
+ "regexp"
19
21
"strconv"
20
22
"strings"
21
23
"sync"
@@ -62,6 +64,7 @@ type Cookie struct {
62
64
// Global variables
63
65
var schemaDecoderForm = schema .NewDecoder ()
64
66
var schemaDecoderQuery = schema .NewDecoder ()
67
+ var cacheControlNoCacheRegexp , _ = regexp .Compile (`/(?:^|,)\s*?no-cache\s*?(?:,|$)/` )
65
68
66
69
// Ctx pool
67
70
var poolCtx = sync.Pool {
@@ -407,8 +410,59 @@ func (ctx *Ctx) FormValue(key string) (value string) {
407
410
}
408
411
409
412
// Fresh is not implemented yet, pull requests are welcome!
413
+ // https://github.com/jshttp/fresh/blob/10e0471669dbbfbfd8de65bc6efac2ddd0bfa057/index.js#L33
410
414
func (ctx * Ctx ) Fresh () bool {
411
- return false
415
+ // fields
416
+ var modifiedSince = ctx .Get (HeaderIfModifiedSince )
417
+ var noneMatch = ctx .Get (HeaderIfNoneMatch )
418
+
419
+ // unconditional request
420
+ if modifiedSince == "" && noneMatch == "" {
421
+ return false
422
+ }
423
+
424
+ // Always return stale when Cache-Control: no-cache
425
+ // to support end-to-end reload requests
426
+ // https://tools.ietf.org/html/rfc2616#section-14.9.4
427
+ var cacheControl = ctx .Get (HeaderCacheControl )
428
+ if cacheControl != "" && cacheControlNoCacheRegexp .MatchString (cacheControl ) {
429
+ return false
430
+ }
431
+
432
+ // if-none-match
433
+ if noneMatch != "" && noneMatch != "*" {
434
+ var etag = getString (ctx .Fasthttp .Response .Header .Peek (HeaderETag ))
435
+ if etag == "" {
436
+ return false
437
+ }
438
+ var etagStal = true
439
+ var matches = parseTokenList (getBytes (noneMatch ))
440
+ for _ , match := range matches {
441
+ if match == etag || match == "W/" + etag || "W/" + match == etag {
442
+ etagStal = false
443
+ break
444
+ }
445
+ }
446
+ if etagStal {
447
+ return false
448
+ }
449
+
450
+ if modifiedSince != "" {
451
+ var lastModified = getString (ctx .Fasthttp .Response .Header .Peek (HeaderLastModified ))
452
+ if lastModified != "" {
453
+ lastModifiedTime , err := http .ParseTime (lastModified )
454
+ if err != nil {
455
+ return false
456
+ }
457
+ modifiedSinceTime , err := http .ParseTime (modifiedSince )
458
+ if err != nil {
459
+ return false
460
+ }
461
+ return lastModifiedTime .Before (modifiedSinceTime )
462
+ }
463
+ }
464
+ }
465
+ return true
412
466
}
413
467
414
468
// Get returns the HTTP request header specified by field.
0 commit comments