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