View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2014 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.handler.url.rewriter.impl;
21  
22  import java.net.URLDecoder;
23  import java.nio.charset.StandardCharsets;
24  
25  import org.apache.cocoon.xml.sax.AbstractSAXPipe;
26  import org.apache.cocoon.xml.sax.AttributesImpl;
27  import org.apache.commons.lang3.StringUtils;
28  import org.apache.sling.rewriter.ProcessingComponentConfiguration;
29  import org.apache.sling.rewriter.ProcessingContext;
30  import org.apache.sling.rewriter.Transformer;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  import org.xml.sax.Attributes;
34  import org.xml.sax.SAXException;
35  
36  import io.wcm.handler.url.UrlHandler;
37  
38  /**
39   * HTML transformer that rewrites URLs in certain HTML element attributes.
40   */
41  class UrlExternalizerTransformer extends AbstractSAXPipe implements Transformer {
42  
43    private UrlExternalizerTransformerConfig transformerConfig;
44    private UrlHandler urlHandler;
45  
46    private static final Logger log = LoggerFactory.getLogger(UrlExternalizerTransformer.class.getName());
47  
48    @Override
49    public void init(ProcessingContext pipelineContext, ProcessingComponentConfiguration config) {
50      log.trace("Initialize UrlExternalizerTransformer with config: {}", config.getConfiguration());
51      transformerConfig = new UrlExternalizerTransformerConfig(config.getConfiguration());
52      urlHandler = pipelineContext.getRequest().adaptTo(UrlHandler.class);
53    }
54  
55    @Override
56    @SuppressWarnings("PMD.UseStringBufferForStringAppends")
57    public void startElement(String nsUri, String name, String raw, Attributes attrs) throws SAXException {
58  
59      // check if for this element an attribute for rewriting is configured
60      String rewriteAttr = transformerConfig.getElementAttributeNames().get(name);
61      if (rewriteAttr == null) {
62        log.trace("Rewrite element {}: Skip - No rewrite attribute configured.", name);
63        super.startElement(nsUri, name, raw, attrs);
64        return;
65      }
66  
67      // validate URL handler
68      if (urlHandler == null) {
69        log.warn("Rewrite element {}: Skip - Unable to get URL handler/Integrator handler instance.", name);
70        super.startElement(nsUri, name, raw, attrs);
71        return;
72      }
73  
74      // check if attribute exists
75      int attributeIndex = attrs.getIndex(rewriteAttr);
76      if (attributeIndex < 0) {
77        log.trace("Rewrite element {}: Skip - Attribute does not exist: {}", name, rewriteAttr);
78        super.startElement(nsUri, name, raw, attrs);
79        return;
80      }
81  
82      // rewrite URL
83      String url = attrs.getValue(attributeIndex);
84      if (StringUtils.isEmpty(url)) {
85        log.trace("Rewrite element {}: Skip - URL is empty.", name);
86        super.startElement(nsUri, name, raw, attrs);
87        return;
88      }
89  
90      // split off query string or fragment that may be appended to the URL
91      String urlRemainder = null;
92      int urlRemainderPos = StringUtils.indexOfAny(url, '?', '#');
93      if (urlRemainderPos >= 0) {
94        urlRemainder = url.substring(urlRemainderPos);
95        url = url.substring(0, urlRemainderPos);
96      }
97  
98      // decode URL (without URL remainder)
99      url = URLDecoder.decode(url, StandardCharsets.UTF_8);
100 
101     // externalize URL (if it is not already externalized)
102     String rewrittenUrl = urlHandler.get(url).buildExternalResourceUrl();
103     if (urlRemainder != null) {
104       if (rewrittenUrl == null) {
105         rewrittenUrl = urlRemainder;
106       }
107       else {
108         rewrittenUrl += urlRemainder;
109       }
110     }
111 
112     if (StringUtils.equals(url, rewrittenUrl)) {
113       log.debug("Rewrite element {}: Skip - URL is already externalized: {}", name, url);
114       super.startElement(nsUri, name, raw, attrs);
115       return;
116     }
117 
118     // set new attribute value
119     log.debug("Rewrite element {}: Rewrite URL {} to {}", name, url, rewrittenUrl);
120     AttributesImpl newAttrs = new AttributesImpl(attrs);
121     newAttrs.setValue(attributeIndex, rewrittenUrl);
122     super.startElement(nsUri, name, raw, newAttrs);
123   }
124 
125   @Override
126   public void dispose() {
127     // nothing to do
128   }
129 
130 }