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_LOCATION_RELOAD_REFERRER;
18
19 import java.io.IOException;
20 import java.lang.reflect.Method;
21 import java.net.MalformedURLException;
22 import java.net.URL;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.htmlunit.BrowserVersion;
27 import org.htmlunit.Page;
28 import org.htmlunit.WebRequest;
29 import org.htmlunit.WebWindow;
30 import org.htmlunit.corejs.javascript.Context;
31 import org.htmlunit.corejs.javascript.Function;
32 import org.htmlunit.corejs.javascript.FunctionObject;
33 import org.htmlunit.corejs.javascript.ScriptableObject;
34 import org.htmlunit.corejs.javascript.VarScope;
35 import org.htmlunit.html.HtmlPage;
36 import org.htmlunit.javascript.HtmlUnitScriptable;
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.host.event.Event;
41 import org.htmlunit.javascript.host.event.HashChangeEvent;
42 import org.htmlunit.protocol.javascript.JavaScriptURLConnection;
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
61
62
63
64
65 @JsxClass
66 public class Location extends HtmlUnitScriptable {
67
68 private static final Log LOG = LogFactory.getLog(Location.class);
69 private static final String UNKNOWN = "null";
70
71
72
73
74 private Window window_;
75
76 private static final Method METHOD_ASSIGN;
77 private static final Method METHOD_RELOAD;
78 private static final Method METHOD_REPLACE;
79 private static final Method METHOD_TO_STRING;
80
81 private static final Method GETTER_HASH;
82 private static final Method SETTER_HASH;
83
84 private static final Method GETTER_HOST;
85 private static final Method SETTER_HOST;
86
87 private static final Method GETTER_HOSTNAME;
88 private static final Method SETTER_HOSTNAME;
89
90 private static final Method GETTER_HREF;
91 private static final Method SETTER_HREF;
92
93 private static final Method GETTER_ORIGIN;
94
95 private static final Method GETTER_PATHNAME;
96 private static final Method SETTER_PATHNAME;
97
98 private static final Method GETTER_PORT;
99 private static final Method SETTER_PORT;
100
101 private static final Method GETTER_PROTOCOL;
102 private static final Method SETTER_PROTOCOL;
103
104 private static final Method GETTER_SEARCH;
105 private static final Method SETTER_SEARCH;
106
107 static {
108 try {
109 METHOD_ASSIGN = Location.class.getDeclaredMethod("assign", String.class);
110 METHOD_RELOAD = Location.class.getDeclaredMethod("reload", boolean.class);
111 METHOD_REPLACE = Location.class.getDeclaredMethod("replace", String.class);
112 METHOD_TO_STRING = Location.class.getDeclaredMethod("jsToString");
113
114 GETTER_HASH = Location.class.getDeclaredMethod("getHash");
115 SETTER_HASH = Location.class.getDeclaredMethod("setHash", String.class);
116
117 GETTER_HOST = Location.class.getDeclaredMethod("getHost");
118 SETTER_HOST = Location.class.getDeclaredMethod("setHost", String.class);
119
120 GETTER_HOSTNAME = Location.class.getDeclaredMethod("getHostname");
121 SETTER_HOSTNAME = Location.class.getDeclaredMethod("setHostname", String.class);
122
123 GETTER_HREF = Location.class.getDeclaredMethod("getHref");
124 SETTER_HREF = Location.class.getDeclaredMethod("setHref", String.class);
125
126 GETTER_ORIGIN = Location.class.getDeclaredMethod("getOrigin");
127
128 GETTER_PATHNAME = Location.class.getDeclaredMethod("getPathname");
129 SETTER_PATHNAME = Location.class.getDeclaredMethod("setPathname", String.class);
130
131 GETTER_PORT = Location.class.getDeclaredMethod("getPort");
132 SETTER_PORT = Location.class.getDeclaredMethod("setPort", String.class);
133
134 GETTER_PROTOCOL = Location.class.getDeclaredMethod("getProtocol");
135 SETTER_PROTOCOL = Location.class.getDeclaredMethod("setProtocol", String.class);
136
137 GETTER_SEARCH = Location.class.getDeclaredMethod("getSearch");
138 SETTER_SEARCH = Location.class.getDeclaredMethod("setSearch", String.class);
139 }
140 catch (NoSuchMethodException | SecurityException e) {
141 throw new RuntimeException(e);
142 }
143 }
144
145
146
147
148
149 private String hash_;
150
151
152
153
154
155
156
157
158
159
160
161 @JsxConstructor
162 public static Location jsConstructor(final Context cx, final VarScope scope,
163 final Object[] args, final Function ctorObj, final boolean inNewExpr) {
164
165 final Location location = new Location();
166 location.setParentScope(scope);
167 location.setPrototype(((FunctionObject) ctorObj).getClassPrototype());
168
169 location.initialize(scope, null, null);
170
171 return location;
172 }
173
174
175
176
177
178
179
180
181 public void initialize(final VarScope scope, final Window window, final Page page) {
182 final int attributes = ScriptableObject.PERMANENT | ScriptableObject.READONLY;
183
184 FunctionObject functionObject = new FunctionObject(METHOD_ASSIGN.getName(), METHOD_ASSIGN, scope);
185 defineProperty(METHOD_ASSIGN.getName(), functionObject, attributes);
186
187 functionObject = new FunctionObject(METHOD_RELOAD.getName(), METHOD_RELOAD, scope);
188 defineProperty(METHOD_RELOAD.getName(), functionObject, attributes);
189
190 functionObject = new FunctionObject(METHOD_REPLACE.getName(), METHOD_REPLACE, scope);
191 defineProperty(METHOD_REPLACE.getName(), functionObject, attributes);
192
193 functionObject = new FunctionObject(METHOD_TO_STRING.getName(), METHOD_TO_STRING, scope);
194 defineProperty("toString", functionObject, attributes);
195
196 defineProperty(scope, "hash", null, GETTER_HASH, SETTER_HASH, attributes);
197 defineProperty(scope, "host", null, GETTER_HOST, SETTER_HOST, attributes);
198 defineProperty(scope, "hostname", null, GETTER_HOSTNAME, SETTER_HOSTNAME, attributes);
199 defineProperty(scope, "href", null, GETTER_HREF, SETTER_HREF, attributes);
200 defineProperty(scope, "origin", null, GETTER_ORIGIN, null, attributes);
201 defineProperty(scope, "pathname", null, GETTER_PATHNAME, SETTER_PATHNAME, attributes);
202 defineProperty(scope, "port", null, GETTER_PORT, SETTER_PORT, attributes);
203 defineProperty(scope, "protocol", null, GETTER_PROTOCOL, SETTER_PROTOCOL, attributes);
204 defineProperty(scope, "search", null, GETTER_SEARCH, SETTER_SEARCH, attributes);
205
206 window_ = window;
207 if (window_ != null && page != null) {
208 setHash(null, page.getUrl().getRef());
209 }
210 }
211
212
213
214
215 @Override
216 public Object getDefaultValue(final Class<?> hint) {
217 if (getPrototype() != null
218 && window_ != null
219 && (hint == null || String.class.equals(hint))) {
220 return getHref();
221 }
222 return super.getDefaultValue(hint);
223 }
224
225
226
227
228
229
230
231
232 public void assign(final String url) throws IOException {
233 setHref(url);
234 }
235
236
237
238
239
240
241
242
243
244 public void reload(final boolean force) throws IOException {
245 final WebWindow webWindow = window_.getWebWindow();
246 final HtmlPage htmlPage = (HtmlPage) webWindow.getEnclosedPage();
247 final WebRequest request = htmlPage.getWebResponse().getWebRequest();
248
249
250 request.setUrl(new URL(getHref()));
251 if (getBrowserVersion().hasFeature(JS_LOCATION_RELOAD_REFERRER)) {
252 request.setRefererHeader(htmlPage.getUrl());
253 }
254
255 webWindow.getWebClient().download(webWindow, "", request, false, null, "JS location.reload");
256 }
257
258
259
260
261
262
263
264
265
266 public void replace(final String url) throws IOException {
267 window_.getWebWindow().getHistory().removeCurrent();
268 setHref(url);
269 }
270
271
272
273
274
275
276 public String jsToString() {
277 if (window_ != null) {
278 return getHref();
279 }
280 return "";
281 }
282
283
284
285
286
287
288
289 public String getHref() {
290 final WebWindow webWindow = window_.getWebWindow();
291 final Page page = webWindow.getEnclosedPage();
292 if (page == null) {
293 return UNKNOWN;
294 }
295 try {
296 URL url = page.getUrl();
297 final String hash = getHash(true);
298 if (hash != null) {
299 url = UrlUtils.getUrlWithNewRef(url, hash);
300 }
301 String s = url.toExternalForm();
302 if (s.startsWith("file:/") && !s.startsWith("file:///")) {
303
304
305 s = "file:///" + s.substring("file:/".length());
306 }
307 return s;
308 }
309 catch (final MalformedURLException e) {
310 if (LOG.isErrorEnabled()) {
311 LOG.error(e.getMessage(), e);
312 }
313 return page.getUrl().toExternalForm();
314 }
315 }
316
317
318
319
320
321
322
323
324 public void setHref(final String newLocation) throws IOException {
325 if (newLocation.startsWith(JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
326 final String script = newLocation.substring(11);
327 final HtmlPage page = (HtmlPage) window_.getWebWindow().getEnclosedPage();
328 page.executeJavaScript(script, "new location value", 1);
329 return;
330 }
331
332 try {
333
334 WebWindow webWindow = ((Window) JavaScriptEngine.getTopCallScope().getGlobalThis()).getWebWindow();
335 final HtmlPage callingPage = (HtmlPage) webWindow.getEnclosedPage();
336
337 final BrowserVersion browserVersion = webWindow.getWebClient().getBrowserVersion();
338
339 URL url = callingPage.getFullyQualifiedUrl(newLocation);
340
341 if (StringUtils.isEmptyOrNull(newLocation)) {
342 url = UrlUtils.getUrlWithNewRef(url, null);
343 }
344
345 final WebRequest webRequest = new WebRequest(url,
346 browserVersion.getHtmlAcceptHeader(), browserVersion.getAcceptEncodingHeader());
347 webRequest.setRefererHeader(callingPage.getUrl());
348
349 webRequest.markAsNavigation(getUrl(), false);
350 webRequest.setFetchModeOverride(WebRequest.FetchMode.NAVIGATE);
351
352 webWindow = window_.getWebWindow();
353 webWindow.getWebClient().download(webWindow, "", webRequest, true, null, "JS set location");
354 }
355 catch (final MalformedURLException e) {
356 if (LOG.isErrorEnabled()) {
357 LOG.error("setHref('" + newLocation + "') got MalformedURLException", e);
358 }
359 throw e;
360 }
361 }
362
363
364
365
366
367
368
369 public String getSearch() {
370 final URL url = getUrl();
371 final String search = url.getQuery();
372 if (StringUtils.isEmptyOrNull(search)) {
373 return "";
374 }
375 return "?" + search;
376 }
377
378
379
380
381
382
383
384
385 public void setSearch(final String search) throws Exception {
386 setUrl(UrlUtils.getUrlWithNewQuery(getUrl(), search));
387 }
388
389
390
391
392
393
394
395 public String getHash() {
396 if (StringUtils.isEmptyOrNull(hash_)) {
397 return "";
398 }
399
400 if (hash_.indexOf('%') == -1) {
401 return "#" + UrlUtils.encodeHash(hash_);
402 }
403 return "#" + UrlUtils.encodeHash(UrlUtils.decode(hash_));
404 }
405
406 private String getHash(final boolean encoded) {
407 if (hash_ == null || hash_.isEmpty()) {
408 return null;
409 }
410 if (encoded) {
411 return UrlUtils.encodeHash(hash_);
412 }
413 return hash_;
414 }
415
416
417
418
419
420
421
422
423 public void setHash(final String hash) {
424
425
426 setHash(getHref(), hash, true);
427 }
428
429
430
431
432
433
434
435 public void setHash(final String oldURL, final String hash) {
436 setHash(oldURL, hash, true);
437 }
438
439
440
441
442
443
444
445
446
447
448 public void setHash(final String oldURL, String hash, final boolean triggerHashChanged) {
449
450
451 if (hash != null && !hash.isEmpty() && hash.charAt(0) == '#') {
452 hash = hash.substring(1);
453 }
454 final boolean hasChanged = hash != null && !hash.equals(hash_);
455 hash_ = hash;
456
457 if (hasChanged) {
458 final Window w = getWindow();
459 final Page page = w.getWebWindow().getEnclosedPage();
460 if (page != null) {
461 final WebRequest request = page.getWebResponse().getWebRequest();
462 request.setUrl(UrlUtils.toUrlSafe(getHref()));
463 }
464
465 if (triggerHashChanged) {
466 final Event event = new HashChangeEvent(w, Event.TYPE_HASH_CHANGE, oldURL, getHref());
467 w.executeEventLocally(event);
468 }
469 }
470 }
471
472
473
474
475
476
477
478 public String getHostname() {
479 return getUrl().getHost();
480 }
481
482
483
484
485
486
487
488
489 public void setHostname(final String hostname) throws Exception {
490 setUrl(UrlUtils.getUrlWithNewHost(getUrl(), hostname));
491 }
492
493
494
495
496
497
498
499 public String getHost() {
500 final URL url = getUrl();
501 final int port = url.getPort();
502 final String host = url.getHost();
503
504 if (port == -1) {
505 return host;
506 }
507 return host + ":" + port;
508 }
509
510
511
512
513
514
515
516
517 public void setHost(final String host) throws Exception {
518 final String hostname;
519 final int port;
520 final int index = host.indexOf(':');
521 if (index == -1) {
522 hostname = host;
523 port = -1;
524 }
525 else {
526 hostname = host.substring(0, index);
527 port = Integer.parseInt(host.substring(index + 1));
528 }
529 final URL url = UrlUtils.getUrlWithNewHostAndPort(getUrl(), hostname, port);
530 setUrl(url);
531 }
532
533
534
535
536
537
538
539 public String getPathname() {
540 if (UrlUtils.URL_ABOUT_BLANK == getUrl()) {
541 return "blank";
542 }
543 return getUrl().getPath();
544 }
545
546
547
548
549
550
551
552
553 public void setPathname(final String pathname) throws Exception {
554 setUrl(UrlUtils.getUrlWithNewPath(getUrl(), pathname));
555 }
556
557
558
559
560
561
562
563 public String getPort() {
564 final int port = getUrl().getPort();
565 if (port == -1) {
566 return "";
567 }
568 return Integer.toString(port);
569 }
570
571
572
573
574
575
576
577
578 public void setPort(final String port) throws Exception {
579 setUrl(UrlUtils.getUrlWithNewPort(getUrl(), Integer.parseInt(port)));
580 }
581
582
583
584
585
586
587
588 public String getProtocol() {
589 return getUrl().getProtocol() + ":";
590 }
591
592
593
594
595
596
597
598
599 public void setProtocol(final String protocol) throws Exception {
600 setUrl(UrlUtils.getUrlWithNewProtocol(getUrl(), protocol));
601 }
602
603
604
605
606
607
608 private URL getUrl() {
609 return window_.getWebWindow().getEnclosedPage().getUrl();
610 }
611
612
613
614
615
616
617
618
619 private void setUrl(final URL url) throws IOException {
620 final WebWindow webWindow = window_.getWebWindow();
621 final BrowserVersion browserVersion = webWindow.getWebClient().getBrowserVersion();
622
623 final WebRequest webRequest = new WebRequest(url,
624 browserVersion.getHtmlAcceptHeader(), browserVersion.getAcceptEncodingHeader());
625
626 webRequest.markAsNavigation(getUrl(), false);
627 webRequest.setFetchModeOverride(WebRequest.FetchMode.NAVIGATE);
628
629 webRequest.setRefererHeader(getUrl());
630
631 webWindow.getWebClient().getPage(webWindow, webRequest);
632 }
633
634
635
636
637
638
639 public String getOrigin() {
640 return getUrl().getProtocol() + "://" + getHost();
641 }
642 }