1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html;
16
17 import static org.htmlunit.BrowserVersionFeatures.HTMLLINK_CHECK_RESPONSE_TYPE_FOR_STYLESHEET;
18
19 import java.io.IOException;
20 import java.net.MalformedURLException;
21 import java.net.URL;
22 import java.util.Map;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.htmlunit.BrowserVersion;
27 import org.htmlunit.SgmlPage;
28 import org.htmlunit.WebClient;
29 import org.htmlunit.WebRequest;
30 import org.htmlunit.WebResponse;
31 import org.htmlunit.css.CssStyleSheet;
32 import org.htmlunit.cssparser.dom.MediaListImpl;
33 import org.htmlunit.javascript.AbstractJavaScriptEngine;
34 import org.htmlunit.javascript.PostponedAction;
35 import org.htmlunit.javascript.host.event.Event;
36 import org.htmlunit.javascript.host.html.HTMLLinkElement;
37 import org.htmlunit.util.ArrayUtils;
38 import org.htmlunit.util.MimeType;
39 import org.htmlunit.util.StringUtils;
40 import org.htmlunit.xml.XmlPage;
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class HtmlLink extends HtmlElement {
55 private static final Log LOG = LogFactory.getLog(HtmlLink.class);
56
57
58 public static final String TAG_NAME = "link";
59
60
61
62
63
64 private CssStyleSheet sheet_;
65
66
67
68
69
70
71
72
73 HtmlLink(final String qualifiedName, final SgmlPage page,
74 final Map<String, DomAttr> attributes) {
75 super(qualifiedName, page, attributes);
76 }
77
78
79
80
81
82
83
84
85
86 public final String getCharsetAttribute() {
87 return getAttributeDirect("charset");
88 }
89
90
91
92
93
94
95
96
97
98 public final String getHrefAttribute() {
99 return getAttributeDirect("href");
100 }
101
102
103
104
105
106
107
108
109
110 public final String getHrefLangAttribute() {
111 return getAttributeDirect("hreflang");
112 }
113
114
115
116
117
118
119
120
121
122 public final String getTypeAttribute() {
123 return getAttributeDirect(TYPE_ATTRIBUTE);
124 }
125
126
127
128
129
130
131
132
133
134 public final String getRelAttribute() {
135 return getAttributeDirect("rel");
136 }
137
138
139
140
141
142
143
144
145
146 public final String getRevAttribute() {
147 return getAttributeDirect("rev");
148 }
149
150
151
152
153
154
155
156
157
158 public final String getMediaAttribute() {
159 return getAttributeDirect("media");
160 }
161
162
163
164
165
166
167
168
169
170 public final String getTargetAttribute() {
171 return getAttributeDirect("target");
172 }
173
174
175
176
177
178
179
180
181
182
183
184 public WebResponse getWebResponse(final boolean downloadIfNeeded) throws IOException {
185 return getWebResponse(downloadIfNeeded, null, false, null);
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 public WebResponse getWebResponse(final boolean downloadIfNeeded, WebRequest request,
203 final boolean isStylesheetRequest, final String type) throws IOException {
204 final WebClient webClient = getPage().getWebClient();
205 if (null == request) {
206 request = getWebRequest();
207 }
208
209 if (downloadIfNeeded) {
210 try {
211 final WebResponse response = webClient.loadWebResponse(request);
212 if (response.isSuccess()) {
213 if (isStylesheetRequest
214 && webClient.getBrowserVersion()
215 .hasFeature(HTMLLINK_CHECK_RESPONSE_TYPE_FOR_STYLESHEET)) {
216
217 if (StringUtils.isNotBlank(type)
218 && !MimeType.TEXT_CSS.equals(type)) {
219 return null;
220 }
221
222 final String respType = response.getContentType();
223 if (StringUtils.isNotBlank(respType)
224 && !MimeType.TEXT_CSS.equals(respType)) {
225 executeEvent(webClient, Event.TYPE_ERROR);
226 return response;
227 }
228 }
229 executeEvent(webClient, Event.TYPE_LOAD);
230 return response;
231 }
232 executeEvent(webClient, Event.TYPE_ERROR);
233 return response;
234 }
235 catch (final IOException e) {
236 executeEvent(webClient, Event.TYPE_ERROR);
237 throw e;
238 }
239 }
240
241
242 return webClient.getCache().getCachedResponse(request);
243 }
244
245
246
247
248
249
250 public WebRequest getWebRequest() throws MalformedURLException {
251 final HtmlPage page = (HtmlPage) getPage();
252 final URL url = page.getFullyQualifiedUrl(getHrefAttribute());
253
254 final BrowserVersion browser = page.getWebClient().getBrowserVersion();
255 final WebRequest request = new WebRequest(url, browser.getCssAcceptHeader(), browser.getAcceptEncodingHeader());
256
257 request.setCharset(page.getCharset());
258 request.setRefererHeader(page.getUrl());
259
260 return request;
261 }
262
263
264
265
266 @Override
267 public DisplayStyle getDefaultStyleDisplay() {
268 return DisplayStyle.NONE;
269 }
270
271
272
273
274 @Override
275 public boolean mayBeDisplayed() {
276 return false;
277 }
278
279 private void executeEvent(final WebClient webClient, final String type) {
280 if (!webClient.isJavaScriptEngineEnabled()) {
281 return;
282 }
283
284 final HTMLLinkElement link = getScriptableObject();
285 final Event event = new Event(this, type);
286 link.executeEventLocally(event);
287 }
288
289
290
291
292 @Override
293 public void onAllChildrenAddedToPage(final boolean postponed) {
294 if (getOwnerDocument() instanceof XmlPage) {
295 return;
296 }
297 if (LOG.isDebugEnabled()) {
298 LOG.debug("Link node added: " + asXml());
299 }
300
301 if (isStyleSheetLink()) {
302 final WebClient webClient = getPage().getWebClient();
303 if (!webClient.getOptions().isCssEnabled()) {
304 if (LOG.isDebugEnabled()) {
305 LOG.debug("Stylesheet Link found but ignored because css support is disabled ("
306 + asXml().replaceAll("[\\r\\n]", "") + ").");
307 }
308 return;
309 }
310
311 if (!webClient.isJavaScriptEngineEnabled()) {
312 if (LOG.isDebugEnabled()) {
313 LOG.debug("Stylesheet Link found but ignored because javascript engine is disabled ("
314 + asXml().replaceAll("[\\r\\n]", "") + ").");
315 }
316 return;
317 }
318
319 final PostponedAction action = new PostponedAction(getPage(), "Loading of link " + this) {
320 @Override
321 public void execute() {
322 final HTMLLinkElement linkElem = HtmlLink.this.getScriptableObject();
323
324 linkElem.getSheet();
325 }
326 };
327
328 final AbstractJavaScriptEngine<?> engine = webClient.getJavaScriptEngine();
329 if (postponed) {
330 engine.addPostponedAction(action);
331 }
332 else {
333 try {
334 action.execute();
335 }
336 catch (final RuntimeException e) {
337 throw e;
338 }
339 catch (final Exception e) {
340 throw new RuntimeException(e);
341 }
342 }
343
344 return;
345 }
346
347 if (LOG.isDebugEnabled()) {
348 LOG.debug("Link type '" + getRelAttribute() + "' not supported ("
349 + asXml().replaceAll("[\\r\\n]", "") + ").");
350 }
351 }
352
353
354
355
356
357
358 public CssStyleSheet getSheet() {
359 if (sheet_ == null) {
360 sheet_ = CssStyleSheet.loadStylesheet(this, this, null);
361 }
362 return sheet_;
363 }
364
365
366
367
368 public boolean isStyleSheetLink() {
369 final String rel = getRelAttribute();
370 if (rel != null) {
371 return ArrayUtils.containsIgnoreCase(StringUtils.splitAtBlank(rel), "stylesheet");
372 }
373 return false;
374 }
375
376
377
378
379 public boolean isModulePreloadLink() {
380 final String rel = getRelAttribute();
381 if (rel != null) {
382 return ArrayUtils.containsIgnoreCase(StringUtils.splitAtBlank(rel), "modulepreload");
383 }
384 return false;
385 }
386
387
388
389
390
391
392
393
394
395 public boolean isActiveStyleSheetLink() {
396 if (isStyleSheetLink()) {
397 final String media = getMediaAttribute();
398 if (StringUtils.isBlank(media)) {
399 return true;
400 }
401
402 final MediaListImpl mediaList =
403 CssStyleSheet.parseMedia(media, getPage().getWebClient());
404 return CssStyleSheet.isActive(mediaList, getPage().getEnclosingWindow());
405 }
406 return false;
407 }
408 }