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

org.javaweb.net.HttpResponseParser Maven / Gradle / Ivy

There is a newer version: 2.0.3
Show newest version
/*
 * Copyright yz 2016-01-14  Email:[email protected].
 *
 * 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.javaweb.net;

import org.apache.commons.collections.map.CaseInsensitiveMap;
import org.javaweb.utils.IOUtils;
import org.javaweb.utils.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.DeflaterInputStream;
import java.util.zip.GZIPInputStream;

/**
 * Http响应解析器
 * Created by yz on 2017/1/5.
 */
public class HttpResponseParser {

	/**
	 * 最大允许读取的Header长度
	 */
	private static final int MAX_HEADER_LENGTH = 1024 * 1000 * 4;

	private static Pattern responsePattern = Pattern.compile("^(HTTP/\\d\\.\\d) (\\d{3}) (.*)$");

	/**
	 * Http版本号
	 */
	private String httpVersion;

	/**
	 * Http响应状态码
	 */
	private int httpStatus = -1;

	/**
	 * Http响应状态消息
	 */
	private String httpStatusInfo;

	/**
	 * Http响应状态Map
	 */
	private Map headerMap = new CaseInsensitiveMap();

	/**
	 * Http响应状态字符串
	 */
	private String header;

	/**
	 * 响应流
	 */
	private DataInputStream dis;

	/**
	 * 解析的主体输入流
	 */
	private InputStream httpBodyInputStream;

	public HttpResponseParser(InputStream in) {
		this.dis = new DataInputStream(in);
		parse();
	}

	/**
	 * 获取最大允许接收的Http响应头长度
	 *
	 * @return
	 */
	public static int getMaxHeaderLength() {
		return MAX_HEADER_LENGTH;
	}

	/**
	 * 获取Http版本号
	 *
	 * @return
	 */
	public String getHttpVersion() {
		return httpVersion;
	}

	/**
	 * 获取Http响应状态码
	 *
	 * @return
	 */
	public int getHttpStatus() {
		return httpStatus;
	}

	/**
	 * Http响应状态消息
	 *
	 * @return
	 */
	public String getHttpStatusInfo() {
		return httpStatusInfo;
	}

	/**
	 * 获取Http响应状态Map
	 *
	 * @return
	 */
	public Map getHeaderMap() {
		return headerMap;
	}

	/**
	 * 获取Http响应状态字符串
	 *
	 * @return
	 */
	public String getHeader() {
		return header;
	}

	/**
	 * 获取Http响应正文输入流
	 *
	 * @return
	 */
	public InputStream getHttpBodyInputStream() {
		return httpBodyInputStream;
	}

	/**
	 * 解析请求响应内容
	 */
	private void parse() {
		try {
			parseHttpResponseHeaderString();
			parseHttpResponseStatus();
			parseHttpResponseHeaderMap();
			parseHttpResponseBodyInputStream();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 解析Http响应头为字符串
	 *
	 * @throws IOException
	 */
	private void parseHttpResponseHeaderString() {
		boolean       loop = true;
		int           a    = 0;
		StringBuilder sb   = new StringBuilder();
		try {
			String str = null;
			while (loop && (str = dis.readLine()) != null) {
				a += str.length();// 不计换行符长度

				if (a > MAX_HEADER_LENGTH) {
					loop = false;
				} else {
					if (str.length() == 0) {
						loop = false;
					} else {
						sb.append(str).append("\n");
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		this.header = sb.toString();
	}

	/**
	 * 解析Http响应头为Map
	 *
	 * @throws IOException
	 */
	private void parseHttpResponseHeaderMap() throws IOException {
		if (StringUtils.isNotEmpty(this.header)) {
			BufferedReader br = null;

			try {
				String str = null;
				br = new BufferedReader(new StringReader(this.header));

				while ((str = br.readLine()) != null) {
					int i = str.indexOf(":");

					if (i != -1) {
						String key   = i > 0 ? str.substring(0, i) : "";
						String value = str.length() - 1 > i ? str.substring(i + 1).trim() : "";

						if (!headerMap.containsKey(key)) {
							headerMap.put(key, value);
						} else {
							Object obj = headerMap.get(key);

							if (obj instanceof String) {
								headerMap.put(key, new String[]{(String) obj, value});
							} else {
								List list = new ArrayList();
								list.addAll(Arrays.asList((String[]) obj));
								list.add(value);
								headerMap.put(key, list.toArray(new String[list.size()]));
							}
						}
					}
				}
			} catch (IOException e) {
				throw e;
			} finally {
				IOUtils.closeQuietly(br);
			}
		}
	}

	/**
	 * 解析Http响应状态码
	 *
	 * @throws IOException
	 */
	private void parseHttpResponseStatus() throws IOException {
		try {
			if (StringUtils.isNotEmpty(this.header)) {
				StringReader sr                 = new StringReader(this.header);
				String       responseStatusLine = new BufferedReader(sr).readLine();

				if (StringUtils.isNotEmpty(responseStatusLine)) {
					Matcher m = responsePattern.matcher(responseStatusLine);

					if (m.find() && m.groupCount() == 3) {
						this.httpVersion = m.group(1);
						this.httpStatus = StringUtils.isNum(m.group(2)) ? Integer.parseInt(m.group(2)) : -1;
						this.httpStatusInfo = m.group(3);
					}
				}
			}
		} catch (IOException e) {
			throw e;
		}
	}

	/**
	 * 解析Http响应流 如果响应头中包含了Transfer-Encoding 和 Content-Encoding 尝试解chunked和压缩流
	 *
	 * @throws IOException
	 */
	private void parseHttpResponseBodyInputStream() throws IOException {
		InputStream bodyInputStream = null;

		// 解析chunked
		if (this.headerMap.containsKey("Transfer-Encoding")) {
			String transferEncoding = (String) this.headerMap.get("Transfer-Encoding");

			if (StringUtils.isNotEmpty(transferEncoding) && "chunked".equalsIgnoreCase(transferEncoding)) {
				bodyInputStream = new ChunkedInputStream(dis);
			} else {
				bodyInputStream = dis;
			}
		} else {
			bodyInputStream = dis;
		}

		// 解析gzip和deflate
		if (this.headerMap.containsKey("Content-Encoding")) {
			String      contentEncoding     = (String) this.headerMap.get("Content-Encoding");
			InputStream compressInputStream = null;

			try {
				if ("gzip".equalsIgnoreCase(contentEncoding)) {
					compressInputStream = new GZIPInputStream(bodyInputStream);
				} else if ("deflate".equalsIgnoreCase(contentEncoding)) {
					compressInputStream = new DeflaterInputStream(bodyInputStream);
				}
			} catch (IOException e) {
				throw e;
			}

			if (compressInputStream != null) {
				bodyInputStream = compressInputStream;
			}
		}

		this.httpBodyInputStream = bodyInputStream;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy