1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host;
16
17 import static org.htmlunit.BrowserVersionFeatures.JS_ANCHOR_HOSTNAME_IGNORE_BLANK;
18
19 import java.net.MalformedURLException;
20 import java.util.List;
21
22 import org.apache.commons.lang3.StringUtils;
23 import org.htmlunit.corejs.javascript.Context;
24 import org.htmlunit.corejs.javascript.Scriptable;
25 import org.htmlunit.javascript.HtmlUnitScriptable;
26 import org.htmlunit.javascript.JavaScriptEngine;
27 import org.htmlunit.javascript.configuration.JsxClass;
28 import org.htmlunit.javascript.configuration.JsxConstructor;
29 import org.htmlunit.javascript.configuration.JsxConstructorAlias;
30 import org.htmlunit.javascript.configuration.JsxFunction;
31 import org.htmlunit.javascript.configuration.JsxGetter;
32 import org.htmlunit.javascript.configuration.JsxSetter;
33 import org.htmlunit.javascript.configuration.JsxStaticFunction;
34 import org.htmlunit.javascript.host.file.Blob;
35 import org.htmlunit.javascript.host.file.File;
36 import org.htmlunit.util.NameValuePair;
37 import org.htmlunit.util.UrlUtils;
38
39
40
41
42
43
44
45
46
47 @JsxClass
48 public class URL extends HtmlUnitScriptable {
49
50 private java.net.URL url_;
51
52
53
54
55
56
57
58
59
60 @JsxConstructor
61 @JsxConstructorAlias(alias = "webkitURL")
62 public void jsConstructor(final String url, final Object base) {
63 String baseStr = null;
64 if (!JavaScriptEngine.isUndefined(base)) {
65 baseStr = JavaScriptEngine.toString(base);
66 }
67
68 try {
69 if (StringUtils.isBlank(baseStr)) {
70 url_ = UrlUtils.toUrlUnsafe(url);
71 }
72 else {
73 final java.net.URL baseUrl = UrlUtils.toUrlUnsafe(baseStr);
74 url_ = new java.net.URL(baseUrl, url);
75 }
76 url_ = UrlUtils.removeRedundantPort(url_);
77 }
78 catch (final MalformedURLException e) {
79 throw JavaScriptEngine.typeError(e.toString());
80 }
81 }
82
83
84
85
86
87
88
89
90
91
92 @JsxStaticFunction
93 public static String createObjectURL(final Object fileOrBlob) {
94 if (fileOrBlob instanceof File) {
95 final File file = (File) fileOrBlob;
96 return getWindow(file).getDocument().generateBlobUrl(file);
97 }
98
99 if (fileOrBlob instanceof Blob) {
100 final Blob blob = (Blob) fileOrBlob;
101 return getWindow(blob).getDocument().generateBlobUrl(blob);
102 }
103
104 return null;
105 }
106
107
108
109
110
111 @JsxStaticFunction
112 public static void revokeObjectURL(final Scriptable objectURL) {
113 getWindow(objectURL).getDocument().revokeBlobUrl(Context.toString(objectURL));
114 }
115
116
117
118
119 @JsxGetter
120 public String getHash() {
121 if (url_ == null) {
122 return null;
123 }
124 final String ref = url_.getRef();
125 return ref == null ? "" : "#" + ref;
126 }
127
128
129
130
131
132 @JsxSetter
133 public void setHash(final String fragment) throws MalformedURLException {
134 if (url_ == null) {
135 return;
136 }
137 url_ = UrlUtils.getUrlWithNewRef(url_, StringUtils.isEmpty(fragment) ? null : fragment);
138 }
139
140
141
142
143
144 @JsxGetter
145 public String getHost() {
146 if (url_ == null) {
147 return null;
148 }
149 final int port = url_.getPort();
150 return url_.getHost() + (port > 0 ? ":" + port : "");
151 }
152
153
154
155
156
157 @JsxSetter
158 public void setHost(final String host) throws MalformedURLException {
159 if (url_ == null) {
160 return;
161 }
162
163 String newHost = StringUtils.substringBefore(host, ':');
164 if (StringUtils.isEmpty(newHost)) {
165 return;
166 }
167
168 try {
169 int ip = Integer.parseInt(newHost);
170 final StringBuilder ipString = new StringBuilder();
171 ipString.insert(0, ip % 256);
172 ipString.insert(0, '.');
173
174 ip = ip / 256;
175 ipString.insert(0, ip % 256);
176 ipString.insert(0, '.');
177
178 ip = ip / 256;
179 ipString.insert(0, ip % 256);
180 ipString.insert(0, '.');
181 ip = ip / 256;
182 ipString.insert(0, ip % 256);
183
184 newHost = ipString.toString();
185 }
186 catch (final Exception expected) {
187
188 }
189
190 url_ = UrlUtils.getUrlWithNewHost(url_, newHost);
191
192 final String newPort = StringUtils.substringAfter(host, ':');
193 if (StringUtils.isNotBlank(newHost)) {
194 try {
195 url_ = UrlUtils.getUrlWithNewHostAndPort(url_, newHost, Integer.parseInt(newPort));
196 }
197 catch (final Exception expected) {
198
199 }
200 }
201 else {
202 url_ = UrlUtils.getUrlWithNewHost(url_, newHost);
203 }
204
205 url_ = UrlUtils.removeRedundantPort(url_);
206 }
207
208
209
210
211
212 @JsxGetter
213 public String getHostname() {
214 if (url_ == null) {
215 return null;
216 }
217
218 return UrlUtils.encodeAnchor(url_.getHost());
219 }
220
221
222
223
224
225 @JsxSetter
226 public void setHostname(final String hostname) throws MalformedURLException {
227 if (getBrowserVersion().hasFeature(JS_ANCHOR_HOSTNAME_IGNORE_BLANK)) {
228 if (!StringUtils.isBlank(hostname)) {
229 url_ = UrlUtils.getUrlWithNewHost(url_, hostname);
230 }
231 }
232 else if (!StringUtils.isEmpty(hostname)) {
233 url_ = UrlUtils.getUrlWithNewHost(url_, hostname);
234 }
235 }
236
237
238
239
240 @JsxGetter
241 public String getHref() {
242 if (url_ == null) {
243 return null;
244 }
245
246 return jsToString();
247 }
248
249
250
251
252
253 @JsxSetter
254 public void setHref(final String href) throws MalformedURLException {
255 if (url_ == null) {
256 return;
257 }
258
259 url_ = UrlUtils.toUrlUnsafe(href);
260 url_ = UrlUtils.removeRedundantPort(url_);
261 }
262
263
264
265
266 @JsxGetter
267 public Object getOrigin() {
268 if (url_ == null) {
269 return null;
270 }
271
272 if (url_.getPort() < 0 || url_.getPort() == url_.getDefaultPort()) {
273 return url_.getProtocol() + "://" + url_.getHost();
274 }
275
276 return url_.getProtocol() + "://" + url_.getHost() + ':' + url_.getPort();
277 }
278
279
280
281
282 @JsxGetter
283 public URLSearchParams getSearchParams() {
284 if (url_ == null) {
285 return null;
286 }
287
288 final URLSearchParams searchParams = new URLSearchParams(this);
289 searchParams.setParentScope(getParentScope());
290 searchParams.setPrototype(getPrototype(searchParams.getClass()));
291 return searchParams;
292 }
293
294
295
296
297 @JsxGetter
298 public String getPassword() {
299 if (url_ == null) {
300 return null;
301 }
302
303 final String userInfo = url_.getUserInfo();
304 final int idx = userInfo == null ? -1 : userInfo.indexOf(':');
305 return idx == -1 ? "" : userInfo.substring(idx + 1);
306 }
307
308
309
310
311
312 @JsxSetter
313 public void setPassword(final String password) throws MalformedURLException {
314 if (url_ == null) {
315 return;
316 }
317
318 url_ = UrlUtils.getUrlWithNewUserPassword(url_, password.isEmpty() ? null : password);
319 }
320
321
322
323
324 @JsxGetter
325 public String getPathname() {
326 if (url_ == null) {
327 return null;
328 }
329
330 final String path = url_.getPath();
331 return path.isEmpty() ? "/" : path;
332 }
333
334
335
336
337
338 @JsxSetter
339 public void setPathname(final String path) throws MalformedURLException {
340 if (url_ == null) {
341 return;
342 }
343
344 url_ = UrlUtils.getUrlWithNewPath(url_, path.startsWith("/") ? path : "/" + path);
345 }
346
347
348
349
350
351 @JsxGetter
352 public String getPort() {
353 if (url_ == null) {
354 return null;
355 }
356
357 final int port = url_.getPort();
358 return port == -1 ? "" : Integer.toString(port);
359 }
360
361
362
363
364
365 @JsxSetter
366 public void setPort(final String port) throws MalformedURLException {
367 if (url_ == null) {
368 return;
369 }
370 final int portInt = port.isEmpty() ? -1 : Integer.parseInt(port);
371 url_ = UrlUtils.getUrlWithNewPort(url_, portInt);
372 url_ = UrlUtils.removeRedundantPort(url_);
373 }
374
375
376
377
378 @JsxGetter
379 public String getProtocol() {
380 if (url_ == null) {
381 return null;
382 }
383 final String protocol = url_.getProtocol();
384 return protocol.isEmpty() ? "" : (protocol + ":");
385 }
386
387
388
389
390
391 @JsxSetter
392 public void setProtocol(final String protocol) throws MalformedURLException {
393 if (url_ == null || protocol.isEmpty()) {
394 return;
395 }
396
397 final String bareProtocol = StringUtils.substringBefore(protocol, ":").trim();
398 if (!UrlUtils.isValidScheme(bareProtocol)) {
399 return;
400 }
401 if (!UrlUtils.isSpecialScheme(bareProtocol)) {
402 return;
403 }
404
405 try {
406 url_ = UrlUtils.getUrlWithNewProtocol(url_, bareProtocol);
407 url_ = UrlUtils.removeRedundantPort(url_);
408 }
409 catch (final MalformedURLException ignored) {
410
411 }
412 }
413
414
415
416
417 @JsxGetter
418 public String getSearch() {
419 if (url_ == null) {
420 return null;
421 }
422 final String search = url_.getQuery();
423 return search == null ? "" : "?" + search;
424 }
425
426
427
428
429
430 @JsxSetter
431 public void setSearch(final String search) throws MalformedURLException {
432 if (url_ == null) {
433 return;
434 }
435
436 String query;
437 if (search == null
438 || org.htmlunit.util.StringUtils.equalsChar('?', search)
439 || org.htmlunit.util.StringUtils.isEmptyString(search)) {
440 query = null;
441 }
442 else {
443 if (search.charAt(0) == '?') {
444 query = search.substring(1);
445 }
446 else {
447 query = search;
448 }
449 query = UrlUtils.encodeQuery(query);
450 }
451
452 url_ = UrlUtils.getUrlWithNewQuery(url_, query);
453 }
454
455
456
457
458
459
460 public void setSearch(final List<NameValuePair> nameValuePairs) throws MalformedURLException {
461 final StringBuilder newSearch = new StringBuilder();
462 for (final NameValuePair nameValuePair : nameValuePairs) {
463 if (newSearch.length() > 0) {
464 newSearch.append('&');
465 }
466 newSearch
467 .append(UrlUtils.encodeQueryPart(nameValuePair.getName()))
468 .append('=')
469 .append(UrlUtils.encodeQueryPart(nameValuePair.getValue()));
470 }
471
472 url_ = UrlUtils.getUrlWithNewQuery(url_, newSearch.toString());
473 }
474
475
476
477
478 @JsxGetter
479 public String getUsername() {
480 if (url_ == null) {
481 return null;
482 }
483
484 final String userInfo = url_.getUserInfo();
485 if (userInfo == null) {
486 return "";
487 }
488
489 return StringUtils.substringBefore(userInfo, ':');
490 }
491
492
493
494
495
496 @JsxSetter
497 public void setUsername(final String username) throws MalformedURLException {
498 if (url_ == null) {
499 return;
500 }
501 url_ = UrlUtils.getUrlWithNewUserName(url_, username.isEmpty() ? null : username);
502 }
503
504
505
506
507
508
509
510 @Override
511 public Object getDefaultValue(final Class<?> hint) {
512 if (url_ == null) {
513 return super.getDefaultValue(hint);
514 }
515
516 if (StringUtils.isEmpty(url_.getPath())) {
517 return url_.toExternalForm() + "/";
518 }
519 return url_.toExternalForm();
520 }
521
522
523
524
525
526 @JsxFunction
527 public String toJSON() {
528 return jsToString();
529 }
530
531
532
533
534
535 @JsxFunction(functionName = "toString")
536 public String jsToString() {
537 if (StringUtils.isEmpty(url_.getPath())) {
538 try {
539 return UrlUtils.getUrlWithNewPath(url_, "/").toExternalForm();
540 }
541 catch (final MalformedURLException e) {
542 return url_.toExternalForm();
543 }
544 }
545 return url_.toExternalForm();
546 }
547 }