View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host;
16  
17  import static org.htmlunit.BrowserVersionFeatures.JS_LOCATION_IGNORE_QUERY_FOR_ABOUT_PROTOCOL;
18  import static org.htmlunit.BrowserVersionFeatures.JS_LOCATION_RELOAD_REFERRER;
19  
20  import java.io.IOException;
21  import java.lang.reflect.Method;
22  import java.net.MalformedURLException;
23  import java.net.URL;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.htmlunit.BrowserVersion;
28  import org.htmlunit.Page;
29  import org.htmlunit.WebRequest;
30  import org.htmlunit.WebWindow;
31  import org.htmlunit.corejs.javascript.Context;
32  import org.htmlunit.corejs.javascript.Function;
33  import org.htmlunit.corejs.javascript.FunctionObject;
34  import org.htmlunit.corejs.javascript.ScriptableObject;
35  import org.htmlunit.corejs.javascript.VarScope;
36  import org.htmlunit.html.HtmlPage;
37  import org.htmlunit.javascript.HtmlUnitScriptable;
38  import org.htmlunit.javascript.JavaScriptEngine;
39  import org.htmlunit.javascript.configuration.JsxClass;
40  import org.htmlunit.javascript.configuration.JsxConstructor;
41  import org.htmlunit.javascript.host.event.Event;
42  import org.htmlunit.javascript.host.event.HashChangeEvent;
43  import org.htmlunit.protocol.javascript.JavaScriptURLConnection;
44  import org.htmlunit.util.StringUtils;
45  import org.htmlunit.util.UrlUtils;
46  
47  /**
48   * JavaScript host object for {@code Location}.
49   *
50   * @author Mike Bowler
51   * @author Michael Ottati
52   * @author Marc Guillemot
53   * @author Chris Erskine
54   * @author Daniel Gredler
55   * @author David K. Taylor
56   * @author Ahmed Ashour
57   * @author Ronald Brill
58   * @author Frank Danek
59   * @author Adam Afeltowicz
60   * @author Atsushi Nakagawa
61   * @author Lai Quang Duong
62   * @author Kanoko Yamamoto
63   *
64   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location">MDN Documentation</a>
65   */
66  @JsxClass
67  public class Location extends HtmlUnitScriptable {
68  
69      private static final Log LOG = LogFactory.getLog(Location.class);
70      private static final String UNKNOWN = "null";
71  
72      /**
73       * The window which owns this location object.
74       */
75      private Window window_;
76  
77      private static final Method METHOD_ASSIGN;
78      private static final Method METHOD_RELOAD;
79      private static final Method METHOD_REPLACE;
80      private static final Method METHOD_TO_STRING;
81  
82      private static final Method GETTER_HASH;
83      private static final Method SETTER_HASH;
84  
85      private static final Method GETTER_HOST;
86      private static final Method SETTER_HOST;
87  
88      private static final Method GETTER_HOSTNAME;
89      private static final Method SETTER_HOSTNAME;
90  
91      private static final Method GETTER_HREF;
92      private static final Method SETTER_HREF;
93  
94      private static final Method GETTER_ORIGIN;
95  
96      private static final Method GETTER_PATHNAME;
97      private static final Method SETTER_PATHNAME;
98  
99      private static final Method GETTER_PORT;
100     private static final Method SETTER_PORT;
101 
102     private static final Method GETTER_PROTOCOL;
103     private static final Method SETTER_PROTOCOL;
104 
105     private static final Method GETTER_SEARCH;
106     private static final Method SETTER_SEARCH;
107 
108     static {
109         try {
110             METHOD_ASSIGN = Location.class.getDeclaredMethod("assign", String.class);
111             METHOD_RELOAD = Location.class.getDeclaredMethod("reload", boolean.class);
112             METHOD_REPLACE = Location.class.getDeclaredMethod("replace", String.class);
113             METHOD_TO_STRING = Location.class.getDeclaredMethod("jsToString");
114 
115             GETTER_HASH = Location.class.getDeclaredMethod("getHash");
116             SETTER_HASH = Location.class.getDeclaredMethod("setHash", String.class);
117 
118             GETTER_HOST = Location.class.getDeclaredMethod("getHost");
119             SETTER_HOST = Location.class.getDeclaredMethod("setHost", String.class);
120 
121             GETTER_HOSTNAME = Location.class.getDeclaredMethod("getHostname");
122             SETTER_HOSTNAME = Location.class.getDeclaredMethod("setHostname", String.class);
123 
124             GETTER_HREF = Location.class.getDeclaredMethod("getHref");
125             SETTER_HREF = Location.class.getDeclaredMethod("setHref", String.class);
126 
127             GETTER_ORIGIN = Location.class.getDeclaredMethod("getOrigin");
128 
129             GETTER_PATHNAME = Location.class.getDeclaredMethod("getPathname");
130             SETTER_PATHNAME = Location.class.getDeclaredMethod("setPathname", String.class);
131 
132             GETTER_PORT = Location.class.getDeclaredMethod("getPort");
133             SETTER_PORT = Location.class.getDeclaredMethod("setPort", String.class);
134 
135             GETTER_PROTOCOL = Location.class.getDeclaredMethod("getProtocol");
136             SETTER_PROTOCOL = Location.class.getDeclaredMethod("setProtocol", String.class);
137 
138             GETTER_SEARCH = Location.class.getDeclaredMethod("getSearch");
139             SETTER_SEARCH = Location.class.getDeclaredMethod("setSearch", String.class);
140         }
141         catch (NoSuchMethodException | SecurityException e) {
142             throw new RuntimeException(e);
143         }
144     }
145 
146     /**
147      * The current hash; cached locally to avoid modifying the page's URL and
148      * forcing a page reload each time this changes.
149      */
150     private String hash_;
151 
152     /**
153      * Creates an instance of this object.
154      *
155      * @param cx the current context
156      * @param scope the scope
157      * @param args the constructor arguments
158      * @param ctorObj the function object
159      * @param inNewExpr whether invoked via {@code new}
160      * @return the new {@code Location} instance
161      */
162     @JsxConstructor
163     public static Location jsConstructor(final Context cx, final VarScope scope,
164             final Object[] args, final Function ctorObj, final boolean inNewExpr) {
165 
166         final Location location = new Location();
167         location.setParentScope(scope);
168         location.setPrototype(((FunctionObject) ctorObj).getClassPrototype());
169 
170         location.initialize(scope, null, null);
171 
172         return location;
173     }
174 
175     /**
176      * Initializes this {@code Location}.
177      *
178      * @param scope the scope
179      * @param window the window that this location belongs to
180      * @param page the page that will become the enclosing page
181      */
182     public void initialize(final VarScope scope, final Window window, final Page page) {
183         final int attributes = ScriptableObject.PERMANENT | ScriptableObject.READONLY;
184 
185         FunctionObject functionObject = new FunctionObject(METHOD_ASSIGN.getName(), METHOD_ASSIGN, scope);
186         defineProperty(METHOD_ASSIGN.getName(), functionObject, attributes);
187 
188         functionObject = new FunctionObject(METHOD_RELOAD.getName(), METHOD_RELOAD, scope);
189         defineProperty(METHOD_RELOAD.getName(), functionObject, attributes);
190 
191         functionObject = new FunctionObject(METHOD_REPLACE.getName(), METHOD_REPLACE, scope);
192         defineProperty(METHOD_REPLACE.getName(), functionObject, attributes);
193 
194         functionObject = new FunctionObject(METHOD_TO_STRING.getName(), METHOD_TO_STRING, scope);
195         defineProperty("toString", functionObject, attributes);
196 
197         defineProperty(scope, "hash", null, GETTER_HASH, SETTER_HASH, attributes);
198         defineProperty(scope, "host", null, GETTER_HOST, SETTER_HOST, attributes);
199         defineProperty(scope, "hostname", null, GETTER_HOSTNAME, SETTER_HOSTNAME, attributes);
200         defineProperty(scope, "href", null, GETTER_HREF, SETTER_HREF, attributes);
201         defineProperty(scope, "origin", null, GETTER_ORIGIN, null, attributes);
202         defineProperty(scope, "pathname", null, GETTER_PATHNAME, SETTER_PATHNAME, attributes);
203         defineProperty(scope, "port", null, GETTER_PORT, SETTER_PORT, attributes);
204         defineProperty(scope, "protocol", null, GETTER_PROTOCOL, SETTER_PROTOCOL, attributes);
205         defineProperty(scope, "search", null, GETTER_SEARCH, SETTER_SEARCH, attributes);
206 
207         window_ = window;
208         if (window_ != null && page != null) {
209             setHash(null, page.getUrl().getRef());
210         }
211     }
212 
213     /**
214      * {@inheritDoc}
215      */
216     @Override
217     public Object getDefaultValue(final Class<?> hint) {
218         if (getPrototype() != null
219                 && window_ != null
220                 && (hint == null || String.class.equals(hint))) {
221             return getHref();
222         }
223         return super.getDefaultValue(hint);
224     }
225 
226     /**
227      * Loads the new HTML document corresponding to the specified URL.
228      *
229      * @param url the URL of the new HTML document to load
230      * @throws IOException if loading the specified location fails
231      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/assign">MDN Documentation</a>
232      */
233     public void assign(final String url) throws IOException {
234         setHref(url);
235     }
236 
237     /**
238      * Reloads the current page, optionally forcing retrieval from the server even if
239      * the browser cache contains the latest version of the document.
240      *
241      * @param force if {@code true}, force reload from the server; otherwise, the browser may reload from cache
242      * @throws IOException if there is a problem reloading the page
243      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/reload">MDN Documentation</a>
244      */
245     public void reload(final boolean force) throws IOException {
246         final WebWindow webWindow = window_.getWebWindow();
247         final HtmlPage htmlPage = (HtmlPage) webWindow.getEnclosedPage();
248         final WebRequest request = htmlPage.getWebResponse().getWebRequest();
249 
250         // update request url with location.href in case hash was changed
251         request.setUrl(new URL(getHref()));
252         if (getBrowserVersion().hasFeature(JS_LOCATION_RELOAD_REFERRER)) {
253             request.setRefererHeader(htmlPage.getUrl());
254         }
255 
256         webWindow.getWebClient().download(webWindow, "", request, false, null, "JS location.reload");
257     }
258 
259     /**
260      * Loads the document at the specified URL, replacing the current entry in the session history
261      * so that the previous page cannot be reached via the back button.
262      *
263      * @param url the new URL to load
264      * @throws IOException if loading the specified location fails
265      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/replace">MDN Documentation</a>
266      */
267     public void replace(final String url) throws IOException {
268         window_.getWebWindow().getHistory().removeCurrent();
269         setHref(url);
270     }
271 
272     /**
273      * Returns the location URL as a string.
274      *
275      * @return the location URL
276      */
277     public String jsToString() {
278         if (window_ != null) {
279             return getHref();
280         }
281         return "";
282     }
283 
284     /**
285      * Returns the full URL of the current page.
286      *
287      * @return the location URL
288      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/href">MDN Documentation</a>
289      */
290     public String getHref() {
291         final WebWindow webWindow = window_.getWebWindow();
292         final Page page = webWindow.getEnclosedPage();
293         if (page == null) {
294             return UNKNOWN;
295         }
296         try {
297             URL url = page.getUrl();
298             final String hash = getHash(true);
299             if (hash != null) {
300                 url = UrlUtils.getUrlWithNewRef(url, hash);
301             }
302             String s = url.toExternalForm();
303             if (s.startsWith("file:/") && !s.startsWith("file:///")) {
304                 // Java (sometimes?) returns file URLs with a single slash; however, browsers return
305                 // three slashes. See http://www.cyanwerks.com/file-url-formats.html for more info.
306                 s = "file:///" + s.substring("file:/".length());
307             }
308             return s;
309         }
310         catch (final MalformedURLException e) {
311             if (LOG.isErrorEnabled()) {
312                 LOG.error(e.getMessage(), e);
313             }
314             return page.getUrl().toExternalForm();
315         }
316     }
317 
318     /**
319      * Sets the location URL to an entirely new value, navigating to the new page.
320      *
321      * @param newLocation the new location URL
322      * @throws IOException if loading the specified location fails
323      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/href">MDN Documentation</a>
324      */
325     public void setHref(final String newLocation) throws IOException {
326         if (newLocation.startsWith(JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
327             final String script = newLocation.substring(11);
328             final HtmlPage page = (HtmlPage) window_.getWebWindow().getEnclosedPage();
329             page.executeJavaScript(script, "new location value", 1);
330             return;
331         }
332 
333         try {
334             // we need to get the caller window to get the calling page
335             WebWindow webWindow = ((Window) JavaScriptEngine.getTopCallScope().getGlobalThis()).getWebWindow();
336             final HtmlPage callingPage = (HtmlPage) webWindow.getEnclosedPage();
337 
338             final BrowserVersion browserVersion = webWindow.getWebClient().getBrowserVersion();
339 
340             URL url = callingPage.getFullyQualifiedUrl(newLocation);
341             // fix for empty url
342             if (StringUtils.isEmptyOrNull(newLocation)) {
343                 url = UrlUtils.getUrlWithNewRef(url, null);
344             }
345 
346             final WebRequest webRequest = new WebRequest(url,
347                         browserVersion.getHtmlAcceptHeader(), browserVersion.getAcceptEncodingHeader());
348             webRequest.setRefererHeader(callingPage.getUrl());
349 
350             webRequest.markAsNavigation(getUrl(), false);
351             webRequest.setFetchModeOverride(WebRequest.FetchMode.NAVIGATE);
352 
353             webWindow = window_.getWebWindow();
354             webWindow.getWebClient().download(webWindow, "", webRequest, true, null, "JS set location");
355         }
356         catch (final MalformedURLException e) {
357             if (LOG.isErrorEnabled()) {
358                 LOG.error("setHref('" + newLocation + "') got MalformedURLException", e);
359             }
360             throw e;
361         }
362     }
363 
364     /**
365      * Returns the search portion of the location URL (the portion following the {@code ?}).
366      *
367      * @return the search portion of the location URL
368      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/search">MDN Documentation</a>
369      */
370     public String getSearch() {
371         final URL url = getUrl();
372         final String search = url.getQuery();
373         if (StringUtils.isEmptyOrNull(search)) {
374             return "";
375         }
376 
377         if (StringUtils.startsWithIgnoreCase(url.getProtocol(), UrlUtils.ABOUT)
378                 && window_.getWebWindow().getWebClient().getBrowserVersion()
379                                 .hasFeature(JS_LOCATION_IGNORE_QUERY_FOR_ABOUT_PROTOCOL)) {
380             return "";
381         }
382         return "?" + search;
383     }
384 
385     /**
386      * Sets the search portion of the location URL (the portion following the {@code ?}).
387      *
388      * @param search the new search portion of the location URL
389      * @throws Exception if an error occurs
390      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/search">MDN Documentation</a>
391      */
392     public void setSearch(final String search) throws Exception {
393         setUrl(UrlUtils.getUrlWithNewQuery(getUrl(), search));
394     }
395 
396     /**
397      * Returns the hash portion of the location URL (the portion following the {@code #}).
398      *
399      * @return the hash portion of the location URL
400      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/hash">MDN Documentation</a>
401      */
402     public String getHash() {
403         if (StringUtils.isEmptyOrNull(hash_)) {
404             return "";
405         }
406 
407         if (hash_.indexOf('%') == -1) {
408             return "#" + UrlUtils.encodeHash(hash_);
409         }
410         return "#" + UrlUtils.encodeHash(UrlUtils.decode(hash_));
411     }
412 
413     private String getHash(final boolean encoded) {
414         if (hash_ == null || hash_.isEmpty()) {
415             return null;
416         }
417         if (encoded) {
418             return UrlUtils.encodeHash(hash_);
419         }
420         return hash_;
421     }
422 
423     /**
424      * Sets the hash portion of the location URL (the portion following the {@code #}).
425      * This method does not cause a server hit.
426      *
427      * @param hash the new hash portion of the location URL
428      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/hash">MDN Documentation</a>
429      */
430     public void setHash(final String hash) {
431         // IMPORTANT: This method must not call setUrl(), because
432         // we must not hit the server just to change the hash!
433         setHash(getHref(), hash, true);
434     }
435 
436     /**
437      * Sets the hash portion of the location URL (the portion following the {@code #}).
438      *
439      * @param oldURL the old URL
440      * @param hash the new hash portion of the location URL
441      */
442     public void setHash(final String oldURL, final String hash) {
443         setHash(oldURL, hash, true);
444     }
445 
446     /**
447      * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
448      *
449      * Sets the hash portion of the location URL (the portion following the {@code #}).
450      *
451      * @param oldURL the old URL
452      * @param hash the new hash portion of the location URL
453      * @param triggerHashChanged option to disable event triggering
454      */
455     public void setHash(final String oldURL, String hash, final boolean triggerHashChanged) {
456         // IMPORTANT: This method must not call setUrl(), because
457         // we must not hit the server just to change the hash!
458         if (hash != null && !hash.isEmpty() && hash.charAt(0) == '#') {
459             hash = hash.substring(1);
460         }
461         final boolean hasChanged = hash != null && !hash.equals(hash_);
462         hash_ = hash;
463 
464         if (hasChanged) {
465             final Window w = getWindow();
466             final Page page = w.getWebWindow().getEnclosedPage();
467             if (page != null) {
468                 final WebRequest request = page.getWebResponse().getWebRequest();
469                 request.setUrl(UrlUtils.toUrlSafe(getHref()));
470             }
471 
472             if (triggerHashChanged) {
473                 final Event event = new HashChangeEvent(w, Event.TYPE_HASH_CHANGE, oldURL, getHref());
474                 w.executeEventLocally(event);
475             }
476         }
477     }
478 
479     /**
480      * Returns the hostname portion of the location URL.
481      *
482      * @return the hostname portion of the location URL
483      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/hostname">MDN Documentation</a>
484      */
485     public String getHostname() {
486         return getUrl().getHost();
487     }
488 
489     /**
490      * Sets the hostname portion of the location URL.
491      *
492      * @param hostname the new hostname portion of the location URL
493      * @throws Exception if an error occurs
494      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/hostname">MDN Documentation</a>
495      */
496     public void setHostname(final String hostname) throws Exception {
497         setUrl(UrlUtils.getUrlWithNewHost(getUrl(), hostname));
498     }
499 
500     /**
501      * Returns the host portion of the location URL (the {@code [hostname]:[port]} portion).
502      *
503      * @return the host portion of the location URL
504      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/host">MDN Documentation</a>
505      */
506     public String getHost() {
507         final URL url = getUrl();
508         final int port = url.getPort();
509         final String host = url.getHost();
510 
511         if (port == -1) {
512             return host;
513         }
514         return host + ":" + port;
515     }
516 
517     /**
518      * Sets the host portion of the location URL (the {@code [hostname]:[port]} portion).
519      *
520      * @param host the new host portion of the location URL
521      * @throws Exception if an error occurs
522      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/host">MDN Documentation</a>
523      */
524     public void setHost(final String host) throws Exception {
525         final String hostname;
526         final int port;
527         final int index = host.indexOf(':');
528         if (index == -1) {
529             hostname = host;
530             port = -1;
531         }
532         else {
533             hostname = host.substring(0, index);
534             port = Integer.parseInt(host.substring(index + 1));
535         }
536         final URL url = UrlUtils.getUrlWithNewHostAndPort(getUrl(), hostname, port);
537         setUrl(url);
538     }
539 
540     /**
541      * Returns the pathname portion of the location URL.
542      *
543      * @return the pathname portion of the location URL
544      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname">MDN Documentation</a>
545      */
546     public String getPathname() {
547         if (UrlUtils.URL_ABOUT_BLANK == getUrl()) {
548             return "blank";
549         }
550         return getUrl().getPath();
551     }
552 
553     /**
554      * Sets the pathname portion of the location URL.
555      *
556      * @param pathname the new pathname portion of the location URL
557      * @throws Exception if an error occurs
558      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname">MDN Documentation</a>
559      */
560     public void setPathname(final String pathname) throws Exception {
561         setUrl(UrlUtils.getUrlWithNewPath(getUrl(), pathname));
562     }
563 
564     /**
565      * Returns the port portion of the location URL.
566      *
567      * @return the port portion of the location URL, or an empty string if no port is specified
568      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/port">MDN Documentation</a>
569      */
570     public String getPort() {
571         final int port = getUrl().getPort();
572         if (port == -1) {
573             return "";
574         }
575         return Integer.toString(port);
576     }
577 
578     /**
579      * Sets the port portion of the location URL.
580      *
581      * @param port the new port portion of the location URL
582      * @throws Exception if an error occurs
583      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/port">MDN Documentation</a>
584      */
585     public void setPort(final String port) throws Exception {
586         setUrl(UrlUtils.getUrlWithNewPort(getUrl(), Integer.parseInt(port)));
587     }
588 
589     /**
590      * Returns the protocol portion of the location URL, including the trailing {@code :}.
591      *
592      * @return the protocol portion of the location URL
593      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/protocol">MDN Documentation</a>
594      */
595     public String getProtocol() {
596         return getUrl().getProtocol() + ":";
597     }
598 
599     /**
600      * Sets the protocol portion of the location URL.
601      *
602      * @param protocol the new protocol portion of the location URL
603      * @throws Exception if an error occurs
604      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/protocol">MDN Documentation</a>
605      */
606     public void setProtocol(final String protocol) throws Exception {
607         setUrl(UrlUtils.getUrlWithNewProtocol(getUrl(), protocol));
608     }
609 
610     /**
611      * Returns this location's current URL.
612      *
613      * @return this location's current URL
614      */
615     private URL getUrl() {
616         return window_.getWebWindow().getEnclosedPage().getUrl();
617     }
618 
619     /**
620      * Sets this location's URL, triggering a server request and loading the resulting document
621      * into this location's window.
622      *
623      * @param url this location's new URL
624      * @throws IOException if there is a problem loading the new location
625      */
626     private void setUrl(final URL url) throws IOException {
627         final WebWindow webWindow = window_.getWebWindow();
628         final BrowserVersion browserVersion = webWindow.getWebClient().getBrowserVersion();
629 
630         final WebRequest webRequest = new WebRequest(url,
631                 browserVersion.getHtmlAcceptHeader(), browserVersion.getAcceptEncodingHeader());
632 
633         webRequest.markAsNavigation(getUrl(), false);
634         webRequest.setFetchModeOverride(WebRequest.FetchMode.NAVIGATE);
635 
636         webRequest.setRefererHeader(getUrl());
637 
638         webWindow.getWebClient().getPage(webWindow, webRequest);
639     }
640 
641     /**
642      * Returns the {@code origin} property.
643      *
644      * @return the {@code origin} property
645      */
646     public String getOrigin() {
647         return getUrl().getProtocol() + "://" + getHost();
648     }
649 }