大飞带你深入Tomcat(五)

本文介绍了一个基于HTTP协议的请求头解析方法,通过自定义HttpHeader类处理请求头数据,并详细展示了如何通过SocketInputStream读取和解析请求头。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

接上篇, 上篇讲到解析请求行,这篇来讲下,请求头的处理, 基于http协议的请求头格式key:value形式存在,再解析时可以以:为分隔点, 左边为name, 右边value,循环,一行一行解析:
新增类:HttpHeader

package com.wolfcode._02_2_tomcat.http;

public class HttpHeader {

    public static final int INITIAL_NAME_SIZE = 32;
    public static final int INITIAL_VALUE_SIZE = 64;
    public static final int MAX_NAME_SIZE = 128;
    public static final int MAX_VALUE_SIZE = 4096;

    public char[] name;
    public int nameEnd;
    public char[] value;
    public int valueEnd;
    protected int hashCode = 0;

    public HttpHeader() {
        this(new char[INITIAL_NAME_SIZE], 0, new char[INITIAL_VALUE_SIZE], 0);
    }

    public HttpHeader(char[] name, int nameEnd, char[] value, int valueEnd) {
        this.name = name;
        this.nameEnd = nameEnd;
        this.value = value;
        this.valueEnd = valueEnd;
    }

    public HttpHeader(String name, String value) {
        this.name = name.toLowerCase().toCharArray();
        this.nameEnd = name.length();
        this.value = value.toCharArray();
        this.valueEnd = value.length();
    }

    public void recycle() {

        nameEnd = 0;
        valueEnd = 0;
        hashCode = 0;

    }
}

修改类:SocketInputStream
添加类解析请求头的方法

/**
     * 读请求头
     * 
     * @param header
     */
    public void readHeader(HttpHeader header) throws IOException {
        if (header.nameEnd != 0) {
            header.recycle();
        }

        int chr = read();
        if (chr == '\r' || chr == '\n') {
            header.nameEnd = 0;
            header.valueEnd = 0;
            return;
        } else {
            pos--; // 退一位操作
        }

        int maxRead = header.name.length;
        int readStart = pos;
        int readCount = 0;
        boolean colon = false;
        while (!colon) {
            if (readCount >= maxRead) {
                if ((2 * maxRead) <= HttpHeader.MAX_NAME_SIZE) {
                    char[] newBuffer = new char[2 * maxRead];
                    System.arraycopy(header.name, 0, newBuffer, 0, maxRead);
                    header.name = newBuffer;
                    maxRead = header.name.length;
                } else {
                    throw new RuntimeException("读请求头数据出错");
                }
            }

            if (pos >= count) {
                int val = read();
                if (val == -1) {
                    throw new RuntimeException("读请求头数据出错");
                }
                pos = 0;
                readStart = 0;
            }

            if (buf[pos] == ':') {
                colon = true;
            }

            char val = (char) buf[pos];
            if ((val >= 'A') && (val <= 'Z')) {
                // 大写转小写
                val = (char) (val + 32);
            }
            // 请求头的key值
            header.name[readCount] = val;
            readCount++;
            pos++;
        }
        header.nameEnd = readCount - 1;

        maxRead = header.value.length;
        readStart = pos;
        readCount = 0;

        boolean eol = false;
        boolean validLine = true;

        while (validLine) {
            boolean space = true;
            while (space) {
                if (pos >= count) {
                    int val = read();
                    if (val == -1)
                        throw new RuntimeException("读请求头数据出错");
                    pos = 0;
                    readStart = 0;
                }

                // 去掉:后面的空格
                if (buf[pos] == ' ') {
                    pos++;
                } else {
                    space = false;
                }
            }

            while (!eol) {
                if (readCount >= maxRead) {
                    if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) {
                        char[] newBuffer = new char[2 * maxRead];
                        System.arraycopy(header.value, 0, newBuffer, 0, maxRead);
                        header.value = newBuffer;
                        maxRead = header.value.length;
                    } else {
                        throw new RuntimeException("读请求头数据出错");
                    }
                }
                if (pos >= count) {
                    int val = read();
                    if (val == -1)
                        throw new RuntimeException("读请求头数据出错");
                    pos = 0;
                    readStart = 0;
                }
                if (buf[pos] == '\r') {
                } else if (buf[pos] == '\n') {
                    eol = true;
                } else {
                    int ch = buf[pos] & 0xff;
                    header.value[readCount] = (char) ch;
                    readCount++;
                }
                pos++;
            }
            int nextChr = read();

            //下一个请求头
            if ((nextChr != ' ') && (nextChr != '\t')) {
                pos--;
                validLine = false;
            } else {
                eol = false;
                if (readCount >= maxRead) {
                    if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) {
                        char[] newBuffer = new char[2 * maxRead];
                        System.arraycopy(header.value, 0, newBuffer, 0,
                                         maxRead);
                        header.value = newBuffer;
                        maxRead = header.value.length;
                    } else {
                        throw new RuntimeException("读请求头数据出错");
                    }
                }
                header.value[readCount] = ' ';
                readCount++;
            }
        }
         header.valueEnd = readCount;
    }

修改类:HttpServer
添加了解析请求头的方法

/**
     * 解析请求头信息
     * 
     * @param input
     */
    private void parseHeaders(SocketInputStream input) throws IOException {
        while (true) {
            HttpHeader header = new HttpHeader();
            input.readHeader(header);
            if (header.nameEnd == 0) {
                if (header.valueEnd == 0) {
                    return;
                } else {
                    throw new RuntimeException("解析请求头报错");
                }
            }

            String name = new String(header.name, 0, header.nameEnd);
            String value = new String(header.value, 0, header.valueEnd);
            request.addHeader(name, value);
            if (name.equals("content-length")) {
                int n = -1;
                try {
                    n = Integer.parseInt(value);
                } catch (Exception e) {
                    throw new RuntimeException("解析请求头报错");
                }
                request.setContentLength(n);
            } else if (name.equals("content-type")) {
                request.setContentType(value);
            }
        }
    }

修改类:Reqeust
添加一个map接收header数据

    public void addHeader(String name, String value) {
        name = name.toLowerCase();
        synchronized (headers) {
            if (value != null) {
                headers.put(name, value);
            }
        }
    }

好到这,本篇内容结束。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值