/*
* Copyright 2011-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.glowroot.agent.plugin.servlet;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import org.glowroot.agent.plugin.api.Agent;
import org.glowroot.agent.plugin.api.config.ConfigListener;
import org.glowroot.agent.plugin.api.config.ConfigService;
class ServletPluginProperties {
static final String HTTP_SESSION_ID_ATTR = "::id";
private static final String CAPTURE_REQUEST_PARAMS_PROPERTY_NAME = "captureRequestParameters";
private static final String MASK_REQUEST_PARAMS_PROPERTY_NAME = "maskRequestParameters";
private static final String CAPTURE_REQUEST_HEADER_PROPERTY_NAME = "captureRequestHeaders";
private static final String CAPTURE_RESPONSE_HEADER_PROPERTY_NAME = "captureResponseHeaders";
private static final String SESSION_USER_ATTRIBUTE_PROPERTY_NAME = "sessionUserAttribute";
private static final String CAPTURE_SESSION_ATTRIBUTES_PROPERTY_NAME =
"captureSessionAttributes";
private static final ConfigService configService = Agent.getConfigService("servlet");
private static final Splitter splitter = Splitter.on(',').trimResults().omitEmptyStrings();
private static ImmutableList<Pattern> captureRequestParameters = ImmutableList.of();
private static ImmutableList<Pattern> maskRequestParameters = ImmutableList.of();
private static ImmutableList<Pattern> captureRequestHeaders = ImmutableList.of();
private static ImmutableList<Pattern> captureResponseHeaders = ImmutableList.of();
private static boolean captureResponseHeadersNonEmpty;
private static String sessionUserAttributePath = "";
private static boolean sessionUserAttributeIsId;
private static ImmutableSet<String> captureSessionAttributePaths = ImmutableSet.of();
private static ImmutableSet<String> captureSessionAttributeNames = ImmutableSet.of();
private static boolean captureSessionAttributeNamesContainsId;
static {
configService.registerConfigListener(new ServletPluginConfigListener());
}
private ServletPluginProperties() {}
static ImmutableList<Pattern> captureRequestParameters() {
return captureRequestParameters;
}
static ImmutableList<Pattern> maskRequestParameters() {
return maskRequestParameters;
}
static ImmutableList<Pattern> captureRequestHeaders() {
return captureRequestHeaders;
}
static ImmutableList<Pattern> captureResponseHeaders() {
return captureResponseHeaders;
}
static boolean captureResponseHeadersNonEmpty() {
return captureResponseHeadersNonEmpty;
}
static String sessionUserAttributePath() {
return sessionUserAttributePath;
}
static boolean sessionUserAttributeIsId() {
return sessionUserAttributeIsId;
}
static ImmutableSet<String> captureSessionAttributePaths() {
return captureSessionAttributePaths;
}
// only the first-level attribute names (e.g. "one", "abc") as opposed to full paths (e.g.
// "one.two", "abc.def") returned by captureSessionAttributePaths()
static ImmutableSet<String> captureSessionAttributeNames() {
return captureSessionAttributeNames;
}
static boolean captureSessionAttributeNamesContainsId() {
return captureSessionAttributeNamesContainsId;
}
private static class ServletPluginConfigListener implements ConfigListener {
@Override
public void onChange() {
recalculateProperties();
}
private static void recalculateProperties() {
captureRequestParameters = buildPatternList(CAPTURE_REQUEST_PARAMS_PROPERTY_NAME);
maskRequestParameters = buildPatternList(MASK_REQUEST_PARAMS_PROPERTY_NAME);
captureRequestHeaders = buildPatternList(CAPTURE_REQUEST_HEADER_PROPERTY_NAME);
captureResponseHeaders = buildPatternList(CAPTURE_RESPONSE_HEADER_PROPERTY_NAME);
captureResponseHeadersNonEmpty = !captureResponseHeaders.isEmpty();
sessionUserAttributePath = configService
.getStringProperty(SESSION_USER_ATTRIBUTE_PROPERTY_NAME).value();
sessionUserAttributeIsId = sessionUserAttributePath.equals(HTTP_SESSION_ID_ATTR);
String captureSessionAttributesText = configService
.getStringProperty(CAPTURE_SESSION_ATTRIBUTES_PROPERTY_NAME).value();
captureSessionAttributePaths =
ImmutableSet.copyOf(splitter.split(captureSessionAttributesText));
captureSessionAttributeNames = buildCaptureSessionAttributeNames();
captureSessionAttributeNamesContainsId =
captureSessionAttributeNames.contains(HTTP_SESSION_ID_ATTR);
}
private static ImmutableList<Pattern> buildPatternList(String propertyName) {
String captureRequestParametersText =
configService.getStringProperty(propertyName).value();
List<Pattern> captureParameters = Lists.newArrayList();
for (String parameter : splitter.split(captureRequestParametersText)) {
// converted to lower case for case-insensitive matching
captureParameters.add(buildRegexPattern(parameter.toLowerCase(Locale.ENGLISH)));
}
return ImmutableList.copyOf(captureParameters);
}
private static ImmutableSet<String> buildCaptureSessionAttributeNames() {
ImmutableSet.Builder<String> names = ImmutableSet.builder();
for (String captureSessionAttributePath : captureSessionAttributePaths) {
int index = captureSessionAttributePath.indexOf('.');
if (index == -1) {
names.add(captureSessionAttributePath);
} else {
names.add(captureSessionAttributePath.substring(0, index));
}
}
return names.build();
}
private static Pattern buildRegexPattern(String wildcardPattern) {
// convert * into .* and quote the rest of the text using \Q...\E
String regex = "\\Q" + wildcardPattern.replace("*", "\\E.*\\Q") + "\\E";
// strip off unnecessary \\Q\\E in case * appeared at beginning or end of part
regex = regex.replace("\\Q\\E", "");
return Pattern.compile(regex);
}
}
}