1 ;;; url-http-ntlm-parse-headers-24.3.el --- Override url-http-parse-headers
3 ;; Copyright (C) 1999, 2001, 2004-2014 Free Software Foundation, Inc.
5 ;; Author: Bill Perry <wmperry@gnu.org>
6 ;; Keywords: comm, data, processes
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
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.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25 ;; Override url-http-parse-headers to clear Authorization headers
26 ;; from url-http-extra-headers prior to executing a redirect. The
27 ;; only change is to apply this backward-compatible patch:
29 ;; diff --git a/lisp/url/url-http.el b/lisp/url/url-http.el
30 ;; index 222dbc9..856b8b7 100644
31 ;; --- a/lisp/url/url-http.el
32 ;; +++ b/lisp/url/url-http.el
33 ;; @@ -620,6 +620,15 @@ should be shown to the user."
34 ;; ;; compute the redirection relative to the URL of the proxy.
36 ;; (url-expand-file-name redirect-uri url-http-target-url)))
37 ;; + ;; Do not automatically include an authorization header in the
38 ;; + ;; redirect. If needed it will be regenerated by the relevant
39 ;; + ;; auth scheme when the new request happens.
40 ;; + (setq url-http-extra-headers
42 ;; + (dolist (header url-http-extra-headers)
43 ;; + (if (not (equal (car header) "Authorization"))
44 ;; + (push header result)))
45 ;; + (nreverse result)))
46 ;; (let ((url-request-method url-http-method)
47 ;; (url-request-data url-http-data)
48 ;; (url-request-extra-headers url-http-extra-headers))
52 (eval-when-compile (require 'cl))
60 (autoload 'url-cache-create-filename "url-cache")
63 (defvar url-http-process)
64 (defvar url-http-end-of-headers)
65 (defvar url-http-response-version)
66 (defvar url-http-response-status)
67 (defvar url-http-target-url)
68 (defvar url-http-method)
69 (defvar url-http-data)
70 (defvar url-http-extra-headers)
71 (defvar url-callback-arguments)
72 (defvar url-callback-function)
74 (defun url-http-parse-headers ()
75 "Parse and handle HTTP specific headers.
76 Return t if and only if the current buffer is still active and
77 should be shown to the user."
78 ;; The comments after each status code handled are taken from RFC
80 (url-http-mark-connection-as-free (url-host url-current-object)
81 (url-port url-current-object)
84 (if (or (not (boundp 'url-http-end-of-headers))
85 (not url-http-end-of-headers))
86 (error "Trying to parse headers in odd buffer: %s" (buffer-name)))
87 (goto-char (point-min))
88 (url-http-debug "url-http-parse-headers called in (%s)" (buffer-name))
89 (url-http-parse-response)
91 ;;(narrow-to-region (point-min) url-http-end-of-headers)
92 (let ((connection (mail-fetch-field "Connection")))
93 ;; In HTTP 1.0, keep the connection only if there is a
94 ;; "Connection: keep-alive" header.
95 ;; In HTTP 1.1 (and greater), keep the connection unless there is a
96 ;; "Connection: close" header
98 ((string= url-http-response-version "1.0")
99 (unless (and connection
100 (string= (downcase connection) "keep-alive"))
101 (delete-process url-http-process)))
103 (when (and connection
104 (string= (downcase connection) "close"))
105 (delete-process url-http-process)))))
106 (let ((buffer (current-buffer))
109 ;; other status symbols: jewelry and luxury cars
110 (status-symbol (cadr (assq url-http-response-status url-http-codes))))
111 (setq class (/ url-http-response-status 100))
112 (url-http-debug "Parsed HTTP headers: class=%d status=%d"
113 class url-http-response-status)
114 (when (url-use-cookies url-http-target-url)
115 (url-http-handle-cookies))
118 ;; Classes of response codes
120 ;; 5xx = Server Error
121 ;; 4xx = Client Error
124 ;; 1xx = Informational
125 (1 ; Information messages
126 ;; 100 = Continue with request
127 ;; 101 = Switching protocols
128 ;; 102 = Processing (Added by DAV)
129 (url-mark-buffer-as-dead buffer)
130 (error "HTTP responses in class 1xx not supported (%d)"
131 url-http-response-status))
136 ;; 203 Non-authoritative information
139 ;; 206 Partial content
140 ;; 207 Multi-status (Added by DAV)
142 ((or `no-content `reset-content)
143 ;; No new data, just stay at the same document
144 (url-mark-buffer-as-dead buffer)
147 ;; Generic success for all others. Store in the cache, and
148 ;; mark it as successful.
150 (if (and url-automatic-caching (equal url-http-method "GET"))
151 (url-store-in-cache buffer))
154 ;; 300 Multiple choices
155 ;; 301 Moved permanently
160 ;; 307 Temporary redirect
161 (let ((redirect-uri (or (mail-fetch-field "Location")
162 (mail-fetch-field "URI"))))
164 (`multiple-choices ; 300
165 ;; Quoth the spec (section 10.3.1)
166 ;; -------------------------------
167 ;; The requested resource corresponds to any one of a set of
168 ;; representations, each with its own specific location and
169 ;; agent-driven negotiation information is being provided so
170 ;; that the user can select a preferred representation and
171 ;; redirect its request to that location.
173 ;; If the server has a preferred choice of representation, it
174 ;; SHOULD include the specific URI for that representation in
175 ;; the Location field; user agents MAY use the Location field
176 ;; value for automatic redirection.
177 ;; -------------------------------
178 ;; We do not support agent-driven negotiation, so we just
179 ;; redirect to the preferred URI if one is provided.
181 ((or `moved-permanently `found `temporary-redirect) ; 301 302 307
182 ;; If the 301|302 status code is received in response to a
183 ;; request other than GET or HEAD, the user agent MUST NOT
184 ;; automatically redirect the request unless it can be
185 ;; confirmed by the user, since this might change the
186 ;; conditions under which the request was issued.
187 (unless (member url-http-method '("HEAD" "GET"))
188 (setq redirect-uri nil)))
190 ;; The response to the request can be found under a different
191 ;; URI and SHOULD be retrieved using a GET method on that
193 (setq url-http-method "GET"
196 ;; The 304 response MUST NOT contain a message-body.
197 (url-http-debug "Extracting document from cache... (%s)"
198 (url-cache-create-filename (url-view-url t)))
199 (url-cache-extract (url-cache-create-filename (url-view-url t)))
200 (setq redirect-uri nil
203 ;; The requested resource MUST be accessed through the
204 ;; proxy given by the Location field. The Location field
205 ;; gives the URI of the proxy. The recipient is expected
206 ;; to repeat this single request via the proxy. 305
207 ;; responses MUST only be generated by origin servers.
208 (error "Redirection thru a proxy server not supported: %s"
211 ;; Treat everything like '300'
214 ;; Clean off any whitespace and/or <...> cruft.
215 (if (string-match "\\([^ \t]+\\)[ \t]" redirect-uri)
216 (setq redirect-uri (match-string 1 redirect-uri)))
217 (if (string-match "^<\\(.*\\)>$" redirect-uri)
218 (setq redirect-uri (match-string 1 redirect-uri)))
220 ;; Some stupid sites (like sourceforge) send a
221 ;; non-fully-qualified URL (ie: /), which royally confuses
223 (if (not (string-match url-nonrelative-link redirect-uri))
224 ;; Be careful to use the real target URL, otherwise we may
225 ;; compute the redirection relative to the URL of the proxy.
227 (url-expand-file-name redirect-uri url-http-target-url)))
228 ;; Do not automatically include an authorization header in the
229 ;; redirect. If needed it will be regenerated by the relevant
230 ;; auth scheme when the new request happens.
231 (setq url-http-extra-headers
233 (dolist (header url-http-extra-headers)
234 (if (not (equal (car header) "Authorization"))
235 (push header result)))
237 (let ((url-request-method url-http-method)
238 (url-request-data url-http-data)
239 (url-request-extra-headers url-http-extra-headers))
240 ;; Check existing number of redirects
241 (if (or (< url-max-redirections 0)
242 (and (> url-max-redirections 0)
243 (let ((events (car url-callback-arguments))
246 (if (eq (car events) :redirect)
247 (setq old-redirects (1+ old-redirects)))
248 (and (setq events (cdr events))
249 (setq events (cdr events))))
250 (< old-redirects url-max-redirections))))
251 ;; url-max-redirections hasn't been reached, so go
252 ;; ahead and redirect.
254 ;; Remember that the request was redirected.
255 (setf (car url-callback-arguments)
256 (nconc (list :redirect redirect-uri)
257 (car url-callback-arguments)))
258 ;; Put in the current buffer a forwarding pointer to the new
259 ;; destination buffer.
260 ;; FIXME: This is a hack to fix url-retrieve-synchronously
261 ;; without changing the API. Instead url-retrieve should
262 ;; either simply not return the "destination" buffer, or it
263 ;; should take an optional `dest-buf' argument.
264 (set (make-local-variable 'url-redirect-buffer)
265 (url-retrieve-internal
266 redirect-uri url-callback-function
267 url-callback-arguments
268 (url-silent url-current-object)
269 (not (url-use-cookies url-current-object))))
270 (url-mark-buffer-as-dead buffer))
271 ;; We hit url-max-redirections, so issue an error and
273 (url-http-debug "Maximum redirections reached")
274 (setf (car url-callback-arguments)
275 (nconc (list :error (list 'error 'http-redirect-limit
277 (car url-callback-arguments)))
278 (setq success t))))))
282 ;; 402 Payment required
285 ;; 405 Method not allowed
286 ;; 406 Not acceptable
287 ;; 407 Proxy authentication required
288 ;; 408 Request time-out
291 ;; 411 Length required
292 ;; 412 Precondition failed
293 ;; 413 Request entity too large
294 ;; 414 Request-URI too large
295 ;; 415 Unsupported media type
296 ;; 416 Requested range not satisfiable
297 ;; 417 Expectation failed
298 ;; 422 Unprocessable Entity (Added by DAV)
300 ;; 424 Failed Dependency
303 ;; The request requires user authentication. The response
304 ;; MUST include a WWW-Authenticate header field containing a
305 ;; challenge applicable to the requested resource. The
306 ;; client MAY repeat the request with a suitable
307 ;; Authorization header field.
308 (url-http-handle-authentication nil))
309 (`payment-required ; 402
310 ;; This code is reserved for future use
311 (url-mark-buffer-as-dead buffer)
312 (error "Somebody wants you to give them money"))
314 ;; The server understood the request, but is refusing to
315 ;; fulfill it. Authorization will not help and the request
316 ;; SHOULD NOT be repeated.
321 (`method-not-allowed ; 405
322 ;; The method specified in the Request-Line is not allowed
323 ;; for the resource identified by the Request-URI. The
324 ;; response MUST include an Allow header containing a list of
325 ;; valid methods for the requested resource.
327 (`not-acceptable ; 406
328 ;; The resource identified by the request is only capable of
329 ;; generating response entities which have content
330 ;; characteristics not acceptable according to the accept
331 ;; headers sent in the request.
333 (`proxy-authentication-required ; 407
334 ;; This code is similar to 401 (Unauthorized), but indicates
335 ;; that the client must first authenticate itself with the
336 ;; proxy. The proxy MUST return a Proxy-Authenticate header
337 ;; field containing a challenge applicable to the proxy for
338 ;; the requested resource.
339 (url-http-handle-authentication t))
340 (`request-timeout ; 408
341 ;; The client did not produce a request within the time that
342 ;; the server was prepared to wait. The client MAY repeat
343 ;; the request without modifications at any later time.
346 ;; The request could not be completed due to a conflict with
347 ;; the current state of the resource. This code is only
348 ;; allowed in situations where it is expected that the user
349 ;; might be able to resolve the conflict and resubmit the
350 ;; request. The response body SHOULD include enough
351 ;; information for the user to recognize the source of the
355 ;; The requested resource is no longer available at the
356 ;; server and no forwarding address is known.
358 (`length-required ; 411
359 ;; The server refuses to accept the request without a defined
360 ;; Content-Length. The client MAY repeat the request if it
361 ;; adds a valid Content-Length header field containing the
362 ;; length of the message-body in the request message.
364 ;; NOTE - this will never happen because
365 ;; `url-http-create-request' automatically calculates the
368 (`precondition-failed ; 412
369 ;; The precondition given in one or more of the
370 ;; request-header fields evaluated to false when it was
371 ;; tested on the server.
373 ((or `request-entity-too-large `request-uri-too-large) ; 413 414
374 ;; The server is refusing to process a request because the
375 ;; request entity|URI is larger than the server is willing or
378 (`unsupported-media-type ; 415
379 ;; The server is refusing to service the request because the
380 ;; entity of the request is in a format not supported by the
381 ;; requested resource for the requested method.
383 (`requested-range-not-satisfiable ; 416
384 ;; A server SHOULD return a response with this status code if
385 ;; a request included a Range request-header field, and none
386 ;; of the range-specifier values in this field overlap the
387 ;; current extent of the selected resource, and the request
388 ;; did not include an If-Range request-header field.
390 (`expectation-failed ; 417
391 ;; The expectation given in an Expect request-header field
392 ;; could not be met by this server, or, if the server is a
393 ;; proxy, the server has unambiguous evidence that the
394 ;; request could not be met by the next-hop server.
397 ;; The request could not be understood by the server due to
398 ;; malformed syntax. The client SHOULD NOT repeat the
399 ;; request without modifications.
401 ;; Tell the callback that an error occurred, and what the
404 (setf (car url-callback-arguments)
405 (nconc (list :error (list 'error 'http url-http-response-status))
406 (car url-callback-arguments)))))
408 ;; 500 Internal server error
409 ;; 501 Not implemented
411 ;; 503 Service unavailable
412 ;; 504 Gateway time-out
413 ;; 505 HTTP version not supported
414 ;; 507 Insufficient storage
416 (pcase url-http-response-status
417 (`not-implemented ; 501
418 ;; The server does not support the functionality required to
419 ;; fulfill the request.
422 ;; The server, while acting as a gateway or proxy, received
423 ;; an invalid response from the upstream server it accessed
424 ;; in attempting to fulfill the request.
426 (`service-unavailable ; 503
427 ;; The server is currently unable to handle the request due
428 ;; to a temporary overloading or maintenance of the server.
429 ;; The implication is that this is a temporary condition
430 ;; which will be alleviated after some delay. If known, the
431 ;; length of the delay MAY be indicated in a Retry-After
432 ;; header. If no Retry-After is given, the client SHOULD
433 ;; handle the response as it would for a 500 response.
435 (`gateway-timeout ; 504
436 ;; The server, while acting as a gateway or proxy, did not
437 ;; receive a timely response from the upstream server
438 ;; specified by the URI (e.g. HTTP, FTP, LDAP) or some other
439 ;; auxiliary server (e.g. DNS) it needed to access in
440 ;; attempting to complete the request.
442 (`http-version-not-supported ; 505
443 ;; The server does not support, or refuses to support, the
444 ;; HTTP protocol version that was used in the request
447 (`insufficient-storage ; 507 (DAV)
448 ;; The method could not be performed on the resource
449 ;; because the server is unable to store the representation
450 ;; needed to successfully complete the request. This
451 ;; condition is considered to be temporary. If the request
452 ;; which received this status code was the result of a user
453 ;; action, the request MUST NOT be repeated until it is
454 ;; requested by a separate user action.
456 ;; Tell the callback that an error occurred, and what the
459 (setf (car url-callback-arguments)
460 (nconc (list :error (list 'error 'http url-http-response-status))
461 (car url-callback-arguments)))))
463 (error "Unknown class of HTTP response code: %d (%d)"
464 class url-http-response-status)))
466 (url-mark-buffer-as-dead buffer))
467 (url-http-debug "Finished parsing HTTP headers: %S" success)
471 (provide 'url-http-ntlm-parse-headers-24.3)
473 ;;; url-http-ntlm-parse-headers-24.3.el ends here