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 (org.apache.commons.lang3.StringUtils.isNotBlank(type)
218 && !MimeType.TEXT_CSS.equals(type)) {
219 return null;
220 }
221
222 final String respType = response.getContentType();
223 if (org.apache.commons.lang3.StringUtils.isNotBlank(respType)
224 && !MimeType.TEXT_CSS.equals(respType)) {
225 executeEvent(Event.TYPE_ERROR);
226 return response;
227 }
228 }
229 executeEvent(Event.TYPE_LOAD);
230 return response;
231 }
232 executeEvent(Event.TYPE_ERROR);
233 return response;
234 }
235 catch (final IOException e) {
236 executeEvent(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 String type) {
280 final HTMLLinkElement link = getScriptableObject();
281 final Event event = new Event(this, type);
282 link.executeEventLocally(event);
283 }
284
285
286
287
288 @Override
289 public void onAllChildrenAddedToPage(final boolean postponed) {
290 if (getOwnerDocument() instanceof XmlPage) {
291 return;
292 }
293 if (LOG.isDebugEnabled()) {
294 LOG.debug("Link node added: " + asXml());
295 }
296
297 final boolean isStyleSheetLink = isStyleSheetLink();
298
299 if (isStyleSheetLink) {
300 final WebClient webClient = getPage().getWebClient();
301 if (!webClient.getOptions().isCssEnabled()) {
302 if (LOG.isDebugEnabled()) {
303 LOG.debug("Stylesheet Link found but ignored because css support is disabled ("
304 + asXml().replaceAll("[\\r\\n]", "") + ").");
305 }
306 return;
307 }
308
309 if (!webClient.isJavaScriptEngineEnabled()) {
310 if (LOG.isDebugEnabled()) {
311 LOG.debug("Stylesheet Link found but ignored because javascript engine is disabled ("
312 + asXml().replaceAll("[\\r\\n]", "") + ").");
313 }
314 return;
315 }
316
317 final PostponedAction action = new PostponedAction(getPage(), "Loading of link " + this) {
318 @Override
319 public void execute() {
320 final HTMLLinkElement linkElem = HtmlLink.this.getScriptableObject();
321
322 linkElem.getSheet();
323 }
324 };
325
326 final AbstractJavaScriptEngine<?> engine = webClient.getJavaScriptEngine();
327 if (postponed) {
328 engine.addPostponedAction(action);
329 }
330 else {
331 try {
332 action.execute();
333 }
334 catch (final RuntimeException e) {
335 throw e;
336 }
337 catch (final Exception e) {
338 throw new RuntimeException(e);
339 }
340 }
341
342 return;
343 }
344
345 if (LOG.isDebugEnabled()) {
346 LOG.debug("Link type '" + getRelAttribute() + "' not supported ("
347 + asXml().replaceAll("[\\r\\n]", "") + ").");
348 }
349 }
350
351
352
353
354
355
356 public CssStyleSheet getSheet() {
357 if (sheet_ == null) {
358 sheet_ = CssStyleSheet.loadStylesheet(this, this, null);
359 }
360 return sheet_;
361 }
362
363
364
365
366 public boolean isStyleSheetLink() {
367 final String rel = getRelAttribute();
368 if (rel != null) {
369 return ArrayUtils.containsIgnoreCase(StringUtils.splitAtBlank(rel), "stylesheet");
370 }
371 return false;
372 }
373
374
375
376
377 public boolean isModulePreloadLink() {
378 final String rel = getRelAttribute();
379 if (rel != null) {
380 return ArrayUtils.containsIgnoreCase(StringUtils.splitAtBlank(rel), "modulepreload");
381 }
382 return false;
383 }
384
385
386
387
388
389
390
391
392
393 public boolean isActiveStyleSheetLink() {
394 if (isStyleSheetLink()) {
395 final String media = getMediaAttribute();
396 if (org.apache.commons.lang3.StringUtils.isBlank(media)) {
397 return true;
398 }
399
400 final MediaListImpl mediaList =
401 CssStyleSheet.parseMedia(media, getPage().getWebClient());
402 return CssStyleSheet.isActive(mediaList, getPage().getEnclosingWindow());
403 }
404 return false;
405 }
406 }