{"action":"created","comment":{"url":"https://api.github.com/repos/threatgrid/ctia/pulls/comments/70097681","id":70097681,"diff_hunk":"@@ -0,0 +1,33 @@\n+(ns ctia.http.middleware.cache-control\n+  (:require [ctia.lib.time :refer [format-rfc822-time]]\n+            [pandect.algo.sha1 :refer [sha1]])\n+  (:import java.io.File))\n+\n+(defn- read-request? [request]\n+  (#{:get :head} (:request-method request)))\n+\n+(defn- ok-response? [response]\n+  (= (:status response) 200))\n+\n+(defn calculate-etag [body]\n+  (case (class body)\n+    String (sha1 body)\n+    File (str (.lastModified body) \"-\" (.length body))\n+    (sha1 (.getBytes (pr-str body) \"UTF-8\"))))\n+\n+(defn update-headers [headers etag body]\n+  (merge headers","path":"src/ctia/http/middleware/cache_control.clj","position":19,"original_position":19,"commit_id":"66e6f8c9a212fec9df405e27ac3f49e69f4f6b39","original_commit_id":"66e6f8c9a212fec9df405e27ac3f49e69f4f6b39","user":{"login":"polygloton","id":368005,"avatar_url":"https://avatars.githubusercontent.com/u/368005?v=3","gravatar_id":"","url":"https://api.github.com/users/polygloton","html_url":"https://github.com/polygloton","followers_url":"https://api.github.com/users/polygloton/followers","following_url":"https://api.github.com/users/polygloton/following{/other_user}","gists_url":"https://api.github.com/users/polygloton/gists{/gist_id}","starred_url":"https://api.github.com/users/polygloton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/polygloton/subscriptions","organizations_url":"https://api.github.com/users/polygloton/orgs","repos_url":"https://api.github.com/users/polygloton/repos","events_url":"https://api.github.com/users/polygloton/events{/privacy}","received_events_url":"https://api.github.com/users/polygloton/received_events","type":"User","site_admin":false},"body":"You could use cond-> with assoc instead of merge (it makes the when-let below a little cleaner, IMO).  For the \"ETag\" key, you could assoc it under the :else predicate.  Just a nit, though.  :)","created_at":"2016-07-08T15:59:49Z","updated_at":"2016-07-08T15:59:49Z","html_url":"https://github.com/threatgrid/ctia/pull/389#discussion_r70097681","pull_request_url":"https://api.github.com/repos/threatgrid/ctia/pulls/389","_links":{"self":{"href":"https://api.github.com/repos/threatgrid/ctia/pulls/comments/70097681"},"html":{"href":"https://github.com/threatgrid/ctia/pull/389#discussion_r70097681"},"pull_request":{"href":"https://api.github.com/repos/threatgrid/ctia/pulls/389"}}},"pull_request":{"url":"https://api.github.com/repos/threatgrid/ctia/pulls/389","id":76457623,"html_url":"https://github.com/threatgrid/ctia/pull/389","diff_url":"https://github.com/threatgrid/ctia/pull/389.diff","patch_url":"https://github.com/threatgrid/ctia/pull/389.patch","issue_url":"https://api.github.com/repos/threatgrid/ctia/issues/389","number":389,"state":"open","locked":false,"title":"initial cache control headers implementation","user":{"login":"gbuisson","id":1433542,"avatar_url":"https://avatars.githubusercontent.com/u/1433542?v=3","gravatar_id":"","url":"https://api.github.com/users/gbuisson","html_url":"https://github.com/gbuisson","followers_url":"https://api.github.com/users/gbuisson/followers","following_url":"https://api.github.com/users/gbuisson/following{/other_user}","gists_url":"https://api.github.com/users/gbuisson/gists{/gist_id}","starred_url":"https://api.github.com/users/gbuisson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gbuisson/subscriptions","organizations_url":"https://api.github.com/users/gbuisson/orgs","repos_url":"https://api.github.com/users/gbuisson/repos","events_url":"https://api.github.com/users/gbuisson/events{/privacy}","received_events_url":"https://api.github.com/users/gbuisson/received_events","type":"User","site_admin":false},"body":"closes #370 \r\n\r\nThis adds HTTP Cache control headers support:\r\n\r\n- Last-Modified is computed from :created or :updated for all entities\r\n- ETag is composed from a sha1 of the output if it's data, else if it's a file we generate through File metas.\r\n\r\nThe result is applied as a couple of middleware to every GET routes.","created_at":"2016-07-06T16:02:01Z","updated_at":"2016-07-08T15:59:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"25850f50aa1dde918fb8fc3fb023ecb07c3a9912","assignee":{"login":"craigbro","id":37200,"avatar_url":"https://avatars.githubusercontent.com/u/37200?v=3","gravatar_id":"","url":"https://api.github.com/users/craigbro","html_url":"https://github.com/craigbro","followers_url":"https://api.github.com/users/craigbro/followers","following_url":"https://api.github.com/users/craigbro/following{/other_user}","gists_url":"https://api.github.com/users/craigbro/gists{/gist_id}","starred_url":"https://api.github.com/users/craigbro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/craigbro/subscriptions","organizations_url":"https://api.github.com/users/craigbro/orgs","repos_url":"https://api.github.com/users/craigbro/repos","events_url":"https://api.github.com/users/craigbro/events{/privacy}","received_events_url":"https://api.github.com/users/craigbro/received_events","type":"User","site_admin":false},"assignees":[{"login":"craigbro","id":37200,"avatar_url":"https://avatars.githubusercontent.com/u/37200?v=3","gravatar_id":"","url":"https://api.github.com/users/craigbro","html_url":"https://github.com/craigbro","followers_url":"https://api.github.com/users/craigbro/followers","following_url":"https://api.github.com/users/craigbro/following{/other_user}","gists_url":"https://api.github.com/users/craigbro/gists{/gist_id}","starred_url":"https://api.github.com/users/craigbro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/craigbro/subscriptions","organizations_url":"https://api.github.com/users/craigbro/orgs","repos_url":"https://api.github.com/users/craigbro/repos","events_url":"https://api.github.com/users/craigbro/events{/privacy}","received_events_url":"https://api.github.com/users/craigbro/received_events","type":"User","site_admin":false},{"login":"saintx","id":711320,"avatar_url":"https://avatars.githubusercontent.com/u/711320?v=3","gravatar_id":"","url":"https://api.github.com/users/saintx","html_url":"https://github.com/saintx","followers_url":"https://api.github.com/users/saintx/followers","following_url":"https://api.github.com/users/saintx/following{/other_user}","gists_url":"https://api.github.com/users/saintx/gists{/gist_id}","starred_url":"https://api.github.com/users/saintx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saintx/subscriptions","organizations_url":"https://api.github.com/users/saintx/orgs","repos_url":"https://api.github.com/users/saintx/repos","events_url":"https://api.github.com/users/saintx/events{/privacy}","received_events_url":"https://api.github.com/users/saintx/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/threatgrid/ctia/milestones/8","html_url":"https://github.com/threatgrid/ctia/milestones/CTIR%20Beta","labels_url":"https://api.github.com/repos/threatgrid/ctia/milestones/8/labels","id":1832431,"number":8,"title":"CTIR Beta","description":"","creator":{"login":"craigbro","id":37200,"avatar_url":"https://avatars.githubusercontent.com/u/37200?v=3","gravatar_id":"","url":"https://api.github.com/users/craigbro","html_url":"https://github.com/craigbro","followers_url":"https://api.github.com/users/craigbro/followers","following_url":"https://api.github.com/users/craigbro/following{/other_user}","gists_url":"https://api.github.com/users/craigbro/gists{/gist_id}","starred_url":"https://api.github.com/users/craigbro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/craigbro/subscriptions","organizations_url":"https://api.github.com/users/craigbro/orgs","repos_url":"https://api.github.com/users/craigbro/repos","events_url":"https://api.github.com/users/craigbro/events{/privacy}","received_events_url":"https://api.github.com/users/craigbro/received_events","type":"User","site_admin":false},"open_issues":13,"closed_issues":2,"state":"open","created_at":"2016-06-16T14:52:57Z","updated_at":"2016-07-07T14:42:29Z","due_on":"2016-06-30T04:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/threatgrid/ctia/pulls/389/commits","review_comments_url":"https://api.github.com/repos/threatgrid/ctia/pulls/389/comments","review_comment_url":"https://api.github.com/repos/threatgrid/ctia/pulls/comments{/number}","comments_url":"https://api.github.com/repos/threatgrid/ctia/issues/389/comments","statuses_url":"https://api.github.com/repos/threatgrid/ctia/statuses/66e6f8c9a212fec9df405e27ac3f49e69f4f6b39","head":{"label":"gbuisson:issue-370-request-caching","ref":"issue-370-request-caching","sha":"66e6f8c9a212fec9df405e27ac3f49e69f4f6b39","user":{"login":"gbuisson","id":1433542,"avatar_url":"https://avatars.githubusercontent.com/u/1433542?v=3","gravatar_id":"","url":"https://api.github.com/users/gbuisson","html_url":"https://github.com/gbuisson","followers_url":"https://api.github.com/users/gbuisson/followers","following_url":"https://api.github.com/users/gbuisson/following{/other_user}","gists_url":"https://api.github.com/users/gbuisson/gists{/gist_id}","starred_url":"https://api.github.com/users/gbuisson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gbuisson/subscriptions","organizations_url":"https://api.github.com/users/gbuisson/orgs","repos_url":"https://api.github.com/users/gbuisson/repos","events_url":"https://api.github.com/users/gbuisson/events{/privacy}","received_events_url":"https://api.github.com/users/gbuisson/received_events","type":"User","site_admin":false},"repo":{"id":55398099,"name":"ctia","full_name":"gbuisson/ctia","owner":{"login":"gbuisson","id":1433542,"avatar_url":"https://avatars.githubusercontent.com/u/1433542?v=3","gravatar_id":"","url":"https://api.github.com/users/gbuisson","html_url":"https://github.com/gbuisson","followers_url":"https://api.github.com/users/gbuisson/followers","following_url":"https://api.github.com/users/gbuisson/following{/other_user}","gists_url":"https://api.github.com/users/gbuisson/gists{/gist_id}","starred_url":"https://api.github.com/users/gbuisson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gbuisson/subscriptions","organizations_url":"https://api.github.com/users/gbuisson/orgs","repos_url":"https://api.github.com/users/gbuisson/repos","events_url":"https://api.github.com/users/gbuisson/events{/privacy}","received_events_url":"https://api.github.com/users/gbuisson/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/gbuisson/ctia","description":"Cisco Threat Intelligence API","fork":true,"url":"https://api.github.com/repos/gbuisson/ctia","forks_url":"https://api.github.com/repos/gbuisson/ctia/forks","keys_url":"https://api.github.com/repos/gbuisson/ctia/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gbuisson/ctia/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gbuisson/ctia/teams","hooks_url":"https://api.github.com/repos/gbuisson/ctia/hooks","issue_events_url":"https://api.github.com/repos/gbuisson/ctia/issues/events{/number}","events_url":"https://api.github.com/repos/gbuisson/ctia/events","assignees_url":"https://api.github.com/repos/gbuisson/ctia/assignees{/user}","branches_url":"https://api.github.com/repos/gbuisson/ctia/branches{/branch}","tags_url":"https://api.github.com/repos/gbuisson/ctia/tags","blobs_url":"https://api.github.com/repos/gbuisson/ctia/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gbuisson/ctia/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gbuisson/ctia/git/refs{/sha}","trees_url":"https://api.github.com/repos/gbuisson/ctia/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gbuisson/ctia/statuses/{sha}","languages_url":"https://api.github.com/repos/gbuisson/ctia/languages","stargazers_url":"https://api.github.com/repos/gbuisson/ctia/stargazers","contributors_url":"https://api.github.com/repos/gbuisson/ctia/contributors","subscribers_url":"https://api.github.com/repos/gbuisson/ctia/subscribers","subscription_url":"https://api.github.com/repos/gbuisson/ctia/subscription","commits_url":"https://api.github.com/repos/gbuisson/ctia/commits{/sha}","git_commits_url":"https://api.github.com/repos/gbuisson/ctia/git/commits{/sha}","comments_url":"https://api.github.com/repos/gbuisson/ctia/comments{/number}","issue_comment_url":"https://api.github.com/repos/gbuisson/ctia/issues/comments{/number}","contents_url":"https://api.github.com/repos/gbuisson/ctia/contents/{+path}","compare_url":"https://api.github.com/repos/gbuisson/ctia/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gbuisson/ctia/merges","archive_url":"https://api.github.com/repos/gbuisson/ctia/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gbuisson/ctia/downloads","issues_url":"https://api.github.com/repos/gbuisson/ctia/issues{/number}","pulls_url":"https://api.github.com/repos/gbuisson/ctia/pulls{/number}","milestones_url":"https://api.github.com/repos/gbuisson/ctia/milestones{/number}","notifications_url":"https://api.github.com/repos/gbuisson/ctia/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gbuisson/ctia/labels{/name}","releases_url":"https://api.github.com/repos/gbuisson/ctia/releases{/id}","deployments_url":"https://api.github.com/repos/gbuisson/ctia/deployments","created_at":"2016-04-04T09:10:25Z","updated_at":"2016-04-04T09:10:26Z","pushed_at":"2016-07-07T09:32:16Z","git_url":"git://github.com/gbuisson/ctia.git","ssh_url":"git@github.com:gbuisson/ctia.git","clone_url":"https://github.com/gbuisson/ctia.git","svn_url":"https://github.com/gbuisson/ctia","homepage":"","size":1920,"stargazers_count":0,"watchers_count":0,"language":"Clojure","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"threatgrid:master","ref":"master","sha":"e05f287a283d126aad13b4b290f2e88b36f5b0a5","user":{"login":"threatgrid","id":337733,"avatar_url":"https://avatars.githubusercontent.com/u/337733?v=3","gravatar_id":"","url":"https://api.github.com/users/threatgrid","html_url":"https://github.com/threatgrid","followers_url":"https://api.github.com/users/threatgrid/followers","following_url":"https://api.github.com/users/threatgrid/following{/other_user}","gists_url":"https://api.github.com/users/threatgrid/gists{/gist_id}","starred_url":"https://api.github.com/users/threatgrid/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/threatgrid/subscriptions","organizations_url":"https://api.github.com/users/threatgrid/orgs","repos_url":"https://api.github.com/users/threatgrid/repos","events_url":"https://api.github.com/users/threatgrid/events{/privacy}","received_events_url":"https://api.github.com/users/threatgrid/received_events","type":"Organization","site_admin":false},"repo":{"id":47668849,"name":"ctia","full_name":"threatgrid/ctia","owner":{"login":"threatgrid","id":337733,"avatar_url":"https://avatars.githubusercontent.com/u/337733?v=3","gravatar_id":"","url":"https://api.github.com/users/threatgrid","html_url":"https://github.com/threatgrid","followers_url":"https://api.github.com/users/threatgrid/followers","following_url":"https://api.github.com/users/threatgrid/following{/other_user}","gists_url":"https://api.github.com/users/threatgrid/gists{/gist_id}","starred_url":"https://api.github.com/users/threatgrid/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/threatgrid/subscriptions","organizations_url":"https://api.github.com/users/threatgrid/orgs","repos_url":"https://api.github.com/users/threatgrid/repos","events_url":"https://api.github.com/users/threatgrid/events{/privacy}","received_events_url":"https://api.github.com/users/threatgrid/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/threatgrid/ctia","description":"Cisco Threat Intelligence API","fork":false,"url":"https://api.github.com/repos/threatgrid/ctia","forks_url":"https://api.github.com/repos/threatgrid/ctia/forks","keys_url":"https://api.github.com/repos/threatgrid/ctia/keys{/key_id}","collaborators_url":"https://api.github.com/repos/threatgrid/ctia/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/threatgrid/ctia/teams","hooks_url":"https://api.github.com/repos/threatgrid/ctia/hooks","issue_events_url":"https://api.github.com/repos/threatgrid/ctia/issues/events{/number}","events_url":"https://api.github.com/repos/threatgrid/ctia/events","assignees_url":"https://api.github.com/repos/threatgrid/ctia/assignees{/user}","branches_url":"https://api.github.com/repos/threatgrid/ctia/branches{/branch}","tags_url":"https://api.github.com/repos/threatgrid/ctia/tags","blobs_url":"https://api.github.com/repos/threatgrid/ctia/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/threatgrid/ctia/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/threatgrid/ctia/git/refs{/sha}","trees_url":"https://api.github.com/repos/threatgrid/ctia/git/trees{/sha}","statuses_url":"https://api.github.com/repos/threatgrid/ctia/statuses/{sha}","languages_url":"https://api.github.com/repos/threatgrid/ctia/languages","stargazers_url":"https://api.github.com/repos/threatgrid/ctia/stargazers","contributors_url":"https://api.github.com/repos/threatgrid/ctia/contributors","subscribers_url":"https://api.github.com/repos/threatgrid/ctia/subscribers","subscription_url":"https://api.github.com/repos/threatgrid/ctia/subscription","commits_url":"https://api.github.com/repos/threatgrid/ctia/commits{/sha}","git_commits_url":"https://api.github.com/repos/threatgrid/ctia/git/commits{/sha}","comments_url":"https://api.github.com/repos/threatgrid/ctia/comments{/number}","issue_comment_url":"https://api.github.com/repos/threatgrid/ctia/issues/comments{/number}","contents_url":"https://api.github.com/repos/threatgrid/ctia/contents/{+path}","compare_url":"https://api.github.com/repos/threatgrid/ctia/compare/{base}...{head}","merges_url":"https://api.github.com/repos/threatgrid/ctia/merges","archive_url":"https://api.github.com/repos/threatgrid/ctia/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/threatgrid/ctia/downloads","issues_url":"https://api.github.com/repos/threatgrid/ctia/issues{/number}","pulls_url":"https://api.github.com/repos/threatgrid/ctia/pulls{/number}","milestones_url":"https://api.github.com/repos/threatgrid/ctia/milestones{/number}","notifications_url":"https://api.github.com/repos/threatgrid/ctia/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/threatgrid/ctia/labels{/name}","releases_url":"https://api.github.com/repos/threatgrid/ctia/releases{/id}","deployments_url":"https://api.github.com/repos/threatgrid/ctia/deployments","created_at":"2015-12-09T04:41:06Z","updated_at":"2016-06-16T16:24:41Z","pushed_at":"2016-07-08T00:29:52Z","git_url":"git://github.com/threatgrid/ctia.git","ssh_url":"git@github.com:threatgrid/ctia.git","clone_url":"https://github.com/threatgrid/ctia.git","svn_url":"https://github.com/threatgrid/ctia","homepage":"","size":1948,"stargazers_count":2,"watchers_count":2,"language":"Clojure","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":68,"forks":6,"open_issues":68,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/threatgrid/ctia/pulls/389"},"html":{"href":"https://github.com/threatgrid/ctia/pull/389"},"issue":{"href":"https://api.github.com/repos/threatgrid/ctia/issues/389"},"comments":{"href":"https://api.github.com/repos/threatgrid/ctia/issues/389/comments"},"review_comments":{"href":"https://api.github.com/repos/threatgrid/ctia/pulls/389/comments"},"review_comment":{"href":"https://api.github.com/repos/threatgrid/ctia/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/threatgrid/ctia/pulls/389/commits"},"statuses":{"href":"https://api.github.com/repos/threatgrid/ctia/statuses/66e6f8c9a212fec9df405e27ac3f49e69f4f6b39"}}}}
{"actor":{"display_login":"polygloton"}}