基於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 此時我們再次運行,發現亂碼不見了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章