1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.html;
16
17 import static org.htmlunit.BrowserVersionFeatures.JS_ANCHOR_PATHNAME_DETECT_WIN_DRIVES_URL_REPLACE;
18 import static org.htmlunit.BrowserVersionFeatures.JS_ANCHOR_PATHNAME_PREFIX_WIN_DRIVES_URL;
19 import static org.htmlunit.BrowserVersionFeatures.JS_ANCHOR_PROTOCOL_COLON_UPPER_CASE_DRIVE_LETTERS;
20 import static org.htmlunit.html.DomElement.ATTRIBUTE_NOT_DEFINED;
21
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.util.Arrays;
25 import java.util.List;
26 import java.util.Locale;
27
28 import org.htmlunit.BrowserVersion;
29 import org.htmlunit.HttpHeader;
30 import org.htmlunit.SgmlPage;
31 import org.htmlunit.html.DomElement;
32 import org.htmlunit.html.DomNode;
33 import org.htmlunit.html.HtmlAnchor;
34 import org.htmlunit.html.HtmlElement;
35 import org.htmlunit.html.HtmlPage;
36 import org.htmlunit.javascript.JavaScriptEngine;
37 import org.htmlunit.javascript.configuration.JsxClass;
38 import org.htmlunit.javascript.configuration.JsxConstructor;
39 import org.htmlunit.javascript.configuration.JsxGetter;
40 import org.htmlunit.javascript.configuration.JsxSetter;
41 import org.htmlunit.javascript.host.dom.DOMTokenList;
42 import org.htmlunit.util.StringUtils;
43 import org.htmlunit.util.UrlUtils;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 @JsxClass(domClass = HtmlAnchor.class)
62 public class HTMLAnchorElement extends HTMLElement {
63 private static final List<String> REFERRER_POLICIES = Arrays.asList(
64 "no-referrer", HttpHeader.ORIGIN_LC, "unsafe-url");
65
66
67
68
69 @Override
70 @JsxConstructor
71 public void jsConstructor() {
72 super.jsConstructor();
73 }
74
75
76
77
78
79 @JsxSetter
80 public void setHref(final String href) {
81 getDomNodeOrDie().setAttribute("href", href);
82 }
83
84
85
86
87
88 @JsxGetter
89 public String getHref() {
90 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
91 final String hrefAttr = anchor.getHrefAttribute();
92
93 if (ATTRIBUTE_NOT_DEFINED == hrefAttr) {
94 return "";
95 }
96
97 try {
98 return getUrl().toString();
99 }
100 catch (final MalformedURLException e) {
101 return hrefAttr;
102 }
103 }
104
105
106
107
108 @Override
109 public void focus() {
110 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
111 final String hrefAttr = anchor.getHrefAttribute();
112
113 if (ATTRIBUTE_NOT_DEFINED != hrefAttr) {
114 anchor.focus();
115 }
116 }
117
118
119
120
121
122 @JsxSetter
123 @Override
124 public void setName(final String name) {
125 getDomNodeOrDie().setAttribute(DomElement.NAME_ATTRIBUTE, name);
126 }
127
128
129
130
131
132 @JsxGetter
133 @Override
134 public String getName() {
135 return getDomNodeOrDie().getAttributeDirect(DomElement.NAME_ATTRIBUTE);
136 }
137
138
139
140
141
142 @JsxSetter
143 public void setTarget(final String target) {
144 getDomNodeOrDie().setAttribute("target", target);
145 }
146
147
148
149
150
151 @JsxGetter
152 public String getTarget() {
153 return getDomNodeOrDie().getAttributeDirect("target");
154 }
155
156
157
158
159
160
161 private URL getUrl() throws MalformedURLException {
162 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
163 return ((HtmlPage) anchor.getPage()).getFullyQualifiedUrl(anchor.getHrefAttribute());
164 }
165
166
167
168
169
170 private void setUrl(final URL url) {
171 getDomNodeOrDie().setAttribute("href", url.toString());
172 }
173
174
175
176
177
178 @JsxSetter
179 public void setRel(final String rel) {
180 getDomNodeOrDie().setAttribute("rel", rel);
181 }
182
183
184
185
186
187 @JsxGetter
188 public String getRel() {
189 return ((HtmlAnchor) getDomNodeOrDie()).getRelAttribute();
190 }
191
192
193
194
195
196 @JsxGetter
197 public String getRev() {
198 return ((HtmlAnchor) getDomNodeOrDie()).getRevAttribute();
199 }
200
201
202
203
204
205 @JsxSetter
206 public void setRev(final String rel) {
207 getDomNodeOrDie().setAttribute("rev", rel);
208 }
209
210
211
212
213
214 @JsxGetter
215 public String getReferrerPolicy() {
216 String attrib = getDomNodeOrDie().getAttribute("referrerPolicy");
217 if (StringUtils.isEmptyOrNull(attrib)) {
218 return "";
219 }
220 attrib = attrib.toLowerCase(Locale.ROOT);
221 if (REFERRER_POLICIES.contains(attrib)) {
222 return attrib;
223 }
224 return "";
225 }
226
227
228
229
230
231 @JsxSetter
232 public void setReferrerPolicy(final String referrerPolicy) {
233 getDomNodeOrDie().setAttribute("referrerPolicy", referrerPolicy);
234 }
235
236
237
238
239
240
241
242 @JsxGetter
243 public String getSearch() {
244 try {
245 return HTMLHyperlinkElementUtils.getSearch(getUrl());
246 }
247 catch (final MalformedURLException e) {
248 return "";
249 }
250 }
251
252
253
254
255
256
257
258
259 @JsxSetter
260 public void setSearch(final String search) throws Exception {
261 setUrl(HTMLHyperlinkElementUtils.setSearch(getUrl(), search));
262 }
263
264
265
266
267
268
269 @JsxGetter
270 public String getHash() {
271 try {
272 return HTMLHyperlinkElementUtils.getHash(getUrl());
273 }
274 catch (final MalformedURLException e) {
275 return "";
276 }
277 }
278
279
280
281
282
283
284
285 @JsxSetter
286 public void setHash(final String hash) throws Exception {
287 setUrl(HTMLHyperlinkElementUtils.setHash(getUrl(), hash));
288 }
289
290
291
292
293
294
295 @JsxGetter
296 public String getHost() {
297 try {
298 final URL url = getUrl();
299 final int port = url.getPort();
300 final String host = url.getHost();
301
302 if (port == -1 || HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), port)) {
303 return host;
304 }
305 return host + ":" + port;
306 }
307 catch (final MalformedURLException e) {
308 return "";
309 }
310 }
311
312
313
314
315
316
317
318 @JsxSetter
319 public void setHost(final String host) throws Exception {
320 setUrl(HTMLHyperlinkElementUtils.setHost(getUrl(), host));
321 }
322
323
324
325
326
327
328 @JsxGetter
329 public String getHostname() {
330 try {
331 return HTMLHyperlinkElementUtils.getHostname(getUrl());
332 }
333 catch (final MalformedURLException e) {
334 return "";
335 }
336 }
337
338
339
340
341
342
343
344 @JsxSetter
345 public void setHostname(String hostname) throws Exception {
346 if (hostname != null) {
347 if (hostname.indexOf(' ') > -1) {
348 return;
349 }
350
351 final int idx = hostname.indexOf('#');
352 if (idx > -1) {
353 hostname = hostname.substring(0, idx);
354 }
355 }
356
357 if (org.htmlunit.util.StringUtils.isEmptyOrNull(hostname)) {
358 return;
359 }
360
361 try {
362 setUrl(UrlUtils.getUrlWithNewHost(getUrl(), hostname));
363 }
364 catch (final MalformedURLException e) {
365
366 }
367 }
368
369
370
371
372
373
374 @JsxGetter
375 public String getPathname() {
376 final BrowserVersion browser = getBrowserVersion();
377 try {
378 if (browser.hasFeature(JS_ANCHOR_PATHNAME_DETECT_WIN_DRIVES_URL_REPLACE)) {
379 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
380 String href = anchor.getHrefAttribute();
381 if (href.length() > 1 && Character.isLetter(href.charAt(0)) && ':' == href.charAt(1)) {
382 if (browser.hasFeature(JS_ANCHOR_PROTOCOL_COLON_UPPER_CASE_DRIVE_LETTERS)) {
383 href = org.apache.commons.lang3.StringUtils.capitalize(href);
384 }
385 if (browser.hasFeature(JS_ANCHOR_PATHNAME_PREFIX_WIN_DRIVES_URL)) {
386 href = "/" + href;
387 }
388 return href;
389 }
390 }
391 return getUrl().getPath();
392 }
393 catch (final MalformedURLException e) {
394 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
395 if (anchor.getHrefAttribute().startsWith("http")) {
396 return "";
397 }
398 return "/";
399 }
400 }
401
402
403
404
405
406
407
408 @JsxSetter
409 public void setPathname(final String pathname) throws Exception {
410 setUrl(HTMLHyperlinkElementUtils.setPathname(getUrl(), pathname));
411 }
412
413
414
415
416
417
418 @JsxGetter
419 public String getPort() {
420 try {
421 final URL url = getUrl();
422 final int port = url.getPort();
423 if (port == -1 || HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), port)) {
424 return "";
425 }
426 return Integer.toString(port);
427 }
428 catch (final MalformedURLException e) {
429 return "";
430 }
431 }
432
433
434
435
436
437
438
439 @JsxSetter
440 public void setPort(final String port) throws Exception {
441 final URL url = getUrl();
442 final int newPort = Integer.parseInt(port);
443 if (HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), newPort)) {
444 setUrl(UrlUtils.getUrlWithNewPort(url, -1));
445 }
446 else {
447 setUrl(UrlUtils.getUrlWithNewPort(url, newPort));
448 }
449 }
450
451
452
453
454
455
456 @JsxGetter
457 public String getProtocol() {
458 final BrowserVersion browser = getBrowserVersion();
459 try {
460 if (browser.hasFeature(JS_ANCHOR_PATHNAME_DETECT_WIN_DRIVES_URL_REPLACE)) {
461 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
462 final String href = anchor.getHrefAttribute().toLowerCase(Locale.ROOT);
463 if (href.length() > 1 && Character.isLetter(href.charAt(0)) && ':' == href.charAt(1)) {
464 return "file:";
465 }
466 }
467
468 return getUrl().getProtocol() + ":";
469 }
470 catch (final MalformedURLException e) {
471 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
472 if (anchor.getHrefAttribute().startsWith("http")) {
473 return ":";
474 }
475 return StringUtils.substringBefore(anchor.getHrefAttribute(), "/");
476 }
477 }
478
479
480
481
482
483
484
485 @JsxSetter
486 public void setProtocol(final String protocol) throws Exception {
487 final URL result = HTMLHyperlinkElementUtils.setProtocol(getUrl(), protocol);
488 if (result != null) {
489 setUrl(result);
490 }
491 }
492
493
494
495
496
497
498
499 @Override
500 public Object getDefaultValue(final Class<?> hint) {
501 final HtmlElement element = getDomNodeOrNull();
502 if (element == null) {
503 return super.getDefaultValue(null);
504 }
505 return getDefaultValue(element);
506 }
507
508 static String getDefaultValue(final HtmlElement element) {
509 String href = element.getAttributeDirect("href");
510
511 if (ATTRIBUTE_NOT_DEFINED == href) {
512 return "";
513 }
514
515 href = href.trim();
516
517 final SgmlPage page = element.getPage();
518 if (page == null || !page.isHtmlPage()) {
519 return href;
520 }
521
522 try {
523 return HtmlAnchor.getTargetUrl(href, (HtmlPage) page).toExternalForm();
524 }
525 catch (final MalformedURLException e) {
526 return href;
527 }
528 }
529
530
531
532
533
534 @JsxGetter
535 public String getText() {
536 final DomNode htmlElement = getDomNodeOrDie();
537 return htmlElement.asNormalizedText();
538 }
539
540
541
542
543
544 @JsxSetter
545 public void setText(final String text) {
546 final DomNode htmlElement = getDomNodeOrDie();
547 htmlElement.setTextContent(text);
548 }
549
550
551
552
553
554 @JsxGetter
555 public String getCharset() {
556 return getDomNodeOrDie().getAttributeDirect("charset");
557 }
558
559
560
561
562
563 @JsxSetter
564 public void setCharset(final String charset) {
565 getDomNodeOrDie().setAttribute("charset", charset);
566 }
567
568
569
570
571
572 @JsxGetter
573 public String getCoords() {
574 return getDomNodeOrDie().getAttributeDirect("coords");
575 }
576
577
578
579
580
581 @JsxSetter
582 public void setCoords(final String coords) {
583 getDomNodeOrDie().setAttribute("coords", coords);
584 }
585
586
587
588
589
590 @JsxGetter
591 public String getHreflang() {
592 return getDomNodeOrDie().getAttributeDirect("hreflang");
593 }
594
595
596
597
598
599 @JsxSetter
600 public void setHreflang(final String hreflang) {
601 getDomNodeOrDie().setAttribute("hreflang", hreflang);
602 }
603
604
605
606
607
608 @JsxGetter
609 public String getOrigin() {
610 if (!getDomNodeOrDie().hasAttribute("href")) {
611 return "";
612 }
613
614 try {
615 return getUrl().getProtocol() + "://" + getHost();
616 }
617 catch (final Exception e) {
618 return "";
619 }
620 }
621
622
623
624
625
626 @JsxGetter
627 public String getUsername() {
628 try {
629 return HTMLHyperlinkElementUtils.getUsername(getUrl());
630 }
631 catch (final MalformedURLException e) {
632 return "";
633 }
634 }
635
636
637
638
639
640 @JsxSetter
641 public void setUsername(final String username) {
642 try {
643 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
644 final String href = anchor.getHrefAttribute();
645 if (ATTRIBUTE_NOT_DEFINED == href) {
646 return;
647 }
648
649 final URL url = ((HtmlPage) anchor.getPage()).getFullyQualifiedUrl(href);
650 setUrl(UrlUtils.getUrlWithNewUserName(url, username));
651 }
652 catch (final MalformedURLException ignored) {
653
654 }
655 }
656
657
658
659
660
661 @JsxGetter
662 public String getPassword() {
663 try {
664 return HTMLHyperlinkElementUtils.getPassword(getUrl());
665 }
666 catch (final MalformedURLException e) {
667 return "";
668 }
669 }
670
671
672
673
674
675 @JsxSetter
676 public void setPassword(final String password) {
677 try {
678 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
679 final String href = anchor.getHrefAttribute();
680 if (ATTRIBUTE_NOT_DEFINED == href) {
681 return;
682 }
683
684 final URL url = ((HtmlPage) anchor.getPage()).getFullyQualifiedUrl(href);
685 setUrl(UrlUtils.getUrlWithNewUserPassword(url, password));
686 }
687 catch (final MalformedURLException ignored) {
688
689 }
690 }
691
692
693
694
695
696 @JsxGetter
697 public String getDownload() {
698 return ((HtmlAnchor) getDomNodeOrDie()).getDownloadAttribute();
699 }
700
701
702
703
704
705 @JsxSetter
706 public void setDownload(final String download) {
707 getDomNodeOrDie().setAttribute("download", download);
708 }
709
710
711
712
713
714 @JsxGetter
715 public String getPing() {
716 return ((HtmlAnchor) getDomNodeOrDie()).getPingAttribute();
717 }
718
719
720
721
722
723 @JsxSetter
724 public void setPing(final String ping) {
725 getDomNodeOrDie().setAttribute("ping", ping);
726 }
727
728
729
730
731
732 @JsxGetter
733 public String getShape() {
734 return getDomNodeOrDie().getAttribute("shape");
735 }
736
737
738
739
740
741 @JsxSetter
742 public void setShape(final String shape) {
743 getDomNodeOrDie().setAttribute("shape", shape);
744 }
745
746
747
748
749
750 @JsxGetter
751 public String getType() {
752 return getDomNodeOrDie().getAttributeDirect(DomElement.TYPE_ATTRIBUTE);
753 }
754
755
756
757
758
759 @JsxSetter
760 public void setType(final String type) {
761 getDomNodeOrDie().setAttribute(DomElement.TYPE_ATTRIBUTE, type);
762 }
763
764
765
766
767
768 @JsxGetter
769 public DOMTokenList getRelList() {
770 return new DOMTokenList(this, "rel");
771 }
772
773
774
775
776
777 @JsxSetter
778 public void setRelList(final Object rel) {
779 setRel(JavaScriptEngine.toString(rel));
780 }
781 }