1 /* Title: Pure/General/url.scala |
1 /* Title: Pure/General/url.scala |
2 Author: Makarius |
2 Author: Makarius |
3 |
3 |
4 Basic URL operations. |
4 Basic URL/URI operations. |
5 */ |
5 */ |
6 |
6 |
7 package isabelle |
7 package isabelle |
8 |
8 |
9 |
9 |
10 import java.io.{File => JFile} |
10 import java.io.{File => JFile, InputStream} |
11 import java.nio.file.{Paths, FileSystemNotFoundException} |
11 import java.nio.file.{Paths, FileSystemNotFoundException} |
12 import java.net.{URI, URISyntaxException, URL, MalformedURLException, URLDecoder, URLEncoder} |
12 import java.net.{URI, URISyntaxException, MalformedURLException, URLDecoder, URLEncoder, |
|
13 URLConnection} |
13 import java.util.Locale |
14 import java.util.Locale |
14 import java.util.zip.GZIPInputStream |
15 import java.util.zip.GZIPInputStream |
15 |
16 |
16 |
17 |
17 object Url { |
18 object Url { |
34 def is_malformed(exn: Throwable): Boolean = |
35 def is_malformed(exn: Throwable): Boolean = |
35 exn.isInstanceOf[MalformedURLException] || |
36 exn.isInstanceOf[MalformedURLException] || |
36 exn.isInstanceOf[URISyntaxException] || |
37 exn.isInstanceOf[URISyntaxException] || |
37 exn.isInstanceOf[IllegalArgumentException] |
38 exn.isInstanceOf[IllegalArgumentException] |
38 |
39 |
39 def apply(name: String): URL = |
40 def apply(uri: URI): Url = new Url(uri) |
40 try { new URI(name).toURL } |
|
41 catch { |
|
42 case exn: Throwable if is_malformed(exn) => error("Malformed URL " + quote(name)) |
|
43 } |
|
44 |
41 |
45 def resolve(url: URL, route: String): URL = |
42 def apply(name: String): Url = { |
46 if (route.isEmpty) url else url.toURI.resolve(route).toURL |
43 val uri = |
|
44 try { new URI(name) } |
|
45 catch { |
|
46 case exn: Throwable if is_malformed(exn) => error("Malformed URL " + quote(name)) |
|
47 } |
|
48 Url(uri) |
|
49 } |
47 |
50 |
48 def is_wellformed(name: String): Boolean = |
51 def is_wellformed(name: String): Boolean = |
49 try { Url(name); true } |
52 try { Url(name); true } |
50 catch { case ERROR(_) => false } |
53 catch { case ERROR(_) => false } |
51 |
54 |
52 def is_readable(name: String): Boolean = |
55 def is_readable(name: String): Boolean = |
53 try { Url(name).openStream.close(); true } |
56 try { Url(name).open_stream().close(); true } |
54 catch { case ERROR(_) => false } |
57 catch { case ERROR(_) => false } |
55 |
58 |
56 |
59 |
57 /* file name */ |
60 /* file name */ |
58 |
61 |
59 def file_name(url: URL): String = |
62 def file_name(url: Url): String = |
60 Library.take_suffix[Char](c => c != '/' && c != '\\', url.getFile.toString.toList)._2.mkString |
63 Library.take_suffix[Char](c => c != '/' && c != '\\', |
|
64 url.java_url.getFile.toString.toList)._2.mkString |
61 |
65 |
62 def trim_index(url: URL): URL = { |
66 def trim_index(url: Url): Url = { |
63 Library.try_unprefix("/index.html", url.toString) match { |
67 Library.try_unprefix("/index.html", url.toString) match { |
64 case Some(u) => Url(u) |
68 case Some(u) => Url(u) |
65 case None => |
69 case None => |
66 Library.try_unprefix("/index.php", url.toString) match { |
70 Library.try_unprefix("/index.php", url.toString) match { |
67 case Some(u) => Url(u) |
71 case Some(u) => Url(u) |
77 def encode(s: String): String = URLEncoder.encode(s, UTF8.charset) |
81 def encode(s: String): String = URLEncoder.encode(s, UTF8.charset) |
78 |
82 |
79 |
83 |
80 /* read */ |
84 /* read */ |
81 |
85 |
82 private def read(url: URL, gzip: Boolean): String = |
86 private def read(url: Url, gzip: Boolean): String = |
83 using(url.openStream)(stream => |
87 using(url.open_stream())(stream => |
84 File.read_stream(if (gzip) new GZIPInputStream(stream) else stream)) |
88 File.read_stream(if (gzip) new GZIPInputStream(stream) else stream)) |
85 |
89 |
86 def read(url: URL): String = read(url, false) |
90 def read(url: Url): String = read(url, false) |
87 def read_gzip(url: URL): String = read(url, true) |
91 def read_gzip(url: Url): String = read(url, true) |
88 |
92 |
89 def read(name: String): String = read(Url(name), false) |
93 def read(name: String): String = read(Url(name), false) |
90 def read_gzip(name: String): String = read(Url(name), true) |
94 def read_gzip(name: String): String = read(Url(name), true) |
91 |
95 |
92 |
96 |
144 } |
148 } |
145 else prefix + "/" + suffix |
149 else prefix + "/" + suffix |
146 |
150 |
147 def direct_path(prefix: String): String = append_path(prefix, ".") |
151 def direct_path(prefix: String): String = append_path(prefix, ".") |
148 } |
152 } |
|
153 |
|
154 final class Url private(val uri: URI) { |
|
155 override def toString: String = uri.toString |
|
156 |
|
157 override def hashCode: Int = uri.hashCode |
|
158 override def equals(obj: Any): Boolean = |
|
159 obj match { |
|
160 case other: Url => uri == other.uri |
|
161 case _ => false |
|
162 } |
|
163 |
|
164 def resolve(route: String): Url = |
|
165 if (route.isEmpty) this else new Url(uri.resolve(route)) |
|
166 |
|
167 def java_url: java.net.URL = uri.toURL |
|
168 def open_stream(): InputStream = java_url.openStream() |
|
169 def open_connection(): URLConnection = java_url.openConnection() |
|
170 } |