package com.zhw.myserver;
/**
* 请求报文解析
* @author 邹鸿威
*
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
public class RequestParse {
private InputStream in;
private Request rq = new Request();
private int offset=0;//解析请求头时剩下的字节数
private ByteArrayOutputStream requestbody = new ByteArrayOutputStream();//请求体
public RequestParse(InputStream in){
this.in = in;
}
public Request parse() throws IOException {
parse(in);
return rq;
}
/**
*面向过程解析请求报文。
* 请求行 + 头部 + 空行 + 请求体
*
* @return
* @throws IOException
*/
private void parse(InputStream in) throws IOException {
byte []bs = new byte[1024];
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte []spdata = "\r\n\r\n".getBytes();
byte []src = null;
int index = 0 ;
String headers = null;
while(true) {
int num = in.read(bs);
bout.write(bs, 0, num);
src = bout.toByteArray();
index = findArray(src,spdata);
if(index != -1) {
headers = new String(src,0,index);
offset = src.length-index-4;
break;
}
}
//分离请求行和请求头
int headindex = headers.indexOf("\r\n");
parseline(headers.substring(0,headindex));
parseheaders(headers.substring(headindex+2,headers.length()));
//读取响应体
if(offset >= 0 && rq.getContentlength() > 0) {
requestbody.write(src,index+4,offset);
parsebody();
}
parseuri();
}
/**
* 解析uri中的参数
*/
private void parseuri() {
//先判断请求方式是post还是get
if(rq.getMethod().equalsIgnoreCase("GET")) {
//参数位于URI。以?作为分隔符,分割URL和参数部分即可。
int index = rq.getUri().indexOf("?");
if(index != -1) {
//有参数
String url = rq.getUri().substring(0, index);
String parameter = rq.getUri().substring(index+1, rq.getUri().length());
rq.setUri(url);
parseParameters(parameter);
}
}else if(rq.getMethod().equalsIgnoreCase("POST")) {
//参数位于请求体 但请求体不一定是参数 但是如果有参数一定在请求体中
if(rq.getContenttype().contains("application/x-www-form-urlencoded")) {
//表明是表单提交,直接读取请求体
String parameter = new String(rq.getRequestbody());
parseParameters(parameter);
}else if(rq.getContenttype().contains("multipart/form-data")) {
//文件上传
}
}
}
/**
* 此处传入的参数是key=v1&k=v2格式。并且经过了url编码。
* @param paramstr
*/
private void parseParameters(String paramstr) {
try {
paramstr = URLDecoder.decode(paramstr, "UTF-8");
//username=%E5%BC%A0%E4%B8%89&password=%E6%9D%8E%E5%9B%9Blisi
//分离参数。使用Map<String,String>
Map<String,String> parameters = new HashMap<String,String>();
StringTokenizer stk = new StringTokenizer(paramstr, "&");
while( stk.hasMoreTokens() ) {
String kvs = stk.nextToken();//key=vaule
String []kv = kvs.split("=");
String k = kv[0];
String v = kv[1];
parameters.put(k, v);
}
rq.setLineparameter( parameters );
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* 读取剩下的请求体
* @throws IOException
*/
private void parsebody() throws IOException {
byte []bs = new byte[rq.getContentlength()-offset];
int num = in.read(bs);
requestbody.write(bs,0,num);
rq.setRequestbody(requestbody.toByteArray());
in.close();
}
/**
* 解析请求行
*/
private void parseline(String line) {
StringTokenizer st = new StringTokenizer(line);
rq.setMethod(st.nextToken());//请求方式
rq.setUri(st.nextToken());//uri 可能存在参数
}
/**
* 解析请求头
*/
private void parseheaders(String header) {
StringTokenizer st = new StringTokenizer(header,"\r\n");
Map<String,List<String>> headparameter = new HashMap<String,List<String >>();
while(st.hasMoreTokens()) {
String dataline = st.nextToken();
//直接分离key 和 values 例如:host: localhost : 8080
// String []str = dataline.split(":");
// String key = str[0].trim();
// String values = str[1].trim();
//找到第一个“:” 分离
int ind = dataline.indexOf(":");
String key = dataline.substring(0,ind).trim();
String value = dataline.substring(ind+1,dataline.length()).trim();
//先根据k获取出value。如果value为null。
//之前没有放入过该key,需要创建一个List<String>
//否则直接放入。先不对values进行切割
List<String> values = headparameter.get(key);
if( values == null ) {
values = new ArrayList<String>();
headparameter.put(key, values);
}
values.add(value);
}
rq.setHeadparameter(headparameter);
//将常用参数设置
if(headparameter.get("Content-Type") != null) {
rq.setContenttype(headparameter.get("Content-Type").get(0));
}
if(headparameter.get("Content-Length") != null) {
rq.setContentlength(Integer.parseInt(headparameter.get("Content-Length").get(0)));
}
}
/**
* 查找一个字节数组在另外一个大字节数组的位置
* @param src
* @param data
* @return
*/
private int findArray(byte []src,byte []data) {
if(src.length>data.length) {
int num = 0;//
for(int i = 0;i<src.length-data.length+1;i++) {
for(int j = 0;j<data.length;j++) {
if(data[j] == src[i+j]) {
num++;
}else break;
if(num == data.length) {
return i;
}
}
}
return -1;
}else return -1;
}
}