All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.instrumentation.servlet.DetailCapture Maven / Gradle / Ivy

There is a newer version: 0.14.9
Show newest version
/*
 * Copyright 2014-2019 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.instrumentation.servlet;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.glowroot.instrumentation.api.checker.Nullable;
import org.glowroot.instrumentation.api.util.ImmutableList;
import org.glowroot.instrumentation.api.util.ImmutableMap;
import org.glowroot.instrumentation.servlet.boot.Patterns;
import org.glowroot.instrumentation.servlet.boot.RequestHostAndPortDetail;
import org.glowroot.instrumentation.servlet.boot.RequestInvoker;
import org.glowroot.instrumentation.servlet.boot.ServletInstrumentationProperties;
import org.glowroot.instrumentation.servlet.boot.Strings;

// shallow copies are necessary because request may not be thread safe, which may affect ability
// to see detail from active traces
//
// shallow copies are also necessary because servlet container may clear out the objects after the
// request is complete (e.g. tomcat does this) in order to reuse them, in which case this detail
// would need to be captured synchronously at end of request anyways (although then it could be
// captured only if trace met threshold for storage...)
public class DetailCapture {

    private DetailCapture() {}

    static Map captureRequestParameters(
            Map requestParameters) {
        List capturePatterns = ServletInstrumentationProperties.captureRequestParameters();
        Map map = new HashMap();
        for (Map.Entry entry : requestParameters.entrySet()) {
            String name = entry.getKey();
            if (name == null) {
                continue;
            }
            // converted to lower case for case-insensitive matching (patterns are lower case)
            String keyLowerCase = name.toLowerCase(Locale.ENGLISH);
            if (!Patterns.matchesOneOf(keyLowerCase, capturePatterns)) {
                continue;
            }
            Object value = entry.getValue();
            if (value instanceof String[]) {
                set(map, name, (String[]) value);
            }
        }
        return ImmutableMap.copyOf(map);
    }

    static Map captureRequestParameters(HttpServletRequest request) {
        Enumeration e = request.getParameterNames();
        if (e == null) {
            return Collections.emptyMap();
        }
        List capturePatterns = ServletInstrumentationProperties.captureRequestParameters();
        List maskPatterns = ServletInstrumentationProperties.maskRequestParameters();
        Map map = new HashMap();
        while (e.hasMoreElements()) {
            Object nameObj = e.nextElement();
            if (nameObj == null) {
                continue;
            }
            if (!(nameObj instanceof String)) {
                continue;
            }
            String name = (String) nameObj;
            // converted to lower case for case-insensitive matching (patterns are lower case)
            String keyLowerCase = name.toLowerCase(Locale.ENGLISH);
            if (!Patterns.matchesOneOf(keyLowerCase, capturePatterns)) {
                continue;
            }
            if (Patterns.matchesOneOf(keyLowerCase, maskPatterns)) {
                map.put(name, "****");
                continue;
            }
            @Nullable
            String[] values = request.getParameterValues(name);
            if (values != null) {
                set(map, name, values);
            }
        }
        return ImmutableMap.copyOf(map);
    }

    static Map captureRequestHeaders(HttpServletRequest request) {
        List capturePatterns = ServletInstrumentationProperties.captureRequestHeaders();
        if (capturePatterns.isEmpty()) {
            return Collections.emptyMap();
        }
        Map requestHeaders = new HashMap();
        Enumeration headerNames = request.getHeaderNames();
        if (headerNames == null) {
            return Collections.emptyMap();
        }
        for (Enumeration e = headerNames; e.hasMoreElements();) {
            String name = e.nextElement();
            if (name == null) {
                continue;
            }
            // converted to lower case for case-insensitive matching (patterns are lower case)
            String keyLowerCase = name.toLowerCase(Locale.ENGLISH);
            if (!Patterns.matchesOneOf(keyLowerCase, capturePatterns)) {
                continue;
            }
            Enumeration values = request.getHeaders(name);
            if (values != null) {
                captureRequestHeader(name, values, requestHeaders);
            }
        }
        return ImmutableMap.copyOf(requestHeaders);
    }

    static Map captureRequestCookies(HttpServletRequest request) {
        List capturePatterns = ServletInstrumentationProperties.captureRequestCookies();
        if (capturePatterns.isEmpty()) {
            return Collections.emptyMap();
        }
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            return Collections.emptyMap();
        }
        Map requestCookies = new HashMap();
        for (Cookie cookie : cookies) {
            String name = cookie.getName();
            if (name == null) {
                continue;
            }
            // cookie names are case sensitive
            if (!Patterns.matchesOneOf(name, capturePatterns)) {
                continue;
            }
            System.out.println(name);
            requestCookies.put(name, cookie.getValue());
        }
        return ImmutableMap.copyOf(requestCookies);
    }

    static @Nullable RequestHostAndPortDetail captureRequestHostAndPortDetail(
            HttpServletRequest request, RequestInvoker requestInvoker) {
        if (ServletInstrumentationProperties.captureSomeRequestHostAndPortDetail()) {
            RequestHostAndPortDetail requestHostAndPortDetail = new RequestHostAndPortDetail();
            if (ServletInstrumentationProperties.captureRequestRemoteAddress()) {
                requestHostAndPortDetail.remoteAddress = request.getRemoteAddr();
            }
            if (ServletInstrumentationProperties.captureRequestRemoteHostname()) {
                requestHostAndPortDetail.remoteHostname = request.getRemoteHost();
            }
            if (ServletInstrumentationProperties.captureRequestRemotePort()) {
                requestHostAndPortDetail.remotePort = requestInvoker.getRemotePort(request);
            }
            if (ServletInstrumentationProperties.captureRequestLocalAddress()) {
                requestHostAndPortDetail.localAddress = requestInvoker.getLocalAddr(request);
            }
            if (ServletInstrumentationProperties.captureRequestLocalHostname()) {
                requestHostAndPortDetail.localHostname = requestInvoker.getLocalName(request);
            }
            if (ServletInstrumentationProperties.captureRequestLocalPort()) {
                requestHostAndPortDetail.localPort = requestInvoker.getLocalPort(request);
            }
            if (ServletInstrumentationProperties.captureRequestServerHostname()) {
                requestHostAndPortDetail.serverHostname = request.getServerName();
            }
            if (ServletInstrumentationProperties.captureRequestServerPort()) {
                requestHostAndPortDetail.serverPort = request.getServerPort();
            }
            if (ServletInstrumentationProperties.captureRequestScheme()) {
                requestHostAndPortDetail.scheme = request.getScheme();
            }
            return requestHostAndPortDetail;
        } else {
            // optimized for common case
            return null;
        }
    }

    private static void set(Map map, String name, /*@Nullable*/ String[] values) {
        if (values.length == 1) {
            String value = values[0];
            if (value != null) {
                map.put(name, value);
            }
        } else {
            List list =
                    new ArrayList(values.length);
            Collections.addAll(list, values);
            map.put(name, list);
        }
    }

    private static void captureRequestHeader(String name, Enumeration values,
            Map requestHeaders) {
        if (!values.hasMoreElements()) {
            requestHeaders.put(name, "");
        } else {
            String value = values.nextElement();
            if (!values.hasMoreElements()) {
                requestHeaders.put(name, Strings.nullToEmpty(value));
            } else {
                List list = new ArrayList();
                list.add(Strings.nullToEmpty(value));
                while (values.hasMoreElements()) {
                    list.add(Strings.nullToEmpty(values.nextElement()));
                }
                requestHeaders.put(name, ImmutableList.copyOf(list));
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy