[Preliminary support for ETag / If-Not-Modified in feeds. prb@mult.ifario.us**20080303202256] { hunk ./servletsrc/perpubplat.hs 22 -import Data.ByteString.Lazy.Char8 ( unpack ) +import Data.ByteString.Lazy.Char8 ( unpack, pack ) +import Data.Digest.MD5 ( md5 ) hunk ./servletsrc/perpubplat.hs 39 - hunk ./servletsrc/perpubplat.hs 64 -serve_feed :: (F.Feedable f) => Controllers -> f -> CGI CGIResult -serve_feed con f = do { m <- liftIO $ DataC.get_model (data_c con) - ; setStatus 200 "OK" - ; let items = F.items f m - ; setHeader "Content-type" "application/atom+xml" - ; setHeader "Last-Modified" $ Utils.iso8601toRfc1123 $ S.last_updated items - ; output $ S.assemble_feed f m items } +serve_feed :: (F.Feedable f, Show f) => Controllers -> f -> CGI CGIResult +serve_feed con f = + do { m <- liftIO $ DataC.get_model (data_c con) + ; let items = F.items f m + ; let last_updated = S.last_updated items + ; let etag = show . md5 . pack $ (show f) ++ (last_updated) + ; ifNoneMatch <- requestHeader "If-None-Match" + ; let etag_didnt_match = + case ifNoneMatch of + Nothing -> True + Just e -> + e /= etag + ; ifModifiedSince <- requestHeader "If-Modified-Since" + {- From the HTTP 1.1 spec: + + "If none of the entity tags match, then the server MAY + perform the requested method as if the If-None-Match header + field did not exist, but MUST also ignore any + If-Modified-Since header field(s) in the request. That is, + if no entity tags match, then the server MUST NOT return a + 304 (Not Modified) response. " + + -} + ; let modified = + etag_didnt_match && + case ifModifiedSince of + Nothing -> True + Just d -> + (Utils.httpDateToIso8601 d) < last_updated + ; if modified then + do { setStatus 200 "OK" + ; setHeader "Content-type" "application/atom+xml" + ; setHeader "Last-Modified" $ Utils.iso8601toRfc1123 last_updated + ; setHeader "ETag" $ etag + ; output $ S.assemble_feed f m items } + else + do { setStatus 304 "Not Modified" + ; output $ ""} + } hunk ./src/Utilities.hs 189 - -rfc1123toIso8601 :: String -> String -rfc1123toIso8601 d = case P.parse rfc1123DateParser d d of - Left _ -> "" - Right d' -> d' }