1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.webappcontainer.util;
35
36 import fr.paris.lutece.plugins.webappcontainer.business.Site;
37 import fr.paris.lutece.plugins.webappcontainer.service.WebappcontainerPlugin;
38 import fr.paris.lutece.plugins.webappcontainer.web.WebappcontainerApp;
39 import fr.paris.lutece.portal.service.util.AppLogService;
40 import fr.paris.lutece.portal.service.util.AppPathService;
41 import fr.paris.lutece.portal.service.util.AppPropertiesService;
42
43 import org.w3c.dom.Document;
44 import org.w3c.dom.Element;
45 import org.w3c.dom.NamedNodeMap;
46 import org.w3c.dom.Node;
47 import org.w3c.dom.NodeList;
48
49 import org.w3c.tidy.Tidy;
50
51 import java.io.ByteArrayInputStream;
52 import java.io.ByteArrayOutputStream;
53 import java.io.PrintWriter;
54 import java.io.StringWriter;
55
56 import javax.xml.transform.OutputKeys;
57 import javax.xml.transform.Transformer;
58 import javax.xml.transform.TransformerConfigurationException;
59 import javax.xml.transform.TransformerException;
60 import javax.xml.transform.TransformerFactory;
61 import javax.xml.transform.dom.DOMSource;
62 import javax.xml.transform.stream.StreamResult;
63
64
65
66
67
68
69 public class HtmlDocumentWebappcontainer
70 {
71 public static final String CONSTANT_STATIC_URL = "https?://[^/]+/";
72 public static final String CONSTANT_PROTOCOL_DELIMITER = ":";
73 private static final String PROPERTY_PARSING_STOP_WHEN_ERROR = "webappcontainer.jtidy.parsing.stopWhenError";
74 private static final String TAG_INPUT = "input";
75 private static final String TAG_INPUT_ATTRIBUTE_TYPE = "type";
76 private static final String TAG_INPUT_ATTRIBUTE_NAME = "name";
77 private static final String TAG_INPUT_ATTRIBUTE_VALUE = "value";
78 private static final String TAG_INPUT_ATTRIBUTE_TYPE_VALUE_HIDDEN = "hidden";
79 private static final String EMPTY_STRING = "";
80 private static final String OMIT_XML_DECLARATION_TRUE = "yes";
81 private static final String METHOD_HTML = "html";
82
83
84
85
86
87
88
89
90
91
92 public static final ElementUrl ELEMENT_CSS_LINK;
93
94
95
96
97
98
99
100
101 public static final ElementUrl ELEMENT_CSS_STYLE;
102
103
104
105
106
107
108
109
110
111 public static final ElementUrl ELEMENT_ALTERNATE;
112
113
114
115
116
117
118
119
120
121 public static final ElementUrl ELEMENT_JAVASCRIPT;
122
123
124
125
126
127
128
129
130 public static final ElementUrl ELEMENT_IMG;
131
132
133
134
135
136
137
138
139 public static final ElementUrl ELEMENT_A;
140
141
142
143
144
145
146
147
148 public static final ElementUrl ELEMENT_FORM;
149
150
151
152
153
154
155
156 public static final ElementUrl ELEMENT_HEAD;
157
158
159
160
161
162
163
164 public static final ElementUrl ELEMENT_BODY;
165
166
167
168
169
170
171
172 public static final ElementUrl ELEMENT_BASE;
173
174
175
176
177
178
179
180 public static final ElementUrl ELEMENT_INPUT;
181
182 static
183 {
184 ELEMENT_CSS_LINK = new ElementUrl( "link", "href", "rel", "stylesheet" );
185 ELEMENT_CSS_STYLE = new ElementUrl( "style", null, "type", "text/css" );
186 ELEMENT_ALTERNATE = new ElementUrl( "link", "href", "rel", "alternate" );
187 ELEMENT_JAVASCRIPT = new ElementUrl( "script", "src", "type", "text/javascript" );
188 ELEMENT_IMG = new ElementUrl( "img", "src", null, null );
189 ELEMENT_A = new ElementUrl( "a", "href", null, null );
190 ELEMENT_FORM = new ElementUrl( "form", "action", null, null );
191 ELEMENT_HEAD = new ElementUrl( "head", null, null, null );
192 ELEMENT_BODY = new ElementUrl( "body", null, null, null );
193 ELEMENT_BASE = new ElementUrl( "base", "href", null, null );
194 ELEMENT_INPUT = new ElementUrl( "input", null, null, null );
195 }
196
197 private Document _content;
198
199
200
201
202
203
204
205
206 public HtmlDocumentWebappcontainer( byte[] byteHtml, String strEncoding )
207 throws HtmlDocumentWebappcontainerException
208 {
209
210 Tidy tidy = new Tidy( );
211 tidy.setQuiet( true );
212 tidy.setShowWarnings( false );
213
214 ByteArrayOutputStream baErrors = new ByteArrayOutputStream( );
215 PrintWriter pw = new PrintWriter( baErrors, true );
216 tidy.setErrout( pw );
217 tidy.setTidyMark( false );
218 tidy.setInputEncoding( strEncoding );
219 _content = tidy.parseDOM( new ByteArrayInputStream( byteHtml ), null );
220
221 boolean bStopWhenError = Boolean.parseBoolean( AppPropertiesService.getProperty(
222 PROPERTY_PARSING_STOP_WHEN_ERROR, Boolean.toString( false ) ) );
223
224 if ( bStopWhenError && !baErrors.toString( ).equals( EMPTY_STRING ) )
225 {
226 throw new HtmlDocumentWebappcontainerException( baErrors.toString( ), null );
227 }
228 }
229
230
231
232
233
234
235
236
237
238
239
240 public void convertUrls( ElementUrl elementType, String strBaseUrlSite, Site site, String strReplaceUrl,
241 boolean bEncodeUrl )
242 {
243 if ( elementType == ELEMENT_FORM )
244 {
245 changeInputs( );
246 }
247
248 NodeList nodes = _content.getElementsByTagName( elementType.getTagName( ) );
249
250 for ( int i = 0; i < nodes.getLength( ); i++ )
251 {
252 Node node = nodes.item( i );
253 NamedNodeMap attributes = node.getAttributes( );
254
255
256 if ( ( elementType.getTestedAttributeName( ) != null ) &&
257 ( attributes.getNamedItem( elementType.getTestedAttributeName( ) ) != null ) )
258 {
259 String strRel = attributes.getNamedItem( elementType.getTestedAttributeName( ) ).getNodeValue( );
260
261 if ( !elementType.getTestedAttributeValue( ).equalsIgnoreCase( strRel ) )
262 {
263 continue;
264 }
265 }
266
267
268 Node nodeAttribute = attributes.getNamedItem( elementType.getAttributeName( ) );
269
270 if ( nodeAttribute == null )
271 {
272 continue;
273 }
274
275 String strSrc = nodeAttribute.getNodeValue( ).trim( );
276 String strAbsoluteUrl = UrlUtils.convertRelativeToAbsoluteUrl( strSrc, strBaseUrlSite );
277 boolean isExternalUrl = !UrlUtils.hostsEquals( strAbsoluteUrl, site.getUrl( ) );
278
279 if ( bEncodeUrl && !isExternalUrl )
280 {
281 strAbsoluteUrl = UrlUtils.encodeUrl( strAbsoluteUrl );
282 }
283
284 if ( elementType == ELEMENT_FORM )
285 {
286 Element elementHiddenXPageName = _content.createElement( TAG_INPUT );
287 elementHiddenXPageName.setAttribute( TAG_INPUT_ATTRIBUTE_TYPE, TAG_INPUT_ATTRIBUTE_TYPE_VALUE_HIDDEN );
288 elementHiddenXPageName.setAttribute( TAG_INPUT_ATTRIBUTE_NAME, WebappcontainerApp.PARAMETER_PAGE );
289 elementHiddenXPageName.setAttribute( TAG_INPUT_ATTRIBUTE_VALUE, WebappcontainerPlugin.PLUGIN_NAME );
290
291 node.appendChild( elementHiddenXPageName );
292
293 Element elementHiddenSiteCode = _content.createElement( TAG_INPUT );
294 elementHiddenSiteCode.setAttribute( TAG_INPUT_ATTRIBUTE_TYPE, TAG_INPUT_ATTRIBUTE_TYPE_VALUE_HIDDEN );
295 elementHiddenSiteCode.setAttribute( TAG_INPUT_ATTRIBUTE_NAME, WebappcontainerApp.PARAMETER_CODE );
296 elementHiddenSiteCode.setAttribute( TAG_INPUT_ATTRIBUTE_VALUE, site.getCode( ) );
297
298 node.appendChild( elementHiddenSiteCode );
299
300 Element elementHiddenWebappUrl = _content.createElement( TAG_INPUT );
301 elementHiddenWebappUrl.setAttribute( TAG_INPUT_ATTRIBUTE_TYPE, TAG_INPUT_ATTRIBUTE_TYPE_VALUE_HIDDEN );
302 elementHiddenWebappUrl.setAttribute( TAG_INPUT_ATTRIBUTE_NAME, WebappcontainerApp.PARAMETER_WEBAPP_URL );
303 elementHiddenWebappUrl.setAttribute( TAG_INPUT_ATTRIBUTE_VALUE, strAbsoluteUrl );
304
305 node.appendChild( elementHiddenWebappUrl );
306
307 nodeAttribute.setNodeValue( AppPathService.getPortalUrl( ) );
308 }
309 else
310 {
311
312 nodeAttribute.setNodeValue( ( !isExternalUrl ) ? ( strReplaceUrl + strAbsoluteUrl ) : strAbsoluteUrl );
313 }
314 }
315 }
316
317
318
319
320
321
322
323 public StringBuffer getFirstElement( ElementUrl elementType )
324 {
325 NodeList nodes = _content.getElementsByTagName( elementType.getTagName( ) );
326
327 if ( nodes.getLength( ) == 0 )
328 {
329 return null;
330 }
331
332 Node node = nodes.item( 0 );
333 NodeList childNodeList = node.getChildNodes( );
334 StringBuffer stringBuffer = new StringBuffer( );
335
336 for ( int i = 0; i < childNodeList.getLength( ); i++ )
337 {
338 stringBuffer.append( getNodeContent( childNodeList.item( i ) ) );
339 }
340
341 return stringBuffer;
342 }
343
344
345
346
347
348
349
350 public StringBuffer getElements( ElementUrl elementType )
351 {
352 NodeList nodes = _content.getElementsByTagName( elementType.getTagName( ) );
353
354 if ( nodes.getLength( ) == 0 )
355 {
356 return null;
357 }
358
359 StringBuffer stringBuffer = new StringBuffer( );
360
361 for ( int i = 0; i < nodes.getLength( ); i++ )
362 {
363 stringBuffer.append( getNodeContent( nodes.item( i ) ) );
364 }
365
366 return stringBuffer;
367 }
368
369
370
371
372
373
374 public void removeFirstElement( ElementUrl elementType )
375 {
376 NodeList nodes = _content.getElementsByTagName( elementType.getTagName( ) );
377
378 if ( nodes.getLength( ) != 0 )
379 {
380 Node node = nodes.item( 0 );
381 Node parentNode = node.getParentNode( );
382 parentNode.removeChild( node );
383 }
384 }
385
386
387
388
389
390
391
392 public String getFirstElementAttribute( ElementUrl elementType )
393 {
394 NodeList nodes = _content.getElementsByTagName( elementType.getTagName( ) );
395
396 if ( nodes.getLength( ) == 0 )
397 {
398 return null;
399 }
400
401 Node node = nodes.item( 0 );
402 NamedNodeMap attributes = node.getAttributes( );
403
404
405 if ( elementType.getTestedAttributeName( ) != null )
406 {
407 String strRel = attributes.getNamedItem( elementType.getTestedAttributeName( ) ).getNodeValue( );
408
409 if ( !elementType.getTestedAttributeValue( ).equals( strRel ) )
410 {
411 return null;
412 }
413 }
414
415
416 Node nodeAttribute = attributes.getNamedItem( elementType.getAttributeName( ) );
417
418 if ( nodeAttribute == null )
419 {
420 return null;
421 }
422
423 return nodeAttribute.getNodeValue( );
424 }
425
426
427
428
429
430 public StringBuffer getContent( )
431 {
432 DOMSource domSource = new DOMSource( _content );
433 StringWriter writer = new StringWriter( );
434 StreamResult result = new StreamResult( writer );
435 TransformerFactory tf = TransformerFactory.newInstance( );
436 Transformer transformer;
437
438 try
439 {
440 transformer = tf.newTransformer( );
441 transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, OMIT_XML_DECLARATION_TRUE );
442 transformer.setOutputProperty( OutputKeys.METHOD, METHOD_HTML );
443 transformer.transform( domSource, result );
444 }
445 catch ( TransformerConfigurationException e )
446 {
447 AppLogService.error( e.getMessage( ) );
448
449 return null;
450 }
451 catch ( TransformerException e )
452 {
453 AppLogService.error( e.getMessage( ) );
454
455 return null;
456 }
457
458 return writer.getBuffer( );
459 }
460
461
462
463
464 private void changeInputs( )
465 {
466 NodeList nodes2 = _content.getElementsByTagName( ELEMENT_INPUT.getTagName( ) );
467
468 for ( int j = 0; j < nodes2.getLength( ); j++ )
469 {
470 Element node2 = (Element) nodes2.item( j );
471
472 node2.setAttribute( TAG_INPUT_ATTRIBUTE_NAME,
473 WebappcontainerApp.PARAMETER_PAGE_HACK + node2.getAttribute( TAG_INPUT_ATTRIBUTE_NAME ) );
474 }
475 }
476
477
478
479
480
481
482
483 private String getNodeContent( Node node )
484 {
485 DOMSource domSource = new DOMSource( node );
486 StringWriter writer = new StringWriter( );
487 StreamResult result = new StreamResult( writer );
488 TransformerFactory tf = TransformerFactory.newInstance( );
489 Transformer transformer;
490
491 try
492 {
493 transformer = tf.newTransformer( );
494 transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, OMIT_XML_DECLARATION_TRUE );
495 transformer.setOutputProperty( OutputKeys.METHOD, METHOD_HTML );
496 transformer.setOutputProperty( OutputKeys.MEDIA_TYPE, "text/html" );
497 transformer.transform( domSource, result );
498 }
499 catch ( TransformerConfigurationException e )
500 {
501 AppLogService.error( e.getMessage( ) );
502
503 return null;
504 }
505 catch ( TransformerException e )
506 {
507 AppLogService.error( e.getMessage( ) );
508
509 return null;
510 }
511
512 return writer.toString( );
513 }
514
515
516
517
518 private static class ElementUrl
519 {
520 private String _strTagName;
521 private String _strAttributeName;
522 private String _strTestedAttributeName;
523 private String _strTestedAttributeValue;
524
525
526
527
528
529
530
531
532
533
534
535 public ElementUrl( String strTagName, String strAttributeName, String strTestedAttributeName,
536 String strTestedAttributeValue )
537 {
538 _strTagName = strTagName;
539 _strAttributeName = strAttributeName;
540 _strTestedAttributeName = strTestedAttributeName;
541 _strTestedAttributeValue = strTestedAttributeValue;
542 }
543
544
545
546
547
548 public String getAttributeName( )
549 {
550 return _strAttributeName;
551 }
552
553
554
555
556
557 public String getTagName( )
558 {
559 return _strTagName;
560 }
561
562
563
564
565
566 public String getTestedAttributeName( )
567 {
568 return _strTestedAttributeName;
569 }
570
571
572
573
574
575 public String getTestedAttributeValue( )
576 {
577 return _strTestedAttributeValue;
578 }
579 }
580 }