ETagMiddleware function

Creates ETag middleware object

Creates ETag middleware object

Adds ETag to an Application .

ETags are header information that enable the caching of content. If enabled, RestRserve will return an ETag (eg a hash of a file) alongside the last time it was modified. When a request is sent, additional headers such as list("If-None-Match"), list("If-Match"), list("If-Modified-Since"), and list("If-Unmodified-Since"), can be passed to the server as well.

If the conditions are met (different hash in case of a If-None-Match header or a later file modification in case of a given If-Modified-Since header), the server does not send the requested file but returns a 304 status code, indicating, that the data on the requesting device is up-to-date.

Note that if both headers are provided, the If-None-Match header takes precedence.

Furthermore, the middleware also supports the headers If-Match, which returns the object if the hash matches (it also supports "*" to always return the file), as well as If-Unmodified-Since, which returns the object if it has not been modified since a certain time. If the conditions are not met, a 412 status code is returned (Precondition Failed). See examples below.

Examples

############################################################################# # setup a static directory with ETag caching static_dir = file.path(tempdir(), "static") if (!dir.exists(static_dir)) dir.create(static_dir) file_path = file.path(static_dir, "example.txt") writeLines("Hello World", file_path) # get the time the file was last modified in UTC time last_modified = as.POSIXlt(file.info(file_path)[["mtime"]], tz = "UTC") file_hash = digest::digest(file = file_path, algo = "crc32") time_fmt = "%a, %d %b %Y %H:%M:%S GMT" ############################################################################# # setup the Application with the ETag Middleware app = Application$new() app$append_middleware(ETagMiddleware$new()) app$add_static(path = "/", static_dir) ############################################################################# # Example Requests # Request the file returns the file with ETag headers req = Request$new(path = "/example.txt") # note that it also returns the Last-Modified and ETag headers app$process_request(req) # provide matching hash of the file in the If-None-Match header to check Etag # => 304 Not Modified (Can be cached) req = Request$new(path = "/example.txt", headers = list("If-None-Match" = file_hash)) # note status_code 304 Not Modified app$process_request(req) # provide a wrong hash, returns the file normally req = Request$new(path = "/example.txt", headers = list("If-None-Match" = "WRONG HASH")) app$process_request(req) # alternatively, you can provide a timestamp in the If-Modified-Since header # => 304 Not Modified (Can be cached) modified_since = format(last_modified + 1, time_fmt) req = Request$new(path = "/example.txt", headers = list("If-Modified-Since" = modified_since)) app$process_request(req) # provide both headers: If-None-Match takes precedence # in this case: # - if none match => modified (No cache) # - if modified since => NOT MODIFIED (cached) # => Overall: modified = no cache modified_since = format(last_modified + 1, time_fmt) req = Request$new(path = "/example.txt", headers = list("If-None-Match" = "CLEARLY WRONG", "If-Modified-Since" = modified_since)) app$process_request(req) # provide matching hash of the file in the If-Match header to check Etag # => 412 Precondition Failed req = Request$new(path = "/example.txt", headers = list("If-Match" = "OTHER HASH")) # note status_code 412 Precondition Failed app$process_request(req) # Use If-Unmodified-Since unmodified_since = format(last_modified - 1, time_fmt) req = Request$new(path = "/example.txt", headers = list("If-Unmodified-Since" = unmodified_since) ) # note status_code 412 Precondition Failed app$process_request(req) ############################################################################# # use an alternative hash function (use name of the file) hash_on_filename = function(x) x # also use an alternate last_modified time function always_1900 = function(x) as.POSIXlt("1900-01-01 12:34:56", tz = "GMT") # setup the app again app = Application$new(middleware = list( ETagMiddleware$new(hash_function = hash_on_filename, last_modified_function = always_1900) )) app$add_static(path = "/", file_path = static_dir) # test the requests req = Request$new(path = "/example.txt") (res = app$process_request(req)) filename = res$body[["file"]] req = Request$new(path = "/example.txt", headers = list("If-None-Match" = filename)) app$process_request(req)

References

MDN

See Also

Middleware Application

Super class

RestRserve::Middleware -> EtagMiddleware

Public fields

  • hash_function: Function that takes an object or file and computes the hash of it

  • last_modified_function: Function that takes an object or file and computes the last time it was modified

Methods

Public methods

Method new()

Creates ETag middleware object

Usage

ETagMiddleware$new(
  routes = "/",
  match = "partial",
  id = "ETagMiddleware",
  hash_function = function(body) {
if ("file" %in% names(body)) {
   
    digest::digest(file = body[["file"]], algo = "crc32")
}
else {
   
    digest::digest(body, algo = "crc32")
}
 },
  last_modified_function = function(body) {
if ("file" %in% names(body)) {
  
as.POSIXlt(file.info(body[["file"]])[["mtime"]], tz = "GMT")
}
else {
    
   as.POSIXlt(Sys.time(), tz = "GMT")
}
 }
)

Arguments

  • routes: Routes paths to protect.

  • match: How routes will be matched: exact or partial (as prefix).

  • id: Middleware id.

  • hash_function: a function that generates the ETag hash. The function takes the body of the response and returns a single character. Default is crc32 using digest::digest .

  • last_modified_function: a function that takes the body of the response and returns the last time this was changed. The default is to take the mtime (last time the file was modified) if its a file, if the body does not contain a file, the current time is returned ( resulting in no caching)

Method clone()

The objects of this class are cloneable with this method.

Usage

ETagMiddleware$clone(deep = FALSE)

Arguments

  • deep: Whether to make a deep clone.