├── .asf.yaml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Jenkinsfile
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
├── doc
│ ├── plain_include.png
│ └── plain_include.svg
├── java
│ └── org
│ │ └── apache
│ │ └── sling
│ │ └── dynamicinclude
│ │ ├── CacheControlFilter.java
│ │ ├── Configuration.java
│ │ ├── ConfigurationWhiteboard.java
│ │ ├── IncludeTagFilter.java
│ │ ├── SyntheticResourceFilter.java
│ │ ├── api
│ │ ├── IncludeGenerator.java
│ │ └── package-info.java
│ │ ├── generator
│ │ ├── IncludeGeneratorWhiteboard.java
│ │ └── types
│ │ │ ├── EsiGenerator.java
│ │ │ ├── JsiGenerator.java
│ │ │ └── SsiGenerator.java
│ │ ├── impl
│ │ └── UrlBuilder.java
│ │ ├── pathmatcher
│ │ ├── PathMatcher.java
│ │ ├── PrefixPathMatcher.java
│ │ └── RegexPathMatcher.java
│ │ └── util
│ │ └── RequestHelperUtil.java
└── resources
│ └── generators
│ └── javascript.html
└── test
└── java
└── org
└── apache
└── sling
└── dynamicinclude
├── ConfigurationTest.java
├── ConfigurationWhiteboardTest.java
├── impl
└── UrlBuilderTest.java
├── pathmatcher
├── PrefixPathMatcherTest.java
└── RegexPathMatcherTest.java
└── util
└── RequestHelperUtilTest.java
/.asf.yaml:
--------------------------------------------------------------------------------
1 | github:
2 | autolink_jira:
3 | - "SLING"
4 | - "OAK"
5 | - "JCR"
6 | - "JCRVLT"
7 | - "INFRA"
8 | - "FELIX"
9 | - "MNG"
10 | notifications:
11 | jira_options: "link"
12 | pullrequests_bot_sonarcloud: "commits@sling.apache.org"
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | .idea
3 | .classpath
4 | .metadata
5 | .project
6 | .settings
7 | .externalToolBuilders
8 | maven-eclipse.xml
9 | *.swp
10 | *.iml
11 | *.ipr
12 | *.iws
13 | *.bak
14 | .vlt
15 | .DS_Store
16 | jcr.log
17 | atlassian-ide-plugin.xml
18 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 |
19 | Apache Software Foundation Code of Conduct
20 | ====
21 |
22 | Being an Apache project, Apache Sling adheres to the Apache Software Foundation's [Code of Conduct](https://www.apache.org/foundation/policies/conduct.html).
23 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
19 | Contributing
20 | ====
21 |
22 | Thanks for choosing to contribute!
23 |
24 | You will find all the necessary details about how you can do this at https://sling.apache.org/contributing.html.
25 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | slingOsgiBundleBuild()
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://sling.apache.org)
2 |
3 | [](https://ci-builds.apache.org/job/Sling/job/modules/job/sling-org-apache-sling-dynamic-include/job/master/) [](https://ci-builds.apache.org/job/Sling/job/modules/job/sling-org-apache-sling-dynamic-include/job/master/test/?width=800&height=600) [](https://sonarcloud.io/dashboard?id=apache_sling-org-apache-sling-dynamic-include) [](https://sonarcloud.io/dashboard?id=apache_sling-org-apache-sling-dynamic-include) [](https://www.javadoc.io/doc/org.apache.sling/org.apache.sling.dynamic-include) [](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.sling%22%20a%3A%22org.apache.sling.dynamic-include%22) [](https://github.com/apache/sling-aggregator/blob/master/docs/status/contrib.md) [](https://www.apache.org/licenses/LICENSE-2.0)
4 |
5 | # Apache Sling Dynamic Include
6 |
7 | This module is part of the [Apache Sling](https://sling.apache.org) project.
8 |
9 | ## Purpose
10 |
11 | The purpose of the module presented here is to replace dynamic generated components (eg. current time or foreign exchange rates) with server-side include tag (eg. [SSI](http://httpd.apache.org/docs/current/howto/ssi.html) or [ESI](http://www.w3.org/TR/esi-lang)). Therefore the dispatcher is able to cache the whole page but dynamic components are generated and included with every request. Components to include are chosen in filter configuration using `resourceType` attribute.
12 |
13 | When the filter intercepts request for a component with given `resourceType`, it'll return a server-side include tag (eg. `` for Apache server). However the path is extended by new selector (`nocache` by default). This is required because filter has to know when to return actual content.
14 |
15 | Components don't have to be modified in order to use this module (or even aware of its existence). It's servlet filter, installed as an OSGi bundle and it can be enabled, disabled or reconfigured without touching CQ installation.
16 |
17 | ## Prerequisites
18 |
19 | * CQ / Apache Sling 2
20 | * Maven 2.x, 3.x
21 |
22 | ## Installation
23 |
24 | Add following dependency to your project:
25 |
26 |
27 | org.apache.sling
28 | org.apache.sling.dynamic-include
29 | 3.1.2
30 |
31 |
32 | ## Configuration
33 |
34 | Filter is delivered as a standard OSGi bundle. SDI is configured via the configuration factory called *SDI Configuration*. Following properties are available:
35 |
36 | * **Enabled** - enable SDI
37 | * **Base path** - This SDI configuration will work only for paths matching this value. If value starts with "^" sign, regex matching will be performed. Otherwise it will check for path prefix. (Available since 3.1.0)
38 | * **Resource types** - which components should be replaced with tags
39 | * **Include type** - type of include tag (Apache SSI, ESI or Javascript)
40 | * **Add comment** - adds debug comment: `` to every replaced component
41 | * **Filter selector** - selector used to get actual content
42 | * **Component TTL** - time to live in seconds, set for rendered component (require Dispatcher 4.1.11+)
43 | * **Required header** - SDI will be enabled only if the configured header is present in the request. By default it's `Server-Agent=Communique-Dispatcher` header, added by the AEM dispatcher. You may enter just the header name only or the name and the value split with `=`.
44 | * **Disable Ignore URL params check** - SDI will process all requests and discard ignore URL params check including requests with GET params.
45 | * **Ignore URL params** - SDI normally skips all requests containing any GET parameters. This option allows to set a list of parameters that should be ignored in the test. (Supports Java Regex Pattern e.g. "**tracking-(.*)**" or "**param-[0-9]**") See the [Ignoring URL parameters](https://docs.adobe.com/docs/en/dispatcher/disp-config.html#Ignoring%20URL%20Parameters) section in the dispatcher documentation.
46 | * **Include path rewriting** -- enable rewriting link (according to sling mappings) that is used for dynamic content including.
47 | * **Append suffix** -- ensures that the suffix of the parent request is included with the dynamic include.
48 |
49 | ## Compatibility with components
50 |
51 | Filter is incompatible with following types of component:
52 |
53 | * components which handles POST requests or GET parameters,
54 | * synthetic components which uses suffixes (because suffix is used to pass `requestType` of the synthetic resource).
55 |
56 | If component do not generate HTML but eg. JS or binary data then remember to turn off *Comment* option in configuration.
57 |
58 | ## Enabling SSI in Apache & dispatcher
59 |
60 | In order to enable SSI in Apache with dispatcher first enable `Include` mod (on Debian: `a2enmod include`). Then add `Includes` option to the `Options` directive in your virtual configuration host. After that find following lines in `dispatcher.conf` file:
61 |
62 |
63 | SetHandler dispatcher-handler
64 |
65 |
66 | and modify it:
67 |
68 |
69 | SetHandler dispatcher-handler
70 |
71 | SetOutputFilter INCLUDES
72 |
73 | After setting output filter open virtualhost configuration and add `Includes` option to `Options` directive:
74 |
75 |
76 | Options FollowSymLinks Includes
77 | AllowOverride None
78 |
79 |
80 | Options Indexes FollowSymLinks Includes
81 | AllowOverride None
82 | Order allow,deny
83 | allow from all
84 |
85 |
86 | It's also a good idea to disable the caching for `.nocache.html` files in `dispatcher.any` config file. Just add:
87 |
88 | /disable-nocache
89 | {
90 | /glob "*.nocache.html*"
91 | /type "deny"
92 | }
93 |
94 | at the end of the `/rules` section.
95 |
96 | ## Enabling TTL in dispatcher 4.1.11+
97 | In order to enable TTL on Apache with dispatcher just add:
98 |
99 | /enableTTL "1"
100 |
101 | to your dispatcher configuration.
102 |
103 |
104 | ## Enabling ESI in Varnish
105 |
106 | Just add following lines at the beginning of the `vcl_fetch` section in `/etc/varnish/default.vcl` file:
107 |
108 | if(req.url ~ "\.nocache.html") {
109 | set beresp.ttl = 0s;
110 | } else if (req.url ~ "\.html") {
111 | set beresp.do_esi = true;
112 | }
113 |
114 | It'll enable ESI includes in `.html` files and disable caching of the `.nocache.html` files.
115 |
116 | ## JavaScript Include
117 |
118 | Dynamic Include Filter can also replace dynamic components with AJAX tags, so they are loaded by the browser. It's called JSI. In the current version jQuery framework is used. More attention is required if included component has some Javascript code. Eg. Geometrixx Carousel component won't work because it's initialization is done in page `
` section while the component itself is still not loaded.
119 |
120 | ## Plain and synthetic resources
121 |
122 | There are two cases: the first involves including a component which is available at some URL, eg.
123 |
124 | /content/geometrixx/en/jcr:content/carousel.html
125 |
126 | In this case, component is replaced with include tag, and `nocache` selector is added
127 |
128 |
129 |
130 | If the filter gets request with selector it'll pass it (using `doChain`) further without taking any action.
131 |
132 | 
133 |
134 | There are also components which are created from so-called synthetic resources. Synthetic resource have some resourceType and path, but they don't have any node is JCR repository. An example is
135 |
136 | /content/geometrixx/en/jcr:content/userinfo
137 |
138 | component with `foundation/components/userinfo` resource type. These components return 404 error if you try to make a HTTP request. SDI recognizes these components and forms a different include URL for them in which resource type is added as a suffix, eg.:
139 |
140 | /content/geometrixx/en/jcr:content/userinfo.nocache.html/foundation/components/userinfo
141 |
142 | If filter got such request, it'll try to emulate `` JSP tag and includes resource with given type and `nocache` selector:
143 |
144 | /content/geometrixx/en/jcr:content/userinfo.nocache.html
145 |
146 | Selector is necessary, because otherwise filter would again replace component with a SSI tag.
147 |
148 | # External resources
149 |
150 | * [SDI presentation](http://www.pro-vision.de/content/medialib/pro-vision/production/adaptto/2012/adaptto2012-sling-dynamic-include-tomasz-rekaweki-pdf/_jcr_content/renditions/rendition.file/adaptto2012-sling-dynamic-include-tomasz-rekaweki.pdf) on [adaptTo() 2012](http://www.pro-vision.de/de/adaptto/adaptto-2012.html)
151 | * [SDI blog](http://www.cognifide.com/blogs/cq/sling-dynamic-include/) post on the Cognifide website
152 | * See the [Apache Sling website](http://sling.apache.org/) for the Sling reference documentation. Apache Sling, Apache and Sling are trademarks of the [Apache Software Foundation](http://apache.org).
153 |
154 | # Release notes
155 |
156 | ## 3.1.2
157 |
158 | - Introduced readable names for SDI configuration entries in the OSGi console ([SLING-7695](https://issues.apache.org/jira/browse/SLING-7695))
159 | - Fixed a bug where the selector configured for use with SDI was added multiple times to the same selector string ([SLING-7742](https://issues.apache.org/jira/browse/SLING-7742))
160 | - Introduced a mechanism that allows synthetic resources included via SDI to be cached by the AEM Dispatcher ([SLING-7785](https://issues.apache.org/jira/browse/SLING-7785))
161 |
162 | ## 3.1.0
163 |
164 | - Regular expression matching can be used when configuring resource paths ([SLING-7621](https://issues.apache.org/jira/browse/SLING-7621))
165 |
166 | ## 3.0.0
167 |
168 | Sling Dynamic Include donated to the Apache Sling project ([SLING-5594](https://issues.apache.org/jira/browse/SLING-5594)), repackaged and released ([SLING-6301](https://issues.apache.org/jira/browse/SLING-6301))
169 |
170 | ## 2.2.0
171 |
172 | \#17 Support for time-based (TTL) caching, Dispatcher 4.1.11+ required
173 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 | 4.0.0
23 |
24 |
25 | org.apache.sling
26 | sling-bundle-parent
27 | 52
28 |
29 |
30 |
31 | org.apache.sling.dynamic-include
32 | 3.3.3-SNAPSHOT
33 |
34 | Apache Sling Dynamic Include
35 | Dynamic Include filter for Apache Sling
36 |
37 |
38 | scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-dynamic-include.git
39 | scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-dynamic-include.git
40 | https://github.com/apache/sling-org-apache-sling-dynamic-include.git
41 | HEAD
42 |
43 |
44 |
45 |
46 | pacoolsky
47 | Przemyslaw Pakulski
48 | ppakulski@gmail.com
49 |
50 |
51 | trekawek
52 | Tomasz Rekawek
53 | rekawek@adobe.com
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.osgi
61 | org.osgi.framework
62 | provided
63 |
64 |
65 | org.osgi
66 | org.osgi.service.component
67 | provided
68 |
69 |
70 | org.osgi
71 | org.osgi.service.metatype.annotations
72 | provided
73 |
74 |
75 | org.osgi
76 | org.osgi.service.component.annotations
77 | provided
78 |
79 |
80 | org.osgi
81 | org.osgi.annotation.versioning
82 | provided
83 |
84 |
85 | org.apache.sling
86 | org.apache.sling.servlets.annotations
87 | provided
88 |
89 |
90 |
91 |
92 | javax.servlet
93 | javax.servlet-api
94 | provided
95 |
96 |
97 |
98 |
99 | org.apache.sling
100 | org.apache.sling.api
101 | 2.25.4
102 | provided
103 |
104 |
105 | org.apache.sling
106 | org.apache.sling.engine
107 | 2.14.0
108 | provided
109 |
110 |
111 | org.apache.sling
112 | org.apache.sling.commons.osgi
113 | 2.2.0
114 | provided
115 |
116 |
117 |
118 |
119 | org.slf4j
120 | slf4j-api
121 | provided
122 |
123 |
124 |
125 |
126 | org.apache.commons
127 | commons-lang3
128 | 3.0
129 | provided
130 |
131 |
132 |
133 |
134 | junit
135 | junit
136 | test
137 |
138 |
139 | org.mockito
140 | mockito-core
141 | 2.18.3
142 | test
143 |
144 |
145 | org.apache.sling
146 | org.apache.sling.testing.osgi-mock.junit4
147 | 2.4.10
148 | test
149 |
150 |
151 | org.osgi
152 | org.osgi.service.event
153 | test
154 |
155 |
156 | org.osgi
157 | org.osgi.service.log
158 | test
159 |
160 |
161 | org.osgi
162 | org.osgi.service.cm
163 | test
164 |
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------
/src/main/doc/plain_include.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apache/sling-org-apache-sling-dynamic-include/ff77046e4fee55893f2b4df652f0d38fb0dd3a47/src/main/doc/plain_include.png
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/CacheControlFilter.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude;
21 |
22 | import java.io.IOException;
23 |
24 | import javax.servlet.Filter;
25 | import javax.servlet.FilterChain;
26 | import javax.servlet.FilterConfig;
27 | import javax.servlet.ServletException;
28 | import javax.servlet.ServletRequest;
29 | import javax.servlet.ServletResponse;
30 |
31 | import org.apache.sling.api.SlingHttpServletRequest;
32 | import org.apache.sling.api.SlingHttpServletResponse;
33 | import org.apache.sling.servlets.annotations.SlingServletFilter;
34 | import org.apache.sling.servlets.annotations.SlingServletFilterScope;
35 | import org.osgi.framework.Constants;
36 | import org.osgi.service.component.annotations.Component;
37 | import org.osgi.service.component.annotations.Reference;
38 | import org.slf4j.Logger;
39 | import org.slf4j.LoggerFactory;
40 |
41 |
42 | @SlingServletFilter(scope = { SlingServletFilterScope.REQUEST, SlingServletFilterScope.FORWARD } )
43 | @Component(property = {
44 | Constants.SERVICE_RANKING + ":Integer=0"
45 | })
46 | public class CacheControlFilter implements Filter {
47 |
48 | private static final String HEADER_DATE = "Date";
49 |
50 | private static final String HEADER_CACHE_CONTROL = "Cache-Control";
51 |
52 | private static final Logger LOG = LoggerFactory.getLogger(CacheControlFilter.class);
53 |
54 | @Reference
55 | private ConfigurationWhiteboard configurationWhiteboard;
56 |
57 | @Override
58 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
59 | ServletException {
60 | final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
61 | final String resourceType = slingRequest.getResource().getResourceType();
62 | final Configuration config = configurationWhiteboard.getConfiguration(slingRequest, resourceType);
63 |
64 | if (config != null && config.hasTtlSet()) {
65 | SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;
66 | slingResponse.setHeader(HEADER_CACHE_CONTROL, "max-age=" + config.getTtl());
67 | LOG.debug("set \"{}: max-age={}\" to {}", HEADER_CACHE_CONTROL, config.getTtl(), resourceType);
68 | if (!slingResponse.containsHeader(HEADER_DATE)) {
69 | slingResponse.setDateHeader(HEADER_DATE, System.currentTimeMillis());
70 | }
71 | }
72 |
73 | chain.doFilter(request, response);
74 | }
75 |
76 | @Override
77 | public void init(FilterConfig filterConfig) throws ServletException {
78 | }
79 |
80 | @Override
81 | public void destroy() {
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/Configuration.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude;
21 |
22 | import java.util.Arrays;
23 | import java.util.Collection;
24 | import java.util.HashSet;
25 | import java.util.List;
26 |
27 | import org.apache.commons.lang3.ArrayUtils;
28 | import org.apache.commons.lang3.StringUtils;
29 | import org.apache.sling.api.SlingHttpServletRequest;
30 | import org.apache.sling.commons.osgi.PropertiesUtil;
31 | import org.apache.sling.dynamicinclude.pathmatcher.PathMatcher;
32 | import org.apache.sling.dynamicinclude.pathmatcher.PrefixPathMatcher;
33 | import org.apache.sling.dynamicinclude.pathmatcher.RegexPathMatcher;
34 | import org.osgi.framework.Constants;
35 | import org.osgi.service.component.annotations.Activate;
36 | import org.osgi.service.component.annotations.Component;
37 | import org.osgi.service.component.annotations.ConfigurationPolicy;
38 | import org.osgi.service.metatype.annotations.AttributeDefinition;
39 | import org.osgi.service.metatype.annotations.AttributeType;
40 | import org.osgi.service.metatype.annotations.Designate;
41 | import org.osgi.service.metatype.annotations.ObjectClassDefinition;
42 | import org.slf4j.Logger;
43 | import org.slf4j.LoggerFactory;
44 |
45 | /**
46 | * Include filter configuration.
47 | */
48 | @Component(service = Configuration.class,
49 | immediate = true,
50 | configurationPolicy = ConfigurationPolicy.REQUIRE,
51 | property = {
52 | Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
53 | "webconsole.configurationFactory.nameHint={include-filter.config.include-type} for [{include-filter.config.resource-types}] at path: {include-filter.config.path}"
54 | })
55 | @Designate(ocd = Configuration.Config.class, factory = true)
56 | public class Configuration {
57 |
58 | @ObjectClassDefinition(name = "Apache Sling Dynamic Include - Configuration")
59 | public @interface Config {
60 | @AttributeDefinition(name="Enabled", description="Check to enable the filter")
61 | boolean include$_$filter_config_enabled() default false;
62 |
63 | @AttributeDefinition(name="Base path regular expression", description="This SDI configuration will work only for paths matching this value. If value starts with \\\"^\\\" sign, regex matching will be performed. Otherwise it will check for path prefix.")
64 | String include$_$filter_config_path() default "/content";
65 |
66 | @AttributeDefinition(name = "Resource types",
67 | description = "Filter will replace components with selected resource types",
68 | type = AttributeType.STRING)
69 | String[] include$_$filter_config_resource$_$types() default {};
70 |
71 | @AttributeDefinition(name = "Include type", description = "Type of generated include tags. The Built-in option are 'SSI','ESI' and 'JSI'. Must match one of the IncludeGenerator service's type")
72 | String include$_$filter_config_include$_$type() default "SSI";
73 |
74 | @AttributeDefinition(name="Add comment", description = "Add comment to included components")
75 | boolean include$_$filter_config_add__comment() default false;
76 |
77 | @AttributeDefinition(name = "Filter selector", description = "Selector used to mark included resources")
78 | String include$_$filter_config_selector() default "nocache";
79 |
80 | @AttributeDefinition(name = "Extension", description = "Extension to append to virtual resources to make caching possible")
81 | String include$_$filter_config_extension() default "";
82 |
83 | @AttributeDefinition(name = "Component TTL", description = "\"Time to live\" cache header for rendered component (in seconds)")
84 | String include$_$filter_config_ttl() default "";
85 |
86 | @AttributeDefinition(name = "Required header", description = "SDI will work only for requests with given header")
87 | String include$_$filter_config_required__header() default "Server-Agent=Communique-Dispatcher";
88 |
89 | @AttributeDefinition(name = "Ignore URL params",
90 | description = "SDI will process the request even if it contains configured GET parameters",
91 | type = AttributeType.STRING)
92 | String[] include$_$filter_config_ignoreUrlParams() default {};
93 |
94 | @AttributeDefinition(name = "Include path rewriting", description = "Check to enable include path rewriting")
95 | boolean include$_$filter_config_rewrite() default false;
96 |
97 | @AttributeDefinition(name = "Append suffix to dynamic includes", description = "Check to append the suffix of the parent request to the dynamic include.")
98 | boolean include$_$filter_config_appendSuffix() default true;
99 |
100 | @AttributeDefinition(name = "Disable ignore URL params check", description = "Disable the check in the Ignore URL Params setting.")
101 | boolean include$_$filter_config_disableIgnoreUrlParams() default false;
102 | }
103 |
104 | private static final Logger LOG = LoggerFactory.getLogger(Configuration.class);
105 |
106 | private PathMatcher pathMatcher;
107 |
108 | private boolean isEnabled;
109 |
110 | private String includeSelector;
111 |
112 | private String extension;
113 |
114 | private int ttl;
115 |
116 | private List resourceTypes;
117 |
118 | private boolean addComment;
119 |
120 | private String includeTypeName;
121 |
122 | private String requiredHeader;
123 |
124 | private boolean disableIgnoreUrlParams;
125 |
126 | private Collection ignoreUrlParams;
127 |
128 | private boolean rewritePath;
129 |
130 | private boolean appendSuffix;
131 |
132 | @Activate
133 | public void activate(Config cfg) {
134 | isEnabled = cfg.include$_$filter_config_enabled();
135 | String pathPattern = cfg.include$_$filter_config_path();
136 | pathMatcher = choosePathMatcher(pathPattern);
137 | String[] resourceTypeList;
138 | resourceTypeList = PropertiesUtil.toStringArray(cfg.include$_$filter_config_resource$_$types(), new String[0]);
139 | for (int i = 0; i < resourceTypeList.length; i++) {
140 | String[] s = resourceTypeList[i].split(";");
141 | String name = s[0].trim();
142 | resourceTypeList[i] = name;
143 | }
144 | this.resourceTypes = Arrays.asList(resourceTypeList);
145 |
146 | includeSelector = cfg.include$_$filter_config_selector();
147 | extension = cfg.include$_$filter_config_extension();
148 | ttl = PropertiesUtil.toInteger(cfg.include$_$filter_config_ttl(), -1);
149 | addComment = cfg.include$_$filter_config_add__comment();
150 | includeTypeName = cfg.include$_$filter_config_include$_$type();
151 | requiredHeader = cfg.include$_$filter_config_required__header();
152 | ignoreUrlParams = new HashSet<>(
153 | Arrays.asList(PropertiesUtil.toStringArray(cfg.include$_$filter_config_ignoreUrlParams(), new String[0]))
154 | );
155 | rewritePath = cfg.include$_$filter_config_rewrite();
156 | appendSuffix = cfg.include$_$filter_config_appendSuffix();
157 | disableIgnoreUrlParams = cfg.include$_$filter_config_disableIgnoreUrlParams();
158 | }
159 |
160 | private PathMatcher choosePathMatcher(String pathPattern) {
161 | PathMatcher result;
162 | if (pathPattern.startsWith("^")) {
163 | LOG.debug("Configured path value: {} is a regexp - will use a RegexPathMatcher.", pathPattern);
164 | result = new RegexPathMatcher(pathPattern);
165 | } else {
166 | LOG.debug("Configured path value: {} is NOT a regexp - will use a PrefixPathMatcher.", pathPattern);
167 | result = new PrefixPathMatcher(pathPattern);
168 | }
169 | return result;
170 | }
171 |
172 | public PathMatcher getPathMatcher() {
173 | return pathMatcher;
174 | }
175 |
176 | public boolean hasIncludeSelector(SlingHttpServletRequest request) {
177 | return ArrayUtils.contains(request.getRequestPathInfo().getSelectors(), includeSelector);
178 | }
179 |
180 | public String getIncludeSelector() {
181 | return includeSelector;
182 | }
183 |
184 | public boolean hasExtension(final SlingHttpServletRequest request) {
185 | final String suffix = request.getRequestPathInfo().getSuffix();
186 | return suffix.endsWith("." + this.extension);
187 | }
188 |
189 | public boolean hasExtensionSet() {
190 | return StringUtils.isNotBlank(this.extension);
191 | }
192 |
193 | public String getExtension() {
194 | return this.extension;
195 | }
196 |
197 | public boolean hasTtlSet() {
198 | return ttl >= 0;
199 | }
200 |
201 | public int getTtl() {
202 | return ttl;
203 | }
204 |
205 | public boolean isSupportedResourceType(String resourceType) {
206 | return StringUtils.isNotBlank(resourceType) && resourceTypes.contains(resourceType);
207 | }
208 |
209 | public boolean getAddComment() {
210 | return addComment;
211 | }
212 |
213 | public String getIncludeTypeName() {
214 | return includeTypeName;
215 | }
216 |
217 | public boolean isEnabled() {
218 | return isEnabled;
219 | }
220 |
221 | public String getRequiredHeader() {
222 | return requiredHeader;
223 | }
224 |
225 | public Collection getIgnoreUrlParams() {
226 | return ignoreUrlParams;
227 | }
228 |
229 | public boolean isDisableIgnoreUrlParams() {
230 | return disableIgnoreUrlParams;
231 | }
232 |
233 | public boolean isRewritePath() {
234 | return rewritePath;
235 | }
236 |
237 | public boolean isAppendSuffix() {
238 | return appendSuffix;
239 | }
240 | }
241 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/ConfigurationWhiteboard.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude;
21 |
22 | import static org.osgi.service.component.annotations.FieldOption.UPDATE;
23 | import static org.osgi.service.component.annotations.ReferenceCardinality.MULTIPLE;
24 | import static org.osgi.service.component.annotations.ReferencePolicy.DYNAMIC;
25 |
26 | import java.util.Collection;
27 | import java.util.concurrent.CopyOnWriteArraySet;
28 |
29 | import org.apache.sling.api.SlingHttpServletRequest;
30 | import org.osgi.service.component.annotations.Component;
31 | import org.osgi.service.component.annotations.Reference;
32 |
33 | @Component(service = ConfigurationWhiteboard.class)
34 | public class ConfigurationWhiteboard {
35 |
36 | @Reference(service = Configuration.class, cardinality = MULTIPLE, policy = DYNAMIC, fieldOption = UPDATE)
37 | // declared Collection due to SLING-8986
38 | private volatile Collection configs = new CopyOnWriteArraySet();
39 |
40 | public Configuration getConfiguration(SlingHttpServletRequest request, String resourceType) {
41 | for (Configuration c : configs) {
42 | if (isEnabled(c, request) && c.isSupportedResourceType(resourceType)) {
43 | return c;
44 | }
45 | }
46 | return null;
47 | }
48 |
49 | private boolean isEnabled(Configuration config, SlingHttpServletRequest request) {
50 | final String requestPath = request.getRequestPathInfo().getResourcePath();
51 | return config.isEnabled() && config.getPathMatcher().match(requestPath);
52 | }
53 |
54 | // visible for testing
55 | void bindConfigs(final Configuration config) {
56 | configs.add(config);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/IncludeTagFilter.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude;
21 |
22 | import java.io.IOException;
23 | import java.io.PrintWriter;
24 | import java.net.URI;
25 | import java.net.URISyntaxException;
26 |
27 | import javax.servlet.Filter;
28 | import javax.servlet.FilterChain;
29 | import javax.servlet.FilterConfig;
30 | import javax.servlet.ServletException;
31 | import javax.servlet.ServletRequest;
32 | import javax.servlet.ServletResponse;
33 |
34 | import org.apache.commons.lang3.StringEscapeUtils;
35 | import org.apache.commons.lang3.StringUtils;
36 | import org.apache.sling.api.SlingHttpServletRequest;
37 | import org.apache.sling.api.resource.Resource;
38 | import org.apache.sling.api.resource.ResourceUtil;
39 | import org.apache.sling.dynamicinclude.api.IncludeGenerator;
40 | import org.apache.sling.dynamicinclude.generator.IncludeGeneratorWhiteboard;
41 | import org.apache.sling.dynamicinclude.impl.UrlBuilder;
42 | import org.apache.sling.dynamicinclude.util.RequestHelperUtil;
43 | import org.apache.sling.servlets.annotations.SlingServletFilter;
44 | import org.apache.sling.servlets.annotations.SlingServletFilterScope;
45 | import org.osgi.framework.Constants;
46 | import org.osgi.service.component.annotations.Component;
47 | import org.osgi.service.component.annotations.Reference;
48 | import org.slf4j.Logger;
49 | import org.slf4j.LoggerFactory;
50 |
51 | @SlingServletFilter(scope = SlingServletFilterScope.INCLUDE)
52 | @Component(property = { Constants.SERVICE_RANKING + ":Integer=-500"} )
53 | public class IncludeTagFilter implements Filter {
54 |
55 | private static final Logger LOG = LoggerFactory.getLogger(IncludeTagFilter.class);
56 |
57 | private static final String COMMENT = "\n";
58 |
59 | @Reference
60 | private ConfigurationWhiteboard configurationWhiteboard;
61 |
62 | @Reference
63 | private IncludeGeneratorWhiteboard generatorWhiteboard;
64 |
65 | @Override
66 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
67 | ServletException {
68 | final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
69 | final String resourceType = slingRequest.getResource().getResourceType();
70 |
71 | final Configuration config = configurationWhiteboard.getConfiguration(slingRequest, resourceType);
72 | if (config == null) {
73 | chain.doFilter(request, response);
74 | return;
75 | }
76 |
77 | final IncludeGenerator generator = generatorWhiteboard.getGenerator(config.getIncludeTypeName());
78 | if (generator == null) {
79 | LOG.error("Invalid generator: " + config.getIncludeTypeName());
80 | chain.doFilter(request, response);
81 | return;
82 | }
83 |
84 | final PrintWriter writer = response.getWriter();
85 | final String url = getUrl(config, slingRequest);
86 | if (url == null) {
87 | chain.doFilter(request, response);
88 | return;
89 | }
90 |
91 | if (config.getAddComment()) {
92 | writer.append(String.format(COMMENT, StringEscapeUtils.escapeHtml4(url), resourceType));
93 | }
94 |
95 | // Only write the includes markup if the required, configurable request
96 | // header is present
97 | if (shouldWriteIncludes(config, slingRequest)) {
98 | String include = generator.getInclude(slingRequest,url);
99 | LOG.debug(include);
100 | writer.append(include);
101 | } else {
102 | chain.doFilter(request, response);
103 | }
104 | }
105 |
106 | private boolean shouldWriteIncludes(Configuration config, SlingHttpServletRequest request) {
107 | // Do not skip GET requests when DisableIgnoreUrlParams set to true.
108 | if (!config.isDisableIgnoreUrlParams() && RequestHelperUtil.requestHasNonIgnoredParameters(config.getIgnoreUrlParams(), request)) {
109 | return false;
110 | }
111 | final String requiredHeader = config.getRequiredHeader();
112 | return StringUtils.isBlank(requiredHeader) || containsHeader(requiredHeader, request);
113 | }
114 |
115 | private boolean containsHeader(String requiredHeader, SlingHttpServletRequest request) {
116 | final String name, expectedValue;
117 | if (StringUtils.contains(requiredHeader, '=')) {
118 | final String split[] = StringUtils.split(requiredHeader, '=');
119 | name = split[0];
120 | expectedValue = split[1];
121 | } else {
122 | name = requiredHeader;
123 | expectedValue = null;
124 | }
125 |
126 | final String actualValue = request.getHeader(name);
127 | if (actualValue == null) {
128 | return false;
129 | } else if (expectedValue == null) {
130 | return true;
131 | } else {
132 | return actualValue.equalsIgnoreCase(expectedValue);
133 | }
134 | }
135 |
136 | private String getUrl(Configuration config, SlingHttpServletRequest request) {
137 | String url = buildUrl(config, request);
138 | if (config.isRewritePath()) {
139 | url = removeQuestionMark(url);
140 | url = request.getResourceResolver().map(request, url);
141 | } else {
142 | url = encodeJcrContentPart(url);
143 | try {
144 | url = new URI(null, null, url, null).toASCIIString();
145 | } catch (URISyntaxException e) {
146 | LOG.error("Include url is in the wrong format", e);
147 | return null;
148 | }
149 | }
150 |
151 | return url;
152 | }
153 |
154 | private String buildUrl(Configuration config, SlingHttpServletRequest request) {
155 | final Resource resource = request.getResource();
156 |
157 | final boolean synthetic = ResourceUtil.isSyntheticResource(request.getResource());
158 | return UrlBuilder.buildUrl(config.getIncludeSelector(), resource.getResourceType(), synthetic, config, request.getRequestPathInfo());
159 | }
160 |
161 | private static String sanitize(String path) {
162 | return StringUtils.defaultString(path);
163 | }
164 |
165 | private static String encodeJcrContentPart(String url) {
166 | return url.replace("jcr:content", "_jcr_content");
167 | }
168 |
169 | private static String removeQuestionMark(String url) {
170 | return url.replaceAll("[?]", "");
171 | }
172 |
173 | @Override
174 | public void init(FilterConfig filterConfig) throws ServletException {
175 | }
176 |
177 | @Override
178 | public void destroy() {
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/SyntheticResourceFilter.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude;
21 |
22 | import java.io.IOException;
23 |
24 | import javax.servlet.Filter;
25 | import javax.servlet.FilterChain;
26 | import javax.servlet.FilterConfig;
27 | import javax.servlet.RequestDispatcher;
28 | import javax.servlet.ServletException;
29 | import javax.servlet.ServletRequest;
30 | import javax.servlet.ServletResponse;
31 |
32 | import org.apache.commons.lang3.StringUtils;
33 | import org.apache.sling.api.SlingHttpServletRequest;
34 | import org.apache.sling.api.request.RequestDispatcherOptions;
35 | import org.apache.sling.api.resource.Resource;
36 | import org.apache.sling.api.resource.ResourceUtil;
37 | import org.apache.sling.servlets.annotations.SlingServletFilter;
38 | import org.apache.sling.servlets.annotations.SlingServletFilterScope;
39 | import org.osgi.framework.Constants;
40 | import org.osgi.service.component.annotations.Component;
41 | import org.osgi.service.component.annotations.Reference;
42 |
43 | @SlingServletFilter(scope = SlingServletFilterScope.REQUEST)
44 | @Component(property = {
45 | Constants.SERVICE_RANKING + ":Integer=" + Integer.MIN_VALUE,
46 | Constants.SERVICE_VENDOR +"=The Apache Software Foundation"
47 | })
48 | public class SyntheticResourceFilter implements Filter {
49 |
50 | @Reference
51 | private ConfigurationWhiteboard configurationWhiteboard;
52 |
53 | @Override
54 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
55 | ServletException {
56 | final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
57 | final String resourceType = getResourceTypeFromSuffix(slingRequest);
58 | final Configuration config = configurationWhiteboard.getConfiguration(slingRequest, resourceType);
59 |
60 | if (config == null || !config.hasIncludeSelector(slingRequest)
61 | || !ResourceUtil.isSyntheticResource(slingRequest.getResource())
62 | || (config.hasExtensionSet() && !config.hasExtension(slingRequest))) {
63 | chain.doFilter(request, response);
64 | return;
65 | }
66 |
67 | final RequestDispatcherOptions options = new RequestDispatcherOptions();
68 | options.setForceResourceType(resourceType);
69 | String resourcePath = StringUtils.substringBefore(slingRequest.getRequestPathInfo().getResourcePath(), ".");
70 | Resource resource = slingRequest.getResourceResolver().resolve(resourcePath);
71 | final RequestDispatcher dispatcher = slingRequest.getRequestDispatcher(resource, options);
72 | dispatcher.forward(request, response);
73 | }
74 |
75 | private static String getResourceTypeFromSuffix(final SlingHttpServletRequest request) {
76 | String suffix = request.getRequestPathInfo().getSuffix();
77 | suffix = StringUtils.substringBeforeLast(suffix, ".");
78 | return StringUtils.removeStart(suffix, "/");
79 | }
80 |
81 | @Override
82 | public void init(FilterConfig filterConfig) throws ServletException {
83 | }
84 |
85 | @Override
86 | public void destroy() {
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/api/IncludeGenerator.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.api;
21 |
22 | import org.apache.sling.api.SlingHttpServletRequest;
23 |
24 | /**
25 | * Include generator interface
26 | */
27 | public interface IncludeGenerator {
28 | String getType();
29 |
30 | /**
31 | * Returns the string used to include the resource.
32 | * For example, this might be a Javascript code that retrieves a snippet of html,
33 | * an Apache SSI Tag, or an Edge Side Include Tag.
34 | *
35 | * This method receives the sling request and an Url that has already be normalized as followed:
36 | *
37 | *
The query string has been removed
38 | *
The Url has been mapped using the ResourceResolver
39 | *
The jcr:content paths have been encoded to _jcr_content.
40 | *
41 | *
42 | * @param request the Sling request object
43 | * @param normalizedUrl the requested url, normalized
44 | * @return a String used to include the resource
45 | **/
46 | String getInclude(SlingHttpServletRequest request, String normalizedUrl);
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/api/package-info.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | @Version("1.0.0")
21 | package org.apache.sling.dynamicinclude.api;
22 |
23 | import org.osgi.annotation.versioning.Version;
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/generator/IncludeGeneratorWhiteboard.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.generator;
21 |
22 | import static org.osgi.service.component.annotations.FieldOption.UPDATE;
23 | import static org.osgi.service.component.annotations.ReferenceCardinality.MULTIPLE;
24 | import static org.osgi.service.component.annotations.ReferencePolicy.DYNAMIC;
25 |
26 | import java.util.Set;
27 | import java.util.concurrent.CopyOnWriteArraySet;
28 |
29 | import org.apache.sling.dynamicinclude.api.IncludeGenerator;
30 | import org.osgi.service.component.annotations.Component;
31 | import org.osgi.service.component.annotations.Reference;
32 |
33 | /**
34 | * Service that provides include generator of given type.
35 | */
36 |
37 | @Component(service = IncludeGeneratorWhiteboard.class)
38 | public class IncludeGeneratorWhiteboard {
39 |
40 | @Reference(service = IncludeGenerator.class, cardinality = MULTIPLE, policy = DYNAMIC, fieldOption = UPDATE)
41 | private Set generators = new CopyOnWriteArraySet();
42 |
43 | public IncludeGenerator getGenerator(String type) {
44 | for (IncludeGenerator generator : generators) {
45 | if (type.equals(generator.getType())) {
46 | return generator;
47 | }
48 | }
49 | return null;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/generator/types/EsiGenerator.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.generator.types;
21 |
22 | import org.apache.commons.lang3.StringEscapeUtils;
23 | import org.apache.sling.api.SlingHttpServletRequest;
24 | import org.apache.sling.dynamicinclude.api.IncludeGenerator;
25 | import org.osgi.service.component.annotations.Component;
26 |
27 | /**
28 | * ESI include generator
29 | */
30 | @Component
31 | public class EsiGenerator implements IncludeGenerator {
32 | private static final String GENERATOR_NAME = "ESI";
33 |
34 | @Override
35 | public String getType() {
36 | return GENERATOR_NAME;
37 | }
38 |
39 | @Override
40 | public String getInclude(SlingHttpServletRequest request, String url) {
41 | StringBuffer buf = new StringBuffer();
42 | buf.append("");
45 | return buf.toString();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/generator/types/JsiGenerator.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.generator.types;
21 |
22 | import java.io.BufferedReader;
23 | import java.io.IOException;
24 | import java.io.InputStream;
25 | import java.io.InputStreamReader;
26 | import java.io.UnsupportedEncodingException;
27 | import java.net.URL;
28 |
29 | import org.apache.commons.lang3.StringEscapeUtils;
30 | import org.apache.sling.api.SlingHttpServletRequest;
31 | import org.apache.sling.dynamicinclude.api.IncludeGenerator;
32 | import org.osgi.service.component.ComponentContext;
33 | import org.osgi.service.component.annotations.Activate;
34 | import org.osgi.service.component.annotations.Component;
35 | import org.slf4j.Logger;
36 | import org.slf4j.LoggerFactory;
37 |
38 | /**
39 | * Client side include generator - using Ajax/JQuery.
40 | */
41 | @Component
42 | public class JsiGenerator implements IncludeGenerator {
43 | private static final String TEMPLATE_FILENAME = "generators/javascript.html";
44 |
45 | private static final String UUID_FIELD = "${uniqueId}";
46 |
47 | private static final String URL_FIELD = "${url}";
48 |
49 | private static final Logger LOG = LoggerFactory.getLogger(JsiGenerator.class);
50 |
51 | private static final String GENERATOR_NAME = "JSI";
52 |
53 | private volatile int divId = 1000;
54 |
55 | private String template;
56 |
57 | @Activate
58 | public void activate(ComponentContext ctx) {
59 | URL url = ctx.getBundleContext().getBundle().getResource(TEMPLATE_FILENAME);
60 | if (url == null) {
61 | LOG.error("File " + TEMPLATE_FILENAME + " not found in bundle.");
62 | return;
63 | }
64 | readTemplateFromUrl(url);
65 | }
66 |
67 | @Override
68 | public String getType() {
69 | return GENERATOR_NAME;
70 | }
71 |
72 | @Override
73 | public String getInclude(SlingHttpServletRequest request, String url) {
74 | if (template == null) {
75 | throw new IllegalStateException("JSI generator hasn't be initialized");
76 | }
77 |
78 | String divName;
79 | synchronized (this) {
80 | divName = "dynamic_include_filter_div_" + divId++;
81 | }
82 |
83 | return template.replace(UUID_FIELD, divName).replace(URL_FIELD, StringEscapeUtils.escapeEcmaScript(url));
84 | }
85 |
86 | private void readTemplateFromUrl(URL url) {
87 | BufferedReader br = null;
88 | try {
89 | InputStream in = url.openStream();
90 | br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
91 | StringBuilder builder = new StringBuilder();
92 | String line;
93 | while ((line = br.readLine()) != null) {
94 | builder.append(line).append('\n');
95 | }
96 | template = builder.toString();
97 | } catch (UnsupportedEncodingException e) {
98 | LOG.error("Error while reading template", e);
99 | } catch (IOException e) {
100 | LOG.error("Error while reading template", e);
101 | } finally {
102 | try {
103 | if (br != null) {
104 | br.close();
105 | }
106 | } catch (Exception e) {
107 | LOG.error("Error while closing reader", e);
108 | }
109 | }
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/generator/types/SsiGenerator.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.generator.types;
21 |
22 | import org.apache.sling.api.SlingHttpServletRequest;
23 | import org.apache.sling.dynamicinclude.api.IncludeGenerator;
24 | import org.osgi.service.component.annotations.Component;
25 |
26 | /**
27 | * Apache SSI include generator
28 | */
29 | @Component
30 | public class SsiGenerator implements IncludeGenerator {
31 | private static final String GENERATOR_NAME = "SSI";
32 |
33 | @Override
34 | public String getType() {
35 | return GENERATOR_NAME;
36 | }
37 |
38 | @Override
39 | public String getInclude(SlingHttpServletRequest request, String url) {
40 | StringBuffer buf = new StringBuffer();
41 | buf.append("");
44 | return buf.toString();
45 | }
46 |
47 | /**
48 | * Escapes $ to \$
49 | *
50 | * @param url
51 | * url to escape
52 | * @return escaped url
53 | */
54 | private Object escapeForApache(String url) {
55 | return url.replace("$", "\\$");
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/impl/UrlBuilder.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.impl;
21 |
22 | import java.util.Arrays;
23 |
24 | import org.apache.commons.lang3.StringUtils;
25 | import org.apache.sling.api.request.RequestPathInfo;
26 | import org.apache.sling.dynamicinclude.Configuration;
27 |
28 | public final class UrlBuilder {
29 |
30 |
31 | public static String buildUrl(String includeSelector, String resourceType, boolean synthetic, Configuration config, RequestPathInfo pathInfo) {
32 | final StringBuilder builder = new StringBuilder();
33 |
34 | final String resourcePath = pathInfo.getResourcePath();
35 | builder.append(resourcePath);
36 | String currentSelectorString = StringUtils.defaultString(pathInfo.getSelectorString());
37 | if (pathInfo.getSelectorString() != null) {
38 | builder.append('.').append(currentSelectorString);
39 | }
40 | if (includeSelectorNotAlreadyPresent(pathInfo.getSelectors(), includeSelector)) {
41 | builder.append('.').append(includeSelector);
42 | }
43 | builder.append('.').append(pathInfo.getExtension());
44 | if (synthetic) {
45 | builder.append('/').append(resourceType);
46 | if (config.hasExtensionSet()) {
47 | builder.append('.').append(config.getExtension());
48 | }
49 | } else {
50 | if (config.isAppendSuffix()) {
51 | builder.append(StringUtils.defaultString(pathInfo.getSuffix()));
52 | }
53 | }
54 | return builder.toString();
55 | }
56 |
57 | private static boolean includeSelectorNotAlreadyPresent(String[] currentSelectors, String includeSelector) {
58 | if (includeSelector.isEmpty()) {
59 | return false;
60 | }
61 | return !Arrays.asList(currentSelectors).contains(includeSelector);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/pathmatcher/PathMatcher.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.sling.dynamicinclude.pathmatcher;
20 |
21 | public interface PathMatcher {
22 |
23 | /**
24 | * Matches given path with the configured path parameter
25 | * @param path path to match
26 | * @return true if path matches, false otherwise
27 | */
28 | boolean match(String path);
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/pathmatcher/PrefixPathMatcher.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.sling.dynamicinclude.pathmatcher;
20 |
21 | import org.apache.commons.lang3.StringUtils;
22 |
23 | public class PrefixPathMatcher implements PathMatcher {
24 |
25 | private final String configurationValue;
26 |
27 | public PrefixPathMatcher(String configurationValue) {
28 | this.configurationValue = configurationValue;
29 | }
30 |
31 | @Override
32 | public boolean match(String path) {
33 | return StringUtils.isNotBlank(path) && path.startsWith(configurationValue);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/pathmatcher/RegexPathMatcher.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.sling.dynamicinclude.pathmatcher;
20 |
21 | import java.util.regex.Pattern;
22 | import org.apache.commons.lang3.StringUtils;
23 |
24 | public class RegexPathMatcher implements PathMatcher {
25 |
26 | private final Pattern configurationPattern;
27 |
28 | public RegexPathMatcher(String configurationRegex) {
29 | this.configurationPattern = Pattern.compile(configurationRegex);
30 | }
31 |
32 | @Override
33 | public boolean match(String path) {
34 | return StringUtils.isNotBlank(path) && configurationPattern.matcher(path).matches();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/sling/dynamicinclude/util/RequestHelperUtil.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.util;
21 |
22 | import org.apache.sling.api.SlingHttpServletRequest;
23 |
24 | import java.util.Collection;
25 |
26 | public class RequestHelperUtil {
27 |
28 | private RequestHelperUtil() {
29 | // private constructor to prevent instance creation of util classes
30 | }
31 |
32 | /**
33 | * Checks if a request contains any parameters that are not defined in the ignoreUrlParams.
34 | * Wildcards as they are possible to configure on Apache-Dispatcher, are also properly checked.
35 | *
36 | * @param ignoreUrlParams The list of configured ignoreUrlParams (regular expressions)
37 | * @param request The slingRequest whose parameters we want to check
38 | * @return true if there was any parameter that is not defined on the ignoreUrlsParams-Collection, otherwise false
39 | */
40 | public static boolean requestHasNonIgnoredParameters(Collection ignoreUrlParams, SlingHttpServletRequest request) {
41 | return request.getParameterMap().keySet().stream()
42 | .anyMatch(urlParameter -> !matchesRegularExpressionIgnoreUrlParameter(ignoreUrlParams, urlParameter));
43 | }
44 |
45 | private static boolean matchesRegularExpressionIgnoreUrlParameter(Collection ignoreUrlParameters, String requestParameter) {
46 | for (String ignoreUrlParameter : ignoreUrlParameters) {
47 | if (requestParameter.matches(ignoreUrlParameter)) {
48 | return true;
49 | }
50 | }
51 |
52 | return false;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/resources/generators/javascript.html:
--------------------------------------------------------------------------------
1 |
19 |
20 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/test/java/org/apache/sling/dynamicinclude/ConfigurationTest.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude;
21 |
22 | import static org.hamcrest.CoreMatchers.is;
23 | import static org.hamcrest.MatcherAssert.assertThat;
24 |
25 | import java.util.HashMap;
26 | import java.util.Map;
27 | import org.apache.sling.dynamicinclude.pathmatcher.PrefixPathMatcher;
28 | import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
29 | import org.junit.Before;
30 | import org.junit.Rule;
31 | import org.junit.Test;
32 |
33 | public class ConfigurationTest {
34 |
35 | private Configuration tested;
36 |
37 | @Rule
38 | public final OsgiContext context = new OsgiContext();
39 |
40 | @Before
41 | public void setUp() {
42 | tested = new Configuration();
43 | }
44 |
45 | @Test(expected = RuntimeException.class)
46 | public void shouldThrowExceptionWhenRegexisInvalid() throws Exception {
47 |
48 | context.registerInjectActivateService(tested, "include-filter.config.path", "^(");
49 | }
50 |
51 | @Test
52 | public void shouldSetDefaultValuesWhenPropertiesAreEmpty() throws Exception {
53 | Map properties = new HashMap();
54 |
55 | context.registerInjectActivateService(tested, properties);
56 |
57 | assertThat(tested.getPathMatcher().getClass().isAssignableFrom(PrefixPathMatcher.class), is(true));
58 | assertThat(tested.getAddComment(), is(false));
59 | assertThat(tested.getIgnoreUrlParams().size(), is(0));
60 | assertThat(tested.getIncludeSelector(), is("nocache"));
61 | assertThat(tested.getIncludeTypeName(), is("SSI"));
62 | assertThat(tested.getRequiredHeader(), is("Server-Agent=Communique-Dispatcher"));
63 | assertThat(tested.getTtl(), is(-1));
64 | assertThat(tested.isEnabled(), is(false));
65 | assertThat(tested.hasTtlSet(), is(false));
66 | assertThat(tested.isRewritePath(), is(false));
67 | }
68 |
69 | @Test
70 | public void shouldSetConfigurationValues() throws Exception {
71 | Map properties = new HashMap();
72 | properties.put("include-filter.config.path", "/content/test/path");
73 | properties.put("include-filter.config.include-type", "ESI");
74 | properties.put("include-filter.config.add_comment", true);
75 | properties.put("include-filter.config.ttl", 60);
76 | properties.put("include-filter.config.enabled", true);
77 | properties.put("include-filter.config.resource-types",
78 | new String[] { "test/resource/type", "test/resource/type2" });
79 | properties.put("include-filter.config.required_header", "CustomHeader: value");
80 | properties.put("include-filter.config.selector", "cache");
81 | properties.put("include-filter.config.rewrite", true);
82 | properties.put("include-filter.config.ignoreUrlParams", new String[] { "query", "query2" });
83 |
84 | context.registerInjectActivateService(tested, properties);
85 |
86 | assertThat(tested.getPathMatcher().getClass().isAssignableFrom(PrefixPathMatcher.class), is(true));
87 | assertThat(tested.getAddComment(), is(true));
88 | assertThat(tested.getIgnoreUrlParams().size(), is(2));
89 | assertThat(tested.getIncludeSelector(), is("cache"));
90 | assertThat(tested.getIncludeTypeName(), is("ESI"));
91 | assertThat(tested.getRequiredHeader(), is("CustomHeader: value"));
92 | assertThat(tested.getTtl(), is(60));
93 | assertThat(tested.isEnabled(), is(true));
94 | assertThat(tested.hasTtlSet(), is(true));
95 | assertThat(tested.isRewritePath(), is(true));
96 | assertThat(tested.isSupportedResourceType("test/resource/type"), is(true));
97 | assertThat(tested.isSupportedResourceType("test/resource/type2"), is(true));
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/test/java/org/apache/sling/dynamicinclude/ConfigurationWhiteboardTest.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.sling.dynamicinclude;
20 |
21 | import static org.hamcrest.CoreMatchers.is;
22 | import static org.hamcrest.CoreMatchers.nullValue;
23 | import static org.hamcrest.MatcherAssert.assertThat;
24 | import static org.mockito.Mockito.when;
25 |
26 | import java.util.HashMap;
27 | import java.util.Map;
28 |
29 | import org.apache.sling.api.SlingHttpServletRequest;
30 | import org.apache.sling.api.request.RequestPathInfo;
31 | import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
32 | import org.junit.Before;
33 | import org.junit.Rule;
34 | import org.junit.Test;
35 | import org.junit.runner.RunWith;
36 | import org.mockito.Mock;
37 | import org.mockito.junit.MockitoJUnitRunner;
38 |
39 | @RunWith(MockitoJUnitRunner.class)
40 | public class ConfigurationWhiteboardTest {
41 |
42 | private static final String TEST_RESOURCE_PATH = "/content/test/engl/home/pageresource";
43 | public static final String TEST_RESOURCE_TYPE = "test/component/resourceType";
44 |
45 | @Rule
46 | public final OsgiContext context = new OsgiContext();
47 |
48 | private ConfigurationWhiteboard tested;
49 |
50 | @Mock
51 | private SlingHttpServletRequest request;
52 |
53 | @Mock
54 | private RequestPathInfo requestPathInfo;
55 |
56 | @Before
57 | public void setUp() throws Exception {
58 | tested = new ConfigurationWhiteboard();
59 | when(request.getRequestPathInfo()).thenReturn(requestPathInfo);
60 | when(requestPathInfo.getResourcePath()).thenReturn(TEST_RESOURCE_PATH);
61 | }
62 |
63 | private Configuration buildConfiguration(boolean enabled, String pathRegex, String[] resourceTypes) {
64 | Configuration configuration = new Configuration();
65 | Map properties = new HashMap();
66 | properties.put("include-filter.config.enabled", enabled);
67 | properties.put("include-filter.config.path", pathRegex);
68 | properties.put("include-filter.config.resource-types", resourceTypes);
69 |
70 | return context.registerInjectActivateService(configuration, properties);
71 | }
72 |
73 | @Test
74 | public void shouldNotReturnConfigsIfNotConfigsHaveBeenBound() throws Exception {
75 | assertThat(tested.getConfiguration(request, TEST_RESOURCE_TYPE), is(nullValue()));
76 | }
77 |
78 | @Test
79 | public void shouldNotReturnConfigurationIfResourceTypeDoesNotMatch() throws Exception {
80 | buildConfiguration(true, "^/content.*$", new String[]{"invalid/resourceType"});
81 | context.registerInjectActivateService(tested);
82 |
83 | assertThat(tested.getConfiguration(request, TEST_RESOURCE_TYPE), is(nullValue()));
84 | }
85 |
86 | @Test
87 | public void shouldNotReturnConfigurationIfConfigurationIsDisabled() throws Exception {
88 | buildConfiguration(false, "^/content.*$", new String[]{TEST_RESOURCE_TYPE});
89 | context.registerInjectActivateService(tested);
90 |
91 | assertThat(tested.getConfiguration(request, TEST_RESOURCE_TYPE), is(nullValue()));
92 | }
93 |
94 | @Test
95 | public void shouldNotReturnConfigurationIfPathDoesNotMatchRegex() throws Exception {
96 | buildConfiguration(true, "^/content/notMatched/.*$",
97 | new String[]{TEST_RESOURCE_TYPE});
98 | context.registerInjectActivateService(tested);
99 |
100 | assertThat(tested.getConfiguration(request, TEST_RESOURCE_TYPE), is(nullValue()));
101 | }
102 |
103 | @Test
104 | public void shouldReturnValidConfiguration() throws Exception {
105 | Configuration testConfiguration = buildConfiguration(true, "^/content.*$", new String[]{TEST_RESOURCE_TYPE});
106 | context.registerInjectActivateService(tested);
107 |
108 | assertThat(tested.getConfiguration(request, TEST_RESOURCE_TYPE), is(testConfiguration));
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/test/java/org/apache/sling/dynamicinclude/impl/UrlBuilderTest.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.impl;
21 |
22 | import org.apache.commons.lang3.StringUtils;
23 | import org.apache.sling.api.request.RequestPathInfo;
24 | import org.apache.sling.dynamicinclude.Configuration;
25 | import org.junit.Before;
26 | import org.junit.Test;
27 | import org.junit.runner.RunWith;
28 | import org.mockito.Mock;
29 | import org.mockito.junit.MockitoJUnitRunner;
30 |
31 | import static org.hamcrest.CoreMatchers.is;
32 | import static org.hamcrest.MatcherAssert.assertThat;
33 | import static org.mockito.Mockito.*;
34 |
35 | @RunWith(MockitoJUnitRunner.class)
36 | public class UrlBuilderTest {
37 |
38 | @Mock
39 | private RequestPathInfo requestPathInfo;
40 |
41 | @Mock
42 | private Configuration config;
43 |
44 | @Test
45 | public void shouldAppendTheIncludeSelectorToUrlWithNoSelectors() {
46 | givenAnHtmlRequestForResource("/resource/path");
47 | withSelectorString(null);
48 | boolean isSyntheticResource = false;
49 |
50 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
51 |
52 | assertThat(actualResult, is("/resource/path.include.html"));
53 | }
54 |
55 | @Test
56 | public void shouldNotAppendTheIncludeSelectorToUrlWhenNotSetAndAppendRequestPathInfoSelectorWhenNotSet() {
57 | givenAnHtmlRequestForResource("/resource/path");
58 | withSelectorString(null);
59 | boolean isSyntheticResource = false;
60 |
61 | String actualResult = UrlBuilder.buildUrl("", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
62 |
63 | assertThat(actualResult, is("/resource/path.html"));
64 | }
65 |
66 | @Test
67 | public void shouldNotAppendTheIncludeSelectorToUrlWhenNotSetAndAppendRequestPathInfoSelectorWhenSet() {
68 | givenAnHtmlRequestForResource("/resource/path");
69 | withSelectorString("foo.bar.baz");
70 | boolean isSyntheticResource = false;
71 |
72 | String actualResult = UrlBuilder.buildUrl("", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
73 |
74 | assertThat(actualResult, is("/resource/path.foo.bar.baz.html"));
75 | }
76 |
77 | @Test
78 | public void shouldAppendTheIncludeSelectorToUrlWhenSetAndNotAppendRequestPathInfoSelectorWhenNotSet() {
79 | givenAnHtmlRequestForResource("/resource/path");
80 | withSelectorString(null);
81 | boolean isSyntheticResource = false;
82 |
83 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
84 |
85 | assertThat(actualResult, is("/resource/path.include.html"));
86 | }
87 |
88 | @Test
89 | public void shouldAppendTheIncludeSelectorToUrlThatAlreadyContainsOtherSelectors() {
90 | givenAnHtmlRequestForResource("/resource/path");
91 | withSelectorString("foo.bar.baz");
92 | boolean isSyntheticResource = false;
93 |
94 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
95 |
96 | assertThat(actualResult, is("/resource/path.foo.bar.baz.include.html"));
97 | }
98 |
99 | @Test
100 | public void shouldAppendTheIncludeSelectorToUrlContainingMixedAlphanumericSelectors() {
101 | givenAnHtmlRequestForResource("/resource/path");
102 | withSelectorString("foo.2.31");
103 | boolean isSyntheticResource = false;
104 |
105 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
106 |
107 | assertThat(actualResult, is("/resource/path.foo.2.31.include.html"));
108 | }
109 |
110 | @Test
111 | public void shouldNotDuplicateTheIncludeSelectorIfAlreadyPresent() {
112 | givenAnHtmlRequestForResource("/resource/path");
113 | withSelectorString("foo.include");
114 | boolean isSyntheticResource = false;
115 |
116 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
117 |
118 | assertThat(actualResult, is("/resource/path.foo.include.html"));
119 | }
120 |
121 | @Test
122 | public void shouldAppendTheIncludeSelectorWhenThereIsAnotherSelectorThatAccidentallyContainsTheIncludeOne() {
123 | givenAnHtmlRequestForResource("/resource/path");
124 | withSelectorString("longerSelectorThatHappensToContainTheIncludeSelector");
125 | boolean isSyntheticResource = false;
126 |
127 | String actualResult = UrlBuilder.buildUrl("IncludeSelector", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
128 |
129 | assertThat(actualResult, is("/resource/path.longerSelectorThatHappensToContainTheIncludeSelector.IncludeSelector.html"));
130 | }
131 |
132 | @Test
133 | public void shouldAppendSuffixForSyntheticResources() {
134 | givenAnHtmlRequestForResource("/resource/path");
135 | withSelectorString("foo.include");
136 | boolean isSyntheticResource = true;
137 |
138 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
139 |
140 | assertThat(actualResult, is("/resource/path.foo.include.html/apps/example/resource/type"));
141 | }
142 |
143 | @Test
144 | public void shouldAppendSuffixWhenRequestedByDefault() {
145 | givenAnHtmlRequestForResource("/resource/path");
146 | withSelectorString("foo.include");
147 | withSuffixString("/suffix/to/some/other/information");
148 | boolean isSyntheticResource = false;
149 |
150 | when(config.isAppendSuffix()).thenReturn(true);
151 |
152 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
153 |
154 | assertThat(actualResult, is("/resource/path.foo.include.html/suffix/to/some/other/information"));
155 | }
156 |
157 | @Test
158 | public void shouldNotAppendSuffixWhenConfigured() {
159 | givenAnHtmlRequestForResource("/resource/path");
160 | withSelectorString("foo.include");
161 | withSuffixString("/suffix/to/some/other/information");
162 | boolean isSyntheticResource = false;
163 |
164 | when(config.isAppendSuffix()).thenReturn(false);
165 |
166 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
167 |
168 | verify(requestPathInfo,times(0)).getSuffix();
169 | assertThat(actualResult, is("/resource/path.foo.include.html"));
170 | }
171 |
172 | @Test
173 | public void shouldAppendExtensionForSyntheticResources() {
174 | givenAnHtmlRequestForResource("/resource/path");
175 | withSelectorString("foo.include");
176 |
177 | when(config.hasExtensionSet()).thenReturn(true);
178 | when(config.getExtension()).thenReturn("sdi");
179 |
180 | boolean isSyntheticResource = true;
181 |
182 | String actualResult = UrlBuilder.buildUrl("include", "apps/example/resource/type", isSyntheticResource, config, requestPathInfo);
183 |
184 | assertThat(actualResult, is("/resource/path.foo.include.html/apps/example/resource/type.sdi"));
185 | }
186 |
187 | private void givenAnHtmlRequestForResource(String resourcePath) {
188 | when(requestPathInfo.getExtension()).thenReturn("html");
189 | when(requestPathInfo.getResourcePath()).thenReturn(resourcePath);
190 | }
191 |
192 | private void withSelectorString(String selectorString) {
193 | when(requestPathInfo.getSelectorString()).thenReturn(selectorString);
194 | when(requestPathInfo.getSelectors()).thenReturn(StringUtils.defaultString(selectorString).split("\\."));
195 | }
196 |
197 | private void withSuffixString(String suffixString) {
198 | when(requestPathInfo.getSuffix()).thenReturn(suffixString);
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/src/test/java/org/apache/sling/dynamicinclude/pathmatcher/PrefixPathMatcherTest.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.pathmatcher;
21 |
22 | import static org.junit.Assert.assertFalse;
23 | import static org.junit.Assert.assertTrue;
24 | import org.junit.Test;
25 |
26 | public class PrefixPathMatcherTest {
27 | private final PrefixPathMatcher ppm = new PrefixPathMatcher("/foo");
28 |
29 | @Test
30 | public void testMatch() {
31 | assertTrue(ppm.match("/foo"));
32 | assertTrue(ppm.match("/foobar"));
33 | }
34 |
35 | @Test
36 | public void testNoMatch() {
37 | assertFalse(ppm.match("/barbar"));
38 | assertFalse(ppm.match("/bar/foo"));
39 | assertFalse(ppm.match(""));
40 | assertFalse(ppm.match(null));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/org/apache/sling/dynamicinclude/pathmatcher/RegexPathMatcherTest.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.pathmatcher;
21 |
22 | import static org.junit.Assert.assertFalse;
23 | import static org.junit.Assert.assertTrue;
24 | import org.junit.Test;
25 |
26 | public class RegexPathMatcherTest {
27 | private final RegexPathMatcher rpm = new RegexPathMatcher("^/[fg]oo");
28 |
29 | @Test
30 | public void testMatch() {
31 | assertTrue(rpm.match("/foo"));
32 | assertTrue(rpm.match("/goo"));
33 | }
34 |
35 | @Test
36 | public void testNoMatch() {
37 | assertFalse(rpm.match("/foobar"));
38 | assertFalse(rpm.match(""));
39 | assertFalse(rpm.match(null));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/org/apache/sling/dynamicinclude/util/RequestHelperUtilTest.java:
--------------------------------------------------------------------------------
1 | /*-
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package org.apache.sling.dynamicinclude.util;
21 |
22 | import org.apache.sling.api.SlingHttpServletRequest;
23 | import org.junit.Assert;
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.mockito.Mockito;
28 | import org.mockito.junit.MockitoJUnitRunner;
29 |
30 | import java.util.ArrayList;
31 | import java.util.Collection;
32 | import java.util.HashMap;
33 | import java.util.Map;
34 |
35 | @RunWith(MockitoJUnitRunner.class)
36 | public class RequestHelperUtilTest {
37 |
38 | private static final String TEST_PARAM_NAME = "test-param";
39 | private static final String IGNORE_PARAM_REGEX_STAR_WILDCARD = "test-(.*)";
40 |
41 | private SlingHttpServletRequest slingHttpServletRequest;
42 | private Collection ignoreUrlParams;
43 | private Map parameterMap;
44 |
45 | @Before
46 | public void prepareTestData() {
47 | slingHttpServletRequest = Mockito.mock(SlingHttpServletRequest.class);
48 |
49 | ignoreUrlParams = new ArrayList<>();
50 | parameterMap = new HashMap<>();
51 | }
52 |
53 | @Test
54 | public void requestHasParameters_noParametersAtAll() {
55 | Mockito.when(slingHttpServletRequest.getParameterMap()).thenReturn(parameterMap);
56 |
57 | Assert.assertFalse(RequestHelperUtil.requestHasNonIgnoredParameters(ignoreUrlParams, slingHttpServletRequest));
58 | }
59 |
60 | @Test
61 | public void requestHasParameters_onlyIgnoredParameters_withoutWildcards() {
62 | ignoreUrlParams.add(TEST_PARAM_NAME);
63 |
64 | parameterMap.put(TEST_PARAM_NAME, new String[] {});
65 |
66 | Mockito.when(slingHttpServletRequest.getParameterMap()).thenReturn(parameterMap);
67 |
68 | Assert.assertFalse(RequestHelperUtil.requestHasNonIgnoredParameters(ignoreUrlParams, slingHttpServletRequest));
69 | }
70 |
71 | @Test
72 | public void requestHasParameters_onlyIgnoredParameters_withWildcards() {
73 | ignoreUrlParams.add(IGNORE_PARAM_REGEX_STAR_WILDCARD);
74 | ignoreUrlParams.add("hello");
75 |
76 | parameterMap.put(TEST_PARAM_NAME, new String[] {});
77 | parameterMap.put("hello", new String[] {});
78 |
79 | Mockito.when(slingHttpServletRequest.getParameterMap()).thenReturn(parameterMap);
80 |
81 | Assert.assertFalse(RequestHelperUtil.requestHasNonIgnoredParameters(ignoreUrlParams, slingHttpServletRequest));
82 | }
83 |
84 | @Test
85 | public void requestHasParameters_hasParametersThatAreNotIgnored_withoutWildcards() {
86 | ignoreUrlParams.add(TEST_PARAM_NAME);
87 |
88 | parameterMap.put(TEST_PARAM_NAME, new String[] {});
89 | parameterMap.put("some-other-param", new String[] {});
90 |
91 | Mockito.when(slingHttpServletRequest.getParameterMap()).thenReturn(parameterMap);
92 |
93 | Assert.assertTrue(RequestHelperUtil.requestHasNonIgnoredParameters(ignoreUrlParams, slingHttpServletRequest));
94 | }
95 |
96 | @Test
97 | public void requestHasParameters_hasParametersThatAreNotIgnored_withWildcards() {
98 | ignoreUrlParams.add(IGNORE_PARAM_REGEX_STAR_WILDCARD);
99 |
100 | parameterMap.put(TEST_PARAM_NAME, new String[] {});
101 | parameterMap.put("some-other-param", new String[] {});
102 |
103 | Mockito.when(slingHttpServletRequest.getParameterMap()).thenReturn(parameterMap);
104 |
105 | Assert.assertTrue(RequestHelperUtil.requestHasNonIgnoredParameters(ignoreUrlParams, slingHttpServletRequest));
106 | }
107 |
108 | @Test
109 | public void requestHasParameters_specificRegex_hasIgnoredParameters() {
110 | ignoreUrlParams.add("hello-[0-9]-world");
111 |
112 | parameterMap.put(TEST_PARAM_NAME, new String[] {});
113 | parameterMap.put("hello-1-world", new String[] {});
114 | parameterMap.put("hello-2-world", new String[] {});
115 |
116 | Mockito.when(slingHttpServletRequest.getParameterMap()).thenReturn(parameterMap);
117 |
118 | Assert.assertTrue(RequestHelperUtil.requestHasNonIgnoredParameters(ignoreUrlParams, slingHttpServletRequest));
119 | }
120 |
121 | @Test
122 | public void requestHasParameters_specificRegex_hasNoIgnoredParameters() {
123 | ignoreUrlParams.add("hello-[0-9]-world");
124 |
125 | parameterMap.put("hello-1-world", new String[] {});
126 | parameterMap.put("hello-2-world", new String[] {});
127 | parameterMap.put("hello-3-world", new String[] {});
128 |
129 | Mockito.when(slingHttpServletRequest.getParameterMap()).thenReturn(parameterMap);
130 |
131 | Assert.assertFalse(RequestHelperUtil.requestHasNonIgnoredParameters(ignoreUrlParams, slingHttpServletRequest));
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------