url-expand.el 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. ;;; url-expand.el --- expand-file-name for URLs
  2. ;; Copyright (C) 1999, 2004-2012 Free Software Foundation, Inc.
  3. ;; Keywords: comm, data, processes
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Code:
  16. (require 'url-methods)
  17. (require 'url-util)
  18. (require 'url-parse)
  19. (eval-when-compile (require 'cl))
  20. (defun url-expander-remove-relative-links (name)
  21. ;; Strip . and .. from pathnames
  22. (let ((new (if (not (string-match "^/" name))
  23. (concat "/" name)
  24. name)))
  25. ;; If it ends with a '/.' or '/..', tack on a trailing '/' sot hat
  26. ;; the tests that follow are not too complicated in terms of
  27. ;; looking for '..' or '../', etc.
  28. (if (string-match "/\\.+$" new)
  29. (setq new (concat new "/")))
  30. ;; Remove '/./' first
  31. (while (string-match "/\\(\\./\\)" new)
  32. (setq new (concat (substring new 0 (match-beginning 1))
  33. (substring new (match-end 1)))))
  34. ;; Then remove '/../'
  35. (while (string-match "/\\([^/]*/\\.\\./\\)" new)
  36. (setq new (concat (substring new 0 (match-beginning 1))
  37. (substring new (match-end 1)))))
  38. ;; Remove cruft at the beginning of the string, so people that put
  39. ;; in extraneous '..' because they are morons won't lose.
  40. (while (string-match "^/\\.\\.\\(/\\)" new)
  41. (setq new (substring new (match-beginning 1) nil)))
  42. new))
  43. (defun url-expand-file-name (url &optional default)
  44. "Convert URL to a fully specified URL, and canonicalize it.
  45. Second arg DEFAULT is a URL to start with if URL is relative.
  46. If DEFAULT is nil or missing, the current buffer's URL is used.
  47. Path components that are `.' are removed, and
  48. path components followed by `..' are removed, along with the `..' itself."
  49. (if (and url (not (string-match "^#" url)))
  50. ;; Need to nuke newlines and spaces in the URL, or we open
  51. ;; ourselves up to potential security holes.
  52. (setq url (mapconcat (function (lambda (x)
  53. (if (memq x '(? ?\n ?\r))
  54. ""
  55. (char-to-string x))))
  56. url "")))
  57. ;; Need to figure out how/where to expand the fragment relative to
  58. (setq default (cond
  59. ((vectorp default)
  60. ;; Default URL has already been parsed
  61. default)
  62. (default
  63. ;; They gave us a default URL in non-parsed format
  64. (url-generic-parse-url default))
  65. (url-current-object
  66. ;; We are in a URL-based buffer, use the pre-parsed object
  67. url-current-object)
  68. ((string-match url-nonrelative-link url)
  69. ;; The URL they gave us is absolute, go for it.
  70. nil)
  71. (t
  72. ;; Hmmm - this shouldn't ever happen.
  73. (error "url-expand-file-name confused - no default?"))))
  74. (cond
  75. ((= (length url) 0) ; nil or empty string
  76. (url-recreate-url default))
  77. ((string-match "^#" url) ; Offset link, use it raw
  78. url)
  79. ((string-match url-nonrelative-link url) ; Fully-qualified URL, return it immediately
  80. url)
  81. (t
  82. (let* ((urlobj (url-generic-parse-url url))
  83. (inhibit-file-name-handlers t)
  84. (expander (url-scheme-get-property (url-type default) 'expand-file-name)))
  85. (if (string-match "^//" url)
  86. (setq urlobj (url-generic-parse-url (concat (url-type default) ":"
  87. url))))
  88. (funcall expander urlobj default)
  89. (url-recreate-url urlobj)))))
  90. (defun url-identity-expander (urlobj defobj)
  91. (setf (url-type urlobj) (or (url-type urlobj) (url-type defobj))))
  92. (defun url-default-expander (urlobj defobj)
  93. ;; The default expansion routine - urlobj is modified by side effect!
  94. (if (url-type urlobj)
  95. ;; Well, they told us the scheme, let's just go with it.
  96. nil
  97. (setf (url-type urlobj) (or (url-type urlobj) (url-type defobj)))
  98. (setf (url-port urlobj) (or (url-port urlobj)
  99. (and (string= (url-type urlobj)
  100. (url-type defobj))
  101. (url-port defobj))))
  102. (if (not (string= "file" (url-type urlobj)))
  103. (setf (url-host urlobj) (or (url-host urlobj) (url-host defobj))))
  104. (if (string= "ftp" (url-type urlobj))
  105. (setf (url-user urlobj) (or (url-user urlobj) (url-user defobj))))
  106. (if (string= (url-filename urlobj) "")
  107. (setf (url-filename urlobj) "/"))
  108. (if (string-match "^/" (url-filename urlobj))
  109. nil
  110. (let ((query nil)
  111. (file nil)
  112. (sepchar nil))
  113. (if (string-match "[?#]" (url-filename urlobj))
  114. (setq query (substring (url-filename urlobj) (match-end 0))
  115. file (substring (url-filename urlobj) 0 (match-beginning 0))
  116. sepchar (substring (url-filename urlobj) (match-beginning 0) (match-end 0)))
  117. (setq file (url-filename urlobj)))
  118. ;; We use concat rather than expand-file-name to combine
  119. ;; directory and file name, since urls do not follow the same
  120. ;; rules as local files on all platforms.
  121. (setq file (url-expander-remove-relative-links
  122. (concat (url-file-directory (url-filename defobj)) file)))
  123. (setf (url-filename urlobj)
  124. (if query (concat file sepchar query) file))))))
  125. (provide 'url-expand)
  126. ;;; url-expand.el ends here