conditionals.lua 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. -- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
  2. -- Licensed to the public under the Apache License 2.0.
  3. -- This class provides basic ETag handling and implements most of the
  4. -- conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
  5. module("luci.http.conditionals", package.seeall)
  6. local date = require("luci.http.date")
  7. function mk_etag( stat )
  8. if stat ~= nil then
  9. return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime )
  10. end
  11. end
  12. -- Test whether the given message object contains an "If-Match" header and
  13. -- compare it against the given stat object.
  14. function if_match( req, stat )
  15. local h = req.headers
  16. local etag = mk_etag( stat )
  17. -- Check for matching resource
  18. if type(h['If-Match']) == "string" then
  19. for ent in h['If-Match']:gmatch("([^, ]+)") do
  20. if ( ent == '*' or ent == etag ) and stat ~= nil then
  21. return true
  22. end
  23. end
  24. return false, 412
  25. end
  26. return true
  27. end
  28. -- Test whether the given message object contains an "If-Modified-Since" header
  29. -- and compare it against the given stat object.
  30. function if_modified_since( req, stat )
  31. local h = req.headers
  32. -- Compare mtimes
  33. if type(h['If-Modified-Since']) == "string" then
  34. local since = date.to_unix( h['If-Modified-Since'] )
  35. if stat == nil or since < stat.mtime then
  36. return true
  37. end
  38. return false, 304, {
  39. ["ETag"] = mk_etag( stat );
  40. ["Date"] = date.to_http( os.time() );
  41. ["Last-Modified"] = date.to_http( stat.mtime )
  42. }
  43. end
  44. return true
  45. end
  46. -- Test whether the given message object contains an "If-None-Match" header and
  47. -- compare it against the given stat object.
  48. function if_none_match( req, stat )
  49. local h = req.headers
  50. local etag = mk_etag( stat )
  51. local method = req.env and req.env.REQUEST_METHOD or "GET"
  52. -- Check for matching resource
  53. if type(h['If-None-Match']) == "string" then
  54. for ent in h['If-None-Match']:gmatch("([^, ]+)") do
  55. if ( ent == '*' or ent == etag ) and stat ~= nil then
  56. if method == "GET" or method == "HEAD" then
  57. return false, 304, {
  58. ["ETag"] = etag;
  59. ["Date"] = date.to_http( os.time() );
  60. ["Last-Modified"] = date.to_http( stat.mtime )
  61. }
  62. else
  63. return false, 412
  64. end
  65. end
  66. end
  67. end
  68. return true
  69. end
  70. -- The If-Range header is currently not implemented due to the lack of general
  71. -- byte range stuff in luci.http.protocol . This function will always return
  72. -- false, 412 to indicate a failed precondition.
  73. function if_range( req, stat )
  74. -- Sorry, no subranges (yet)
  75. return false, 412
  76. end
  77. -- Test whether the given message object contains an "If-Unmodified-Since"
  78. -- header and compare it against the given stat object.
  79. function if_unmodified_since( req, stat )
  80. local h = req.headers
  81. -- Compare mtimes
  82. if type(h['If-Unmodified-Since']) == "string" then
  83. local since = date.to_unix( h['If-Unmodified-Since'] )
  84. if stat ~= nil and since <= stat.mtime then
  85. return false, 412
  86. end
  87. end
  88. return true
  89. end