Commit | Line | Data |
---|---|---|
8c8b8430 | 1 | ;;; url-cache.el --- Uniform Resource Locator retrieval tool |
00eef4de | 2 | |
a5cda60e GM |
3 | ;; Copyright (C) 1996, 1997, 1998, 1999, 2004, 2005, 2006, 2007, 2008, |
4 | ;; 2009, 2010 Free Software Foundation, Inc. | |
00eef4de | 5 | |
8c8b8430 SM |
6 | ;; Keywords: comm, data, processes, hypermedia |
7 | ||
00eef4de LH |
8 | ;; This file is part of GNU Emacs. |
9 | ||
4936186e | 10 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
00eef4de | 11 | ;; it under the terms of the GNU General Public License as published by |
4936186e GM |
12 | ;; the Free Software Foundation, either version 3 of the License, or |
13 | ;; (at your option) any later version. | |
00eef4de LH |
14 | |
15 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | ;; GNU General Public License for more details. | |
19 | ||
20 | ;; You should have received a copy of the GNU General Public License | |
4936186e | 21 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
00eef4de LH |
22 | |
23 | ;;; Code: | |
24 | ||
8c8b8430 | 25 | (require 'url-parse) |
55d6ea46 | 26 | (require 'url-util) |
8abe1fd5 | 27 | (require 'url) ;E.g. for url-configuration-directory. |
8c8b8430 SM |
28 | |
29 | (defcustom url-cache-directory | |
30 | (expand-file-name "cache" url-configuration-directory) | |
a5cda60e | 31 | "The directory where cache files should be stored." |
8c8b8430 SM |
32 | :type 'directory |
33 | :group 'url-file) | |
34 | ||
18d68e52 JD |
35 | (defcustom url-cache-expire-time 3600 |
36 | "Maximum time in seconds to keep the documents cached." | |
37 | :version "24.1" | |
38 | :type 'integer | |
39 | :group 'url-cache) | |
40 | ||
8c8b8430 SM |
41 | ;; Cache manager |
42 | (defun url-cache-file-writable-p (file) | |
43 | "Follows the documentation of `file-writable-p', unlike `file-writable-p'." | |
44 | (and (file-writable-p file) | |
45 | (if (file-exists-p file) | |
46 | (not (file-directory-p file)) | |
47 | (file-directory-p (file-name-directory file))))) | |
71ddfde5 | 48 | |
8c8b8430 SM |
49 | (defun url-cache-prepare (file) |
50 | "Makes it possible to cache data in FILE. | |
51 | Creates any necessary parent directories, deleting any non-directory files | |
52 | that would stop this. Returns nil if parent directories can not be | |
53 | created. If FILE already exists as a non-directory, it changes | |
54 | permissions of FILE or deletes FILE to make it possible to write a new | |
d1ce47b0 JB |
55 | version of FILE. Returns nil if this can not be done, or if FILE already |
56 | exists as a directory. Otherwise, returns t, indicating that | |
8c8b8430 SM |
57 | FILE can be created or overwritten." |
58 | (cond | |
59 | ((url-cache-file-writable-p file) | |
60 | t) | |
61 | ((file-directory-p file) | |
62 | nil) | |
63 | (t | |
64 | (condition-case () | |
65 | (or (make-directory (file-name-directory file) t) t) | |
66 | (error nil))))) | |
67 | ||
68 | ;;;###autoload | |
69 | (defun url-store-in-cache (&optional buff) | |
70 | "Store buffer BUFF in the cache." | |
6f6dc4da JD |
71 | (with-current-buffer (get-buffer (or buff (current-buffer))) |
72 | (let ((fname (url-cache-create-filename (url-view-url t)))) | |
73 | (if (url-cache-prepare fname) | |
74 | (let ((coding-system-for-write 'binary)) | |
75 | (write-region (point-min) (point-max) fname nil 5)))))) | |
71ddfde5 | 76 | |
50e4f0bf JD |
77 | (defun url-fetch-from-cache (url) |
78 | "Fetch URL from cache and return a buffer with the content." | |
79 | (with-current-buffer (generate-new-buffer " *temp*") | |
80 | (url-cache-extract (url-cache-create-filename url)) | |
81 | (current-buffer))) | |
82 | ||
8c8b8430 SM |
83 | ;;;###autoload |
84 | (defun url-is-cached (url) | |
85 | "Return non-nil if the URL is cached." | |
86 | (let* ((fname (url-cache-create-filename url)) | |
87 | (attribs (file-attributes fname))) | |
88 | (and fname ; got a filename | |
89 | (file-exists-p fname) ; file exists | |
90 | (not (eq (nth 0 attribs) t)) ; Its not a directory | |
91 | (nth 5 attribs)))) ; Can get last mod-time | |
92 | ||
93 | (defun url-cache-create-filename-human-readable (url) | |
d1ce47b0 | 94 | "Return a filename in the local cache for URL." |
8c8b8430 SM |
95 | (if url |
96 | (let* ((url (if (vectorp url) (url-recreate-url url) url)) | |
97 | (urlobj (url-generic-parse-url url)) | |
98 | (protocol (url-type urlobj)) | |
99 | (hostname (url-host urlobj)) | |
100 | (host-components | |
101 | (cons | |
102 | (user-real-login-name) | |
103 | (cons (or protocol "file") | |
104 | (reverse (split-string (or hostname "localhost") | |
105 | (eval-when-compile | |
106 | (regexp-quote "."))))))) | |
107 | (fname (url-filename urlobj))) | |
108 | (if (and fname (/= (length fname) 0) (= (aref fname 0) ?/)) | |
109 | (setq fname (substring fname 1 nil))) | |
110 | (if fname | |
111 | (let ((slash nil)) | |
112 | (setq fname | |
113 | (mapconcat | |
114 | (function | |
115 | (lambda (x) | |
116 | (cond | |
117 | ((and (= ?/ x) slash) | |
118 | (setq slash nil) | |
119 | "%2F") | |
120 | ((= ?/ x) | |
121 | (setq slash t) | |
122 | "/") | |
123 | (t | |
124 | (setq slash nil) | |
125 | (char-to-string x))))) fname "")))) | |
126 | ||
127 | (setq fname (and fname | |
128 | (mapconcat | |
129 | (function (lambda (x) | |
130 | (if (= x ?~) "" (char-to-string x)))) | |
131 | fname "")) | |
132 | fname (cond | |
133 | ((null fname) nil) | |
134 | ((or (string= "" fname) (string= "/" fname)) | |
135 | url-directory-index-file) | |
136 | ((= (string-to-char fname) ?/) | |
137 | (if (string= (substring fname -1 nil) "/") | |
138 | (concat fname url-directory-index-file) | |
139 | (substring fname 1 nil))) | |
140 | (t | |
141 | (if (string= (substring fname -1 nil) "/") | |
142 | (concat fname url-directory-index-file) | |
143 | fname)))) | |
144 | (and fname | |
145 | (expand-file-name fname | |
146 | (expand-file-name | |
147 | (mapconcat 'identity host-components "/") | |
148 | url-cache-directory)))))) | |
149 | ||
150 | (defun url-cache-create-filename-using-md5 (url) | |
151 | "Create a cached filename using MD5. | |
55d6ea46 | 152 | Very fast if you have an `md5' primitive function, suitably fast otherwise." |
8c8b8430 SM |
153 | (require 'md5) |
154 | (if url | |
155 | (let* ((url (if (vectorp url) (url-recreate-url url) url)) | |
156 | (checksum (md5 url)) | |
157 | (urlobj (url-generic-parse-url url)) | |
158 | (protocol (url-type urlobj)) | |
159 | (hostname (url-host urlobj)) | |
160 | (host-components | |
161 | (cons | |
162 | (user-real-login-name) | |
163 | (cons (or protocol "file") | |
164 | (nreverse | |
165 | (delq nil | |
166 | (split-string (or hostname "localhost") | |
167 | (eval-when-compile | |
168 | (regexp-quote ".")))))))) | |
169 | (fname (url-filename urlobj))) | |
170 | (and fname | |
171 | (expand-file-name checksum | |
172 | (expand-file-name | |
173 | (mapconcat 'identity host-components "/") | |
174 | url-cache-directory)))))) | |
175 | ||
176 | (defcustom url-cache-creation-function 'url-cache-create-filename-using-md5 | |
a5cda60e | 177 | "What function to use to create a cached filename." |
8c8b8430 SM |
178 | :type '(choice (const :tag "MD5 of filename (low collision rate)" |
179 | :value url-cache-create-filename-using-md5) | |
180 | (const :tag "Human readable filenames (higher collision rate)" | |
181 | :value url-cache-create-filename-human-readable) | |
182 | (function :tag "Other")) | |
183 | :group 'url-cache) | |
184 | ||
185 | (defun url-cache-create-filename (url) | |
186 | (funcall url-cache-creation-function url)) | |
187 | ||
188 | ;;;###autoload | |
189 | (defun url-cache-extract (fnam) | |
d1ce47b0 | 190 | "Extract FNAM from the local disk cache." |
8c8b8430 SM |
191 | (erase-buffer) |
192 | (insert-file-contents-literally fnam)) | |
193 | ||
18d68e52 | 194 | (defun url-cache-expired (url &optional expire-time) |
48ff1664 GM |
195 | "Return non-nil if a cached URL is older than EXPIRE-TIME seconds. |
196 | The default value of EXPIRE-TIME is `url-cache-expire-time'. | |
197 | If `url-standalone-mode' is non-nil, cached items never expire." | |
198 | (if url-standalone-mode | |
199 | (not (file-exists-p (url-cache-create-filename url))) | |
200 | (let ((cache-time (url-is-cached url))) | |
201 | (and cache-time | |
202 | (time-less-p | |
203 | (time-add | |
204 | cache-time | |
205 | (seconds-to-time (or expire-time url-cache-expire-time))) | |
206 | (current-time)))))) | |
8c8b8430 SM |
207 | |
208 | (provide 'url-cache) | |
e5566bd5 | 209 | |
32d5ce4d | 210 | ;; arch-tag: 95b050a6-8e81-4f23-8e63-191b9d1d657c |
00eef4de | 211 | ;;; url-cache.el ends here |