Merge from emacs-24; up to 2012-05-02T11:38:01Z!lekktu@gmail.com
[bpt/emacs.git] / lisp / url / url.el
CommitLineData
e95a67dc 1;;; url.el --- Uniform Resource Locator retrieval tool -*- lexical-binding: t -*-
42b369cd 2
acaf905b 3;; Copyright (C) 1996-1999, 2001, 2004-2012 Free Software Foundation, Inc.
42b369cd 4
8c8b8430 5;; Author: Bill Perry <wmperry@gnu.org>
8c8b8430
SM
6;; Keywords: comm, data, processes, hypermedia
7
42b369cd
SM
8;; This file is part of GNU Emacs.
9;;
4936186e 10;; GNU Emacs is free software: you can redistribute it and/or modify
42b369cd 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.
14
42b369cd
SM
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.
4936186e 19
42b369cd 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/>.
42b369cd
SM
22
23;;; Commentary:
8c8b8430
SM
24
25;; Registered URI schemes: http://www.iana.org/assignments/uri-schemes
26
42b369cd
SM
27;;; Code:
28
8c8b8430 29
aa8f8277
GM
30(require 'mailcap)
31
8c8b8430
SM
32(eval-when-compile
33 (require 'mm-decode)
34 (require 'mm-view))
35
8c8b8430
SM
36(require 'url-vars)
37(require 'url-cookie)
38(require 'url-history)
39(require 'url-expand)
40(require 'url-privacy)
41(require 'url-methods)
42(require 'url-proxy)
43(require 'url-parse)
44(require 'url-util)
45
4577244f 46
4577244f 47(defcustom url-configuration-directory
091b0137 48 (locate-user-emacs-file "url/" ".url/")
4577244f
GM
49 "Directory used by the URL package for cookies, history, etc."
50 :type 'directory
51 :group 'url)
8c8b8430
SM
52
53(defun url-do-setup ()
d1ce47b0 54 "Setup the URL package.
8c8b8430
SM
55This is to avoid conflict with user settings if URL is dumped with
56Emacs."
57 (unless url-setup-done
58
59 ;; Make OS/2 happy
60 ;;(push '("http" "80") tcp-binary-process-input-services)
61
62 (mailcap-parse-mailcaps)
63 (mailcap-parse-mimetypes)
71ddfde5 64
8c8b8430
SM
65 ;; Register all the authentication schemes we can handle
66 (url-register-auth-scheme "basic" nil 4)
67 (url-register-auth-scheme "digest" nil 7)
68
69 (setq url-cookie-file
70 (or url-cookie-file
71 (expand-file-name "cookies" url-configuration-directory)))
71ddfde5 72
8c8b8430
SM
73 (setq url-history-file
74 (or url-history-file
75 (expand-file-name "history" url-configuration-directory)))
71ddfde5 76
8c8b8430
SM
77 ;; Parse the global history file if it exists, so that it can be used
78 ;; for URL completion, etc.
79 (url-history-parse-history)
80 (url-history-setup-save-timer)
81
82 ;; Ditto for cookies
83 (url-cookie-setup-save-timer)
84 (url-cookie-parse-file url-cookie-file)
85
86 ;; Read in proxy gateways
87 (let ((noproxy (and (not (assoc "no_proxy" url-proxy-services))
88 (or (getenv "NO_PROXY")
89 (getenv "no_PROXY")
90 (getenv "no_proxy")))))
91 (if noproxy
92 (setq url-proxy-services
93 (cons (cons "no_proxy"
94 (concat "\\("
95 (mapconcat
96 (lambda (x)
97 (cond
98 ((= x ?,) "\\|")
99 ((= x ? ) "")
100 ((= x ?.) (regexp-quote "."))
101 ((= x ?*) ".*")
102 ((= x ??) ".")
103 (t (char-to-string x))))
104 noproxy "") "\\)"))
105 url-proxy-services))))
106
8c8b8430
SM
107 (url-setup-privacy-info)
108 (run-hooks 'url-load-hook)
109 (setq url-setup-done t)))
110
111;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
112;;; Retrieval functions
113;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9b4cf231
SM
114
115(defvar url-redirect-buffer nil
116 "New buffer into which the retrieval will take place.
117Sometimes while retrieving a URL, the URL library needs to use another buffer
118than the one returned initially by `url-retrieve'. In this case, it sets this
119variable in the original buffer as a forwarding pointer.")
120
1968bb1b
LI
121(defvar url-retrieve-number-of-calls 0)
122(autoload 'url-cache-prune-cache "url-cache")
123
2ef88a69 124;;;###autoload
aacaa419 125(defun url-retrieve (url callback &optional cbargs silent inhibit-cookies)
8c8b8430 126 "Retrieve URL asynchronously and call CALLBACK with CBARGS when finished.
ce7b18ec
CY
127URL is either a string or a parsed URL. If it is a string
128containing characters that are not valid in a URI, those
129characters are percent-encoded; see `url-encode-url'.
497803ed
RS
130
131CALLBACK is called when the object has been completely retrieved, with
8c8b8430 132the current buffer containing the object, and any MIME headers associated
1b244f61
CY
133with it. It is called as (apply CALLBACK STATUS CBARGS).
134STATUS is a list with an even number of elements representing
135what happened during the request, with most recent events first,
136or an empty list if no events have occurred. Each pair is one of:
5695d1dd
CY
137
138\(:redirect REDIRECTED-TO) - the request was redirected to this URL
139\(:error (ERROR-SYMBOL . DATA)) - an error occurred. The error can be
140signaled with (signal ERROR-SYMBOL DATA).
8c8b8430
SM
141
142Return the buffer URL will load into, or nil if the process has
5695d1dd
CY
143already completed (i.e. URL was a mailto URL or similar; in this case
144the callback is not called).
145
146The variables `url-request-data', `url-request-method' and
147`url-request-extra-headers' can be dynamically bound around the
148request; dynamic binding of other variables doesn't necessarily
08b8ba9f
LMI
149take effect.
150
aacaa419
LI
151If SILENT, then don't message progress reports and the like.
152If INHIBIT-COOKIES, cookies will neither be stored nor sent to
a967e26b
WX
153the server.
154If URL is a multibyte string, it will be encoded as utf-8 and
155URL-encoded before it's used."
5695d1dd
CY
156;;; XXX: There is code in Emacs that does dynamic binding
157;;; of the following variables around url-retrieve:
158;;; url-standalone-mode, url-gateway-unplugged, w3-honor-stylesheets,
159;;; url-confirmation-func, url-cookie-multiple-line,
160;;; url-cookie-{{,secure-}storage,confirmation}
161;;; url-standalone-mode and url-gateway-unplugged should work as
162;;; usual. url-confirmation-func is only used in nnwarchive.el and
163;;; webmail.el; the latter should be updated. Is
164;;; url-cookie-multiple-line needed anymore? The other url-cookie-*
165;;; are (for now) only used in synchronous retrievals.
aacaa419
LI
166 (url-retrieve-internal url callback (cons nil cbargs) silent
167 inhibit-cookies))
5695d1dd 168
aacaa419
LI
169(defun url-retrieve-internal (url callback cbargs &optional silent
170 inhibit-cookies)
5695d1dd
CY
171 "Internal function; external interface is `url-retrieve'.
172CBARGS is what the callback will actually receive - the first item is
08b8ba9f
LMI
173the list of events, as described in the docstring of `url-retrieve'.
174
aacaa419
LI
175If SILENT, don't message progress reports and the like.
176If INHIBIT-COOKIES, cookies will neither be stored nor sent to
a967e26b
WX
177the server.
178If URL is a multibyte string, it will be encoded as utf-8 and
179URL-encoded before it's used."
8c8b8430
SM
180 (url-do-setup)
181 (url-gc-dead-buffers)
a3f10d3e
CY
182 (when (stringp url)
183 (set-text-properties 0 (length url) nil url)
184 (setq url (url-encode-url url)))
8c8b8430
SM
185 (if (not (vectorp url))
186 (setq url (url-generic-parse-url url)))
187 (if (not (functionp callback))
188 (error "Must provide a callback function to url-retrieve"))
189 (unless (url-type url)
190 (error "Bad url: %s" (url-recreate-url url)))
08b8ba9f 191 (setf (url-silent url) silent)
aacaa419 192 (setf (url-use-cookies url) (not inhibit-cookies))
1968bb1b
LI
193 ;; Once in a while, remove old entries from the URL cache.
194 (when (zerop (% url-retrieve-number-of-calls 1000))
1e54a73b
LI
195 (condition-case error
196 (url-cache-prune-cache)
197 (file-error
198 (message "Error when expiring the cache: %s" error))))
1968bb1b 199 (setq url-retrieve-number-of-calls (1+ url-retrieve-number-of-calls))
8c8b8430
SM
200 (let ((loader (url-scheme-get-property (url-type url) 'loader))
201 (url-using-proxy (if (url-host url)
202 (url-find-proxy-for-url url (url-host url))))
203 (buffer nil)
204 (asynch (url-scheme-get-property (url-type url) 'asynchronous-p)))
205 (if url-using-proxy
206 (setq asynch t
207 loader 'url-proxy))
208 (if asynch
08b8ba9f
LMI
209 (let ((url-current-object url))
210 (setq buffer (funcall loader url callback cbargs)))
8c8b8430
SM
211 (setq buffer (funcall loader url))
212 (if buffer
42b369cd 213 (with-current-buffer buffer
8c8b8430 214 (apply callback cbargs))))
11b5750f
RS
215 (if url-history-track
216 (url-history-update-url url (current-time)))
8c8b8430
SM
217 buffer))
218
2ef88a69 219;;;###autoload
8c8b8430
SM
220(defun url-retrieve-synchronously (url)
221 "Retrieve URL synchronously.
222Return the buffer containing the data, or nil if there are no data
223associated with it (the case for dired, info, or mailto URLs that need
224no further processing). URL is either a string or a parsed URL."
225 (url-do-setup)
226
e95a67dc
SM
227 (let ((retrieval-done nil)
228 (asynch-buffer nil))
8c8b8430
SM
229 (setq asynch-buffer
230 (url-retrieve url (lambda (&rest ignored)
231 (url-debug 'retrieval "Synchronous fetching done (%S)" (current-buffer))
232 (setq retrieval-done t
233 asynch-buffer (current-buffer)))))
7f954571
SM
234 (if (null asynch-buffer)
235 ;; We do not need to do anything, it was a mailto or something
236 ;; similar that takes processing completely outside of the URL
237 ;; package.
238 nil
239 (let ((proc (get-buffer-process asynch-buffer)))
240 ;; If the access method was synchronous, `retrieval-done' should
241 ;; hopefully already be set to t. If it is nil, and `proc' is also
242 ;; nil, it implies that the async process is not running in
243 ;; asynch-buffer. This happens e.g. for FTP files. In such a case
244 ;; url-file.el should probably set something like a `url-process'
245 ;; buffer-local variable so we can find the exact process that we
246 ;; should be waiting for. In the mean time, we'll just wait for any
247 ;; process output.
944b2ab6
SM
248 (while (not retrieval-done)
249 (url-debug 'retrieval
250 "Spinning in url-retrieve-synchronously: %S (%S)"
251 retrieval-done asynch-buffer)
9b4cf231
SM
252 (if (buffer-local-value 'url-redirect-buffer asynch-buffer)
253 (setq proc (get-buffer-process
254 (setq asynch-buffer
255 (buffer-local-value 'url-redirect-buffer
256 asynch-buffer))))
257 (if (and proc (memq (process-status proc)
258 '(closed exit signal failed))
259 ;; Make sure another process hasn't been started.
260 (eq proc (or (get-buffer-process asynch-buffer) proc)))
261 ;; FIXME: It's not clear whether url-retrieve's callback is
262 ;; guaranteed to be called or not. It seems that url-http
263 ;; decides sometimes consciously not to call it, so it's not
264 ;; clear that it's a bug, but even then we need to decide how
265 ;; url-http can then warn us that the download has completed.
266 ;; In the mean time, we use this here workaround.
5695d1dd
CY
267 ;; XXX: The callback must always be called. Any
268 ;; exception is a bug that should be fixed, not worked
269 ;; around.
9ffb9521
RS
270 (progn ;; Call delete-process so we run any sentinel now.
271 (delete-process proc)
272 (setq retrieval-done t)))
799fba8f
SM
273 ;; We used to use `sit-for' here, but in some cases it wouldn't
274 ;; work because apparently pending keyboard input would always
275 ;; interrupt it before it got a chance to handle process input.
276 ;; `sleep-for' was tried but it lead to other forms of
277 ;; hanging. --Stef
da6062e6 278 (unless (or (with-local-quit
947612be
MH
279 (accept-process-output proc))
280 (null proc))
799fba8f 281 ;; accept-process-output returned nil, maybe because the process
947612be
MH
282 ;; exited (and may have been replaced with another). If we got
283 ;; a quit, just stop.
284 (when quit-flag
285 (delete-process proc))
286 (setq proc (and (not quit-flag)
287 (get-buffer-process asynch-buffer)))))))
8c8b8430
SM
288 asynch-buffer)))
289
290(defun url-mm-callback (&rest ignored)
291 (let ((handle (mm-dissect-buffer t)))
7f954571
SM
292 (url-mark-buffer-as-dead (current-buffer))
293 (with-current-buffer
294 (generate-new-buffer (url-recreate-url url-current-object))
8c8b8430
SM
295 (if (eq (mm-display-part handle) 'external)
296 (progn
297 (set-process-sentinel
298 ;; Fixme: this shouldn't have to know the form of the
299 ;; undisplayer produced by `mm-display-part'.
300 (get-buffer-process (cdr (mm-handle-undisplayer handle)))
301 `(lambda (proc event)
302 (mm-destroy-parts (quote ,handle))))
303 (message "Viewing externally")
304 (kill-buffer (current-buffer)))
305 (display-buffer (current-buffer))
71ddfde5 306 (add-hook 'kill-buffer-hook
14e25c87
MY
307 `(lambda () (mm-destroy-parts ',handle))
308 nil
309 t)))))
8c8b8430
SM
310
311(defun url-mm-url (url)
312 "Retrieve URL and pass to the appropriate viewing application."
717c6bde
SM
313 ;; These requires could advantageously be moved to url-mm-callback or
314 ;; turned into autoloads, but I suspect that it would introduce some bugs
315 ;; because loading those files from a process sentinel or filter may
da6062e6 316 ;; result in some undesirable corner cases.
8c8b8430
SM
317 (require 'mm-decode)
318 (require 'mm-view)
319 (url-retrieve url 'url-mm-callback nil))
320
321;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
322;;; Miscellaneous
323;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
324(defvar url-dead-buffer-list nil)
325
326(defun url-mark-buffer-as-dead (buff)
327 (push buff url-dead-buffer-list))
328
329(defun url-gc-dead-buffers ()
330 (let ((buff))
331 (while (setq buff (pop url-dead-buffer-list))
332 (if (buffer-live-p buff)
333 (kill-buffer buff)))))
334
335(cond
336 ((fboundp 'display-warning)
337 (defalias 'url-warn 'display-warning))
338 ((fboundp 'warn)
339 (defun url-warn (class message &optional level)
340 (warn "(%s/%s) %s" class (or level 'warning) message)))
341 (t
342 (defun url-warn (class message &optional level)
42b369cd 343 (with-current-buffer (get-buffer-create "*URL-WARNINGS*")
8c8b8430
SM
344 (goto-char (point-max))
345 (save-excursion
346 (insert (format "(%s/%s) %s\n" class (or level 'warning) message)))
347 (display-buffer (current-buffer))))))
348
349(provide 'url)
350
351;;; url.el ends here