Java 解析原始HTTP请求

Java 解析原始HTTP请求,java,http-headers,Java,Http Headers,我正在研究HTTP流量数据集,它由完整的POST和GET请求组成,如下所示。我用java编写了代码,将每个请求分开,并将其保存为数组列表中的字符串元素。现在我不知道如何在java中解析这些原始HTTP请求,有什么方法比手动解析更好吗 我正在研究一个HTTP流量数据集,它由完整的POST和GET请求组成 因此,您需要解析包含多个HTTP请求的文件或列表。您要提取哪些数据?反正是一个JavaHTTP解析类,它可以读取请求行中使用的方法、版本和URI,并将所有头读入哈希表 如果你想重新发明轮子,你可以

我正在研究HTTP流量数据集,它由完整的POST和GET请求组成,如下所示。我用java编写了代码,将每个请求分开,并将其保存为数组列表中的字符串元素。现在我不知道如何在java中解析这些原始HTTP请求,有什么方法比手动解析更好吗

我正在研究一个HTTP流量数据集,它由完整的POST和GET请求组成

因此,您需要解析包含多个HTTP请求的文件或列表。您要提取哪些数据?反正是一个JavaHTTP解析类,它可以读取请求行中使用的方法、版本和URI,并将所有头读入哈希表

如果你想重新发明轮子,你可以用它或者自己写一个。查看以查看请求的外观,以便正确解析它:

Request       = Request-Line              ; Section 5.1
                    *(( general-header        ; Section 4.5
                     | request-header         ; Section 5.3
                     | entity-header ) CRLF)  ; Section 7.1
                    CRLF
                    [ message-body ]          ; Section 4.3

下面是一个通用Http请求解析器,用于所有方法类型(GET、POST等),以方便您使用:

    package util.dpi.capture;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Hashtable;

/**
 * Class for HTTP request parsing as defined by RFC 2612:
 * 
 * Request = Request-Line ; Section 5.1 (( general-header ; Section 4.5 |
 * request-header ; Section 5.3 | entity-header ) CRLF) ; Section 7.1 CRLF [
 * message-body ] ; Section 4.3
 * 
 * @author izelaya
 *
 */
public class HttpRequestParser {

    private String _requestLine;
    private Hashtable<String, String> _requestHeaders;
    private StringBuffer _messagetBody;

    public HttpRequestParser() {
        _requestHeaders = new Hashtable<String, String>();
        _messagetBody = new StringBuffer();
    }

    /**
     * Parse and HTTP request.
     * 
     * @param request
     *            String holding http request.
     * @throws IOException
     *             If an I/O error occurs reading the input stream.
     * @throws HttpFormatException
     *             If HTTP Request is malformed
     */
    public void parseRequest(String request) throws IOException, HttpFormatException {
        BufferedReader reader = new BufferedReader(new StringReader(request));

        setRequestLine(reader.readLine()); // Request-Line ; Section 5.1

        String header = reader.readLine();
        while (header.length() > 0) {
            appendHeaderParameter(header);
            header = reader.readLine();
        }

        String bodyLine = reader.readLine();
        while (bodyLine != null) {
            appendMessageBody(bodyLine);
            bodyLine = reader.readLine();
        }

    }

    /**
     * 
     * 5.1 Request-Line The Request-Line begins with a method token, followed by
     * the Request-URI and the protocol version, and ending with CRLF. The
     * elements are separated by SP characters. No CR or LF is allowed except in
     * the final CRLF sequence.
     * 
     * @return String with Request-Line
     */
    public String getRequestLine() {
        return _requestLine;
    }

    private void setRequestLine(String requestLine) throws HttpFormatException {
        if (requestLine == null || requestLine.length() == 0) {
            throw new HttpFormatException("Invalid Request-Line: " + requestLine);
        }
        _requestLine = requestLine;
    }

    private void appendHeaderParameter(String header) throws HttpFormatException {
        int idx = header.indexOf(":");
        if (idx == -1) {
            throw new HttpFormatException("Invalid Header Parameter: " + header);
        }
        _requestHeaders.put(header.substring(0, idx), header.substring(idx + 1, header.length()));
    }

    /**
     * The message-body (if any) of an HTTP message is used to carry the
     * entity-body associated with the request or response. The message-body
     * differs from the entity-body only when a transfer-coding has been
     * applied, as indicated by the Transfer-Encoding header field (section
     * 14.41).
     * @return String with message-body
     */
    public String getMessageBody() {
        return _messagetBody.toString();
    }

    private void appendMessageBody(String bodyLine) {
        _messagetBody.append(bodyLine).append("\r\n");
    }

    /**
     * For list of available headers refer to sections: 4.5, 5.3, 7.1 of RFC 2616
     * @param headerName Name of header
     * @return String with the value of the header or null if not found.
     */
    public String getHeaderParam(String headerName){
        return _requestHeaders.get(headerName);
    }
}
package util.dpi.capture;
导入java.io.BufferedReader;
导入java.io.IOException;
导入java.io.StringReader;
导入java.util.Hashtable;
/**
*用于RFC 2612定义的HTTP请求解析的类:
* 
*请求=请求行;第5.1节((一般标题;第4.5节|
*请求标头;第5.3节(实体标头)CRLF);第7.1节CRLF[
*信息正文];第4.3节
* 
*@作者伊泽拉亚
*
*/
公共类HttpRequestParser{
私有字符串_requestLine;
私有哈希表_requestHeaders;
私有StringBuffer_messagebody;
公共HttpRequestParser(){
_requestHeaders=新哈希表();
_messagetBody=newstringbuffer();
}
/**
*解析和HTTP请求。
* 
*@param请求
*包含http请求的字符串。
*@抛出异常
*如果读取输入流时发生I/O错误。
*@抛出HttpFormatException
*如果HTTP请求格式不正确
*/
public void parseRequest(字符串请求)引发IOException、HttpFormatException{
BufferedReader reader=新BufferedReader(新StringReader(请求));
setRequestLine(reader.readLine());//请求行;第5.1节
字符串头=reader.readLine();
while(header.length()>0){
附录标题参数(标题);
header=reader.readLine();
}
字符串bodyLine=reader.readLine();
while(bodyLine!=null){
车身(车身线);
bodyLine=reader.readLine();
}
}
/**
* 
*5.1请求行请求行以方法令牌开头,后跟
*请求URI和协议版本,并以CRLF结尾
*元素由SP字符分隔。除中之外,不允许使用CR或LF
*最后的CRLF序列。
* 
*@带请求行的返回字符串
*/
公共字符串getRequestLine(){
返回请求行;
}
私有void setRequestLine(字符串requestLine)引发HttpFormatException{
if(requestLine==null | | requestLine.length()==0){
抛出新的HttpFormatException(“无效请求行:+requestLine”);
}
_requestLine=requestLine;
}
私有void appendHeaderParameter(字符串头)引发HttpFormatException{
int idx=header.indexOf(“:”);
如果(idx==-1){
抛出新的HttpFormatException(“无效的标头参数:“+标头”);
}
_requestHeaders.put(header.substring(0,idx),header.substring(idx+1,header.length());
}
/**
*HTTP消息的消息体(如果有)用于承载
*与请求或响应关联的实体正文。消息正文
*仅当传输编码已更改时,才与实体体不同
*已应用,如传输编码标题字段(第节)所示
* 14.41).
*@返回消息体字符串
*/
公共字符串getMessageBody(){
return_messagetBody.toString();
}
私有void appendMessageBody(字符串bodyLine){
_messagetBody.append(bodyLine.append(“\r\n”);
}
/**
*有关可用标题的列表,请参阅RFC 2616第4.5、5.3和7.1节
*@param headerName标头的名称
*@返回带有标头值的字符串,如果找不到则返回null。
*/
公共字符串getHeaderParam(字符串头名称){
return _requestHeaders.get(headerName);
}
}

如果您只想按原样发送原始请求,很简单,只需使用TCP套接字发送实际字符串即可

大概是这样的:

    Socket socket = new Socket(host, port);

    BufferedWriter out = new BufferedWriter(
            new OutputStreamWriter(socket.getOutputStream(), "UTF8"));

    for (String line : getContents(request)) {
        System.out.println(line);
        out.write(line + "\r\n");
    }

    out.write("\r\n");
    out.flush();
请参阅JoeJag提供的完整代码

更新


我启动了一个项目,为请求、响应、标题等提供HTTP解析器。。。结果证明,它非常好,使得在上面编写HTTP服务器和客户端非常容易。如果您正在寻找较低级别的内容,请查看它。

您需要在哪里解析这些内容?在Servlet或类似技术(或)普通Java类中?数据来自哪里?您需要解析什么呢?如果您绝对必须直接执行HTTP,而这不是针对类,我强烈建议您使用ApacheCommonsHttpClient之类的工具。自己做这件事有很多陷阱。(例如分块传输编码)@AliAhmad-你到底想完成什么?如果您使用的是HttpClient类,则不需要手动解析HTTP数据流。您已经询问了如何解析HTTP,但这可能意味着很多事情,具体取决于您试图从原始流中提取的内容。如果不说明你的最终目标,这个问题就近乎于“没有建设性”。
    Socket socket = new Socket(host, port);

    BufferedWriter out = new BufferedWriter(
            new OutputStreamWriter(socket.getOutputStream(), "UTF8"));

    for (String line : getContents(request)) {
        System.out.println(line);
        out.write(line + "\r\n");
    }

    out.write("\r\n");
    out.flush();