自己做个HttpDump。
用料好简单,WinPcap + Jpcap (小心,Jpcap有两个,一个是sourceforge.net的,那个已经实现了一个capture client,而且功能齐全,但在Windows下要用cygwin或mingwin)。另需要Jakarta common的codec及log4j,其它的可有可无。
HttpDump.java
/*
* HttpDump.java Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without fee is hereby
* granted provided that this copyright notice appears in all copies.
*
* ALSAN WONG MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
* NON-INFRINGEMENT. ALSAN WONG SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
* LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES.
*
* Created on 2005-5-28 Copyright 2005, alsan.home.net
*/
package net.alsan.httpdump;
import jpcap.*;
import org.apache.log4j.Logger;
/**
*
* @author alsan
* @version 1.0
*/
public final class HttpDump implements JpcapHandler {
public static final Logger log = Logger.getLogger(HttpDump.class);
public void handlePacket(Packet packet) {
boolean capture = true;
if (packet instanceof TCPPacket) {
TCPPacket tcp = (TCPPacket) packet;
if (80 == tcp.dst_port || 80 == tcp.src_port) {
printHost(tcp);
printPacket(tcp);
}
}
}
private void printPacket(TCPPacket tcp) {
if (0 != tcp.data.length) {
try {
HttpPacket http = new HttpPacket(tcp.data);
http.printInfo();
} catch (Exception e) {
log.error("handlePacket(Packet)", e);
}
}
log.info("---------------------------------------------------------------");
}
private void printHost(TCPPacket tcp) {
StringBuilder sb = new StringBuilder();
sb.append(tcp.src_ip.getHostAddress()).append(tcp.src_port).append(" -> ");
sb.append(tcp.dst_ip.getHostAddress()).append(tcp.dst_port);
log.info(sb.toString());
}
public static void main(String[] args) throws Exception {
Jpcap jpcap = Jpcap.openDevice(Jpcap.getDeviceList()[1], 1000, false, 20);
jpcap.loopPacket(-1, new HttpDump());
}
}
HttpPacket.java
/*
* HttpPacket.java
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* ALSAN WONG MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
* SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ALSAN WONG
* SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT
* OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*
* Created on 2005-5-30
* Copyright 2005, alsan.home.net
*/
package net.alsan.httpdump;
import java.io.*;
import net.alsan.jlib.io.BufferedInputStreamReader;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.httpclient.*;
import org.apache.log4j.Logger;
/**
*
* @author alsan
* @version 1.0
*/
public final class HttpPacket {
public static final Logger log = Logger.getLogger(HttpPacket.class);
byte[] data;
BufferedInputStreamReader reader;
String status, content;
Header[] header;
int headerLen = 0;
private static int lastDecodeMethod = 0; // 0=text, 1=bin
public HttpPacket(byte[] data) {
this.data = data;
reader = new BufferedInputStreamReader(new ByteArrayInputStream(data));
}
public void printInfo() throws IOException, HttpException {
decodeData();
printStatus();
printHeader();
printContent();
}
private void printContent() {
if(null != content) {
log.info(content);
}
}
private void printHeader() {
if(null != header) {
for(int i=0; i<header.length; i++) {
StringBuilder sb = new StringBuilder();
sb.append(header[i].getName()).append(": ").append(header[i].getValue());
log.info(sb.toString());
}
}
}
private void printStatus() {
if(null != status) {
log.info(status);
}
}
private void decodeData() throws IOException, HttpException {
if(detectHeader()) {
decodeHeader();
if (data.length > headerLen) {
if (isTextContent()) {
decodeTextContent();
} else {
decodeBinContent();
}
}
} else {
if(0 == lastDecodeMethod) {
content = new String(data);
if(content.startsWith("GIF89a")) {
decodeBinContent();
}
} else {
decodeBinContent();
}
}
}
private void decodeBinContent() {
lastDecodeMethod = 1;
StringBuilder sb = new StringBuilder();
for (int i = 0, cnt = data.length - headerLen; i < cnt; i++) {
sb.append(Hex.encodeHex(new byte[] { data[i + headerLen] })).append(" ");
if (31 == (i % 32)) {
sb.append("\n");
} else if (7 == (i % 8)) {
sb.append(" ");
}
}
content = sb.toString();
}
private void decodeTextContent() throws IOException {
lastDecodeMethod = 0;
StringBuilder sb = new StringBuilder();
String line;
while(null != (line = reader.readLine())) {
sb.append(line);
}
content = sb.toString();
}
private boolean isTextContent() {
boolean textContent = false;
String value = findHeader("Content-Type");
if(null != value && (value.startsWith("text") || value.endsWith("x-www-form-urlencoded")) ) {
value = findHeader("Content-Encoding");
if(null == value || -1 == value.indexOf("gzip")) {
textContent = true;
}
}
return textContent;
}
private boolean detectHeader() throws IOException {
boolean exist = false;
String line = reader.readLine();
if(-1 != line.indexOf("HTTP/1")) {
status = line;
exist = true;
}
return exist;
}
private void decodeHeader() throws IOException, HttpException {
String[] heads = getHeaders();
header = new Header[heads.length];
for(int i=0; i<heads.length; i++) {
String[] parts = heads[i].split(": ");
if(2 != parts.length) {
throw new HttpException("Invalid HTTP header");
}
header[i] = new Header(parts[0], parts[1]);
}
}
private String[] getHeaders() throws IOException {
StringBuilder sb = new StringBuilder();
String line;
while(null != (line = reader.readLine()) && !line.equals("")) {
sb.append(line).append("\r\n");
}
headerLen = status.length() + sb.length() + 4;
return sb.toString().split("\r\n");
}
private String findHeader(String name) {
String value = null;
for(int i=0; i<header.length; i++) {
if(header[i].getName().equalsIgnoreCase(name)) {
value = header[i].getValue();
break;
}
}
return value;
}
}