基于Idea构建Tomcat源码及问题解决

1.前言

最近在项目中有一个想法,要是项目中能通过网页热部署一些二次开发的模块,那应该是一件很有意思而且很有实际作用的功能。所以想到了Tomcat中类加载器中反委派机制做法。为了更深入了解tomcat类加载器的反委派机制的具体实现,需要搭建Tomcat源码环境。虽然不是很难,但是还有避免不了一些坑,依次记载,方便大家学习交流。

2.环境准备

2.1 Idea环境

本次Idea版本采用比较稳定的IntelliJIDEA2018.2.1。

2.2 JDK版本

JDK版本为1.8.0.131_x64。

2.3 Tomcat版本

本次tomcat版本采用tomcat7.0.103。可以通过在官网下载。注意,此处应该选择Source Code Distributions。下载的格式为zip。

https://tomcat.apache.org/download-70.cgi

3.源码部署

3.1 解压zip压缩包,此处简单,一句带过。

3.2 通过idea导入此项目

依次选择【Open -->选择刚才解压的文件夹】。

3.3 指定jdk,工程语言级别以及编译输出路径

3.4 指定src以及test路径

将java指定为【Sources Root】,将test指定为【Test Sources Root】,具体操作如下:

3.5 引入Jar包

此时,我们发现有部分代码飘红,说明需要引入部分jar包,如下图。

为了方便大家构建项目,这里我们通过maven将依赖的jar包引导到工程中去。下文是我整理好的pom.xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.surpass</groupId>
    <artifactId>tomcat</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>tomcat</name>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.10.7</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jdt</groupId>
            <artifactId>org.eclipse.jdt.core</artifactId>
            <version>3.20.0</version>
        </dependency>
        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.3</version>
        </dependency>

        <dependency>
            <groupId>javax.xml</groupId>
            <artifactId>jaxrpc</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>jmock</groupId>
            <artifactId>jmock</artifactId>
            <version>1.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.jmock</groupId>
            <artifactId>jmock</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.easymock</groupId>
            <artifactId>easymock</artifactId>
            <version>4.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jdt.core.compiler</groupId>
            <artifactId>ecj</artifactId>
            <version>4.4.2</version>
        </dependency>
    </dependencies>
</project>

3.5.1 将pom.xml文件拷贝到tomcat的文件夹下。

3.5.2 编程maven工程,引入pom.xml文件

选择idea右侧的选项卡【Maven Projects】,然后点击【+】,现在刚才拷贝进去的pom.xml文件,在弹出的点击【import changes】,此操作对于熟悉idea的读者并不陌生,可以直接略过。

此时,我们发现之前飘红的已经消失了。

3.6 运行tomcat启动文件

我们通过路径找到类文件org.apache.catalina.startup.Bootstrap。熟悉idea的朋友知道,双击shift键,输入Bootstrap可以快速定位。接下来我们运行此类。很不幸,发现缺少一个类。

通过此类分析,这个类并没有在import导入,所以我们猜想这个CookieFilter类应该和TestCookieFilter在同一个全类路径,即在util包下。为了方便大家学习,我也把这个文件分享出来,然后把此类放到${tomcat}\test\util下。

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 util;

import java.util.Locale;
import java.util.StringTokenizer;

/**
 * Processes a cookie header and attempts to obfuscate any cookie values that
 * represent session IDs from other web applications. Since session cookie names
 * are configurable, as are session ID lengths, this filter is not expected to
 * be 100% effective.
 *
 * It is required that the examples web application is removed in security
 * conscious environments as documented in the Security How-To. This filter is
 * intended to reduce the impact of failing to follow that advice. A failure by
 * this filter to obfuscate a session ID or similar value is not a security
 * vulnerability. In such instances the vulnerability is the failure to remove
 * the examples web application.
 */
public class CookieFilter {

    private static final String OBFUSCATED = "[obfuscated]";

    private CookieFilter() {
        // Hide default constructor
    }

    public static String filter(String cookieHeader, String sessionId) {

        StringBuilder sb = new StringBuilder(cookieHeader.length());

        // Cookie name value pairs are ';' separated.
        // Session IDs don't use ; in the value so don't worry about quoted
        // values that contain ;
        StringTokenizer st = new StringTokenizer(cookieHeader, ";");

        boolean first = true;
        while (st.hasMoreTokens()) {
            if (first) {
                first = false;
            } else {
                sb.append(';');
            }
            sb.append(filterNameValuePair(st.nextToken(), sessionId));
        }


        return sb.toString();
    }

    private static String filterNameValuePair(String input, String sessionId) {
        int i = input.indexOf('=');
        if (i == -1) {
            return input;
        }
        String name = input.substring(0, i);
        String value = input.substring(i + 1, input.length());

        return name + "=" + filter(name, value, sessionId);
    }

    public static String filter(String cookieName, String cookieValue, String sessionId) {
        if (cookieName.toLowerCase(Locale.ENGLISH).contains("jsessionid") &&
                (sessionId == null || !cookieValue.contains(sessionId))) {
            cookieValue = OBFUSCATED;
        }

        return cookieValue;
    }
}

3.7 运行tomcat启动文件

此时我们在运行此类,发现运行成功。随后我们在网页打开http://127.0.0.1:8080验证是否启动成功。

4 修改乱码

不知道上面读者是否发现在输出日志的控制台中发生了乱码。

其实解决问题的思路很简单,我们需要修改两个类。

4.1 org.apache.tomcat.util.res.StringManager

代码如插入位置如下图

try{
    value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
}catch (Exception e){}

4.2 org.apache.jasper.compiler.Localizer

代码如插入位置如下图

try{
    errMsg = new String(errMsg.getBytes("ISO-8859-1"),"UTF-8");
}catch (Exception e){}

4.3 此时我们再次运行,发现乱码不见了。

发布了88 篇原创文章 · 获赞 97 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/oYinHeZhiGuang/article/details/105057540