Skip to content

Commit

Permalink
Update c.Fresh(#311) (#317)
Browse files Browse the repository at this point in the history
* update: ctx.BodyParser

* add #311

* Update utils.go
  • Loading branch information
bestgopher committed Apr 28, 2020
1 parent 1cf0d25 commit 86a9b05
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
56 changes: 55 additions & 1 deletion ctx.go
Expand Up @@ -14,8 +14,10 @@ import (
"log"
"mime"
"mime/multipart"
"net/http"
"net/url"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -62,6 +64,7 @@ type Cookie struct {
// Global variables
var schemaDecoderForm = schema.NewDecoder()
var schemaDecoderQuery = schema.NewDecoder()
var cacheControlNoCacheRegexp, _ = regexp.Compile(`/(?:^|,)\s*?no-cache\s*?(?:,|$)/`)

// Ctx pool
var poolCtx = sync.Pool{
Expand Down Expand Up @@ -407,8 +410,59 @@ func (ctx *Ctx) FormValue(key string) (value string) {
}

// Fresh is not implemented yet, pull requests are welcome!
// https://github.com/jshttp/fresh/blob/10e0471669dbbfbfd8de65bc6efac2ddd0bfa057/index.js#L33
func (ctx *Ctx) Fresh() bool {
return false
// fields
var modifiedSince = ctx.Get(HeaderIfModifiedSince)
var noneMatch = ctx.Get(HeaderIfNoneMatch)

// unconditional request
if modifiedSince == "" && noneMatch == "" {
return false
}

// Always return stale when Cache-Control: no-cache
// to support end-to-end reload requests
// https://tools.ietf.org/html/rfc2616#section-14.9.4
var cacheControl = ctx.Get(HeaderCacheControl)
if cacheControl != "" && cacheControlNoCacheRegexp.MatchString(cacheControl) {
return false
}

// if-none-match
if noneMatch != "" && noneMatch != "*" {
var etag = getString(ctx.Fasthttp.Response.Header.Peek(HeaderETag))
if etag == "" {
return false
}
var etagStal = true
var matches = parseTokenList(getBytes(noneMatch))
for _, match := range matches {
if match == etag || match == "W/"+etag || "W/"+match == etag {
etagStal = false
break
}
}
if etagStal {
return false
}

if modifiedSince != "" {
var lastModified = getString(ctx.Fasthttp.Response.Header.Peek(HeaderLastModified))
if lastModified != "" {
lastModifiedTime, err := http.ParseTime(lastModified)
if err != nil {
return false
}
modifiedSinceTime, err := http.ParseTime(modifiedSince)
if err != nil {
return false
}
return lastModifiedTime.Before(modifiedSinceTime)
}
}
}
return true
}

// Get returns the HTTP request header specified by field.
Expand Down
28 changes: 28 additions & 0 deletions utils.go
Expand Up @@ -156,6 +156,34 @@ func (c *testConn) SetDeadline(t time.Time) error { return nil }
func (c *testConn) SetReadDeadline(t time.Time) error { return nil }
func (c *testConn) SetWriteDeadline(t time.Time) error { return nil }

// Adapted from:
// https://github.com/jshttp/fresh/blob/10e0471669dbbfbfd8de65bc6efac2ddd0bfa057/index.js#L110
func parseTokenList(noneMatchBytes []byte) []string {
var (
start int
end int
list []string
)
for i, v := range noneMatchBytes {
switch v {
case 0x20:
if start == end {
start = i + 1
end = i + 1
}
case 0x2c:
list = append(list, getString(noneMatchBytes[start:end]))
start = i + 1
end = i + 1
default:
end = i + 1
}
}

list = append(list, getString(noneMatchBytes[start:end]))
return list
}

// HTTP status codes were copied from net/http.
var statusMessages = map[int]string{
100: "Continue",
Expand Down

0 comments on commit 86a9b05

Please sign in to comment.