I'm putting everything together now. I finished up the Http header type. Most specifically finished JMappedHeader implementation which allows enum tables to be used as fields. This greatly saves on the amount of code that needs to go into the file.
I still haven't fully solved the threading issue, although I haven't looked at it too much, as I started working on JMappedHeader instead. Putting the primary thread to sleep for 100ms stops the other thread from exiting prematurely. I still don't understand why. I'll revisit the issue tomorrow with new perspective.
Added JRegistry methods for managing analyzers. Also added a rudimentatary HttpAnalyzer. This is what everything I've been doing is leading up to. HttpAnalyzer is in the position to tell tcp how to reassemble the stream. Anyway, I made some good progress.
Http is implemented in terms of JMappedHeader. A base class called AbstractMessageHeader implements most of the common header stuff and then Http header defines Http specific stuff. SIP header will also extend AbstractMessageHeader and add its own field types.
Here is the complete Http and Html header definitions:
package org.jnetpcap.packet.header;
import org.jnetpcap.newstuff.AbstractMessageHeader;
import org.jnetpcap.packet.JPacket;
import org.jnetpcap.packet.annotate.Bind;
import org.jnetpcap.packet.annotate.Field;
import org.jnetpcap.packet.annotate.Header;
/**
* @author Mark Bednarczyk
* @author Sly Technologies, Inc.
*/
@Header
public class Http
extends AbstractMessageHeader {
@Bind(to = Tcp.class, intValue = {
80,
8080 })
public static boolean bindToTcp(JPacket packet, Tcp tcp) {
return tcp.destination() == 80 || tcp.source() == 80
|| tcp.destination() == 8080 || tcp.source() == 8080;
}
/**
* HTTP Request fields
*
* @author Mark Bednarczyk
* @author Sly Technologies, Inc.
*/
@Field
public enum Request {
Accept,
Accept_Charset,
Accept_Encoding,
Accept_Ranges,
Authorization,
Cache_Control,
Connection,
Cookie,
Date,
Host,
If_Modified_Since,
If_None_Match,
Referrer,
User_Agent,
RequestVersion,
RequestMethod,
RequestUrl,
}
/**
* HTTP Response fields
*
* @author Mark Bednarczyk
* @author Sly Technologies, Inc.
*/
@Field
public enum Response {
Accept_Ranges,
Age,
Allow,
Cache_Control,
Content_Encoding,
Content_Length,
Content_Location,
Content_Disposition,
Content_MD5,
Content_Range,
Content_Type,
RequestVersion,
ResponseCode,
ResponseCodeMsg,
RequestUrl,
}
public boolean hasField(Request field) {
return super.hasField(field);
}
public String fieldValue(Request field) {
return super.fieldValue(String.class, field);
}
public boolean hasField(Response field) {
return super.hasField(field);
}
public String fieldValue(Response field) {
return super.fieldValue(String.class, field);
}
@Override
protected void decodeFirstLine(String line) {
String[] c = line.split(" ");
if (c[0].startsWith("HTTP")) {
super.setMessageType(MessageType.RESPONSE);
super.addField(Response.RequestVersion, c[0], line.indexOf(c[0]));
super.addField(Response.ResponseCode, c[1], line.indexOf(c[1]));
super.addField(Response.ResponseCodeMsg, c[2], line.indexOf(c[2]));
} else {
super.setMessageType(MessageType.REQUEST);
super.addField(Request.RequestMethod, c[0], line.indexOf(c[0]));
super.addField(Request.RequestUrl, c[1], line.indexOf(c[1]));
super.addField(Request.RequestVersion, c[2], line.indexOf(c[2]));
}
}
/**
* @return
*/
public boolean hasContentType() {
return hasField(Response.Content_Type);
}
/**
* @return
*/
public String contentType() {
return fieldValue(Response.Content_Type);
}
/**
* @return
*/
public boolean isResponse() {
return getMessageType() == MessageType.RESPONSE;
}
/**
* @return
*/
public boolean hasContent() {
return hasField(Response.Content_Type);
}
}
package org.jnetpcap.packet.header;
import org.jnetpcap.nio.JBuffer;
import org.jnetpcap.packet.JHeader;
import org.jnetpcap.packet.JPacket;
import org.jnetpcap.packet.annotate.Bind;
import org.jnetpcap.packet.annotate.Dynamic;
import org.jnetpcap.packet.annotate.Field;
import org.jnetpcap.packet.annotate.Header;
import org.jnetpcap.packet.annotate.HeaderLength;
/**
* @author Mark Bednarczyk
* @author Sly Technologies, Inc.
*/
@Header(nicname = "Html")
public class Html
extends JHeader {
@HeaderLength
public static int headerLength(JBuffer buffer, int offset) {
return buffer.size() - offset;
}
@Bind(to = Http.class, stringValue = "text/html")
public static boolean bind2Http(JPacket packet, Http http) {
return http.hasContentType() && http.contentType().startsWith("text/html;");
}
private final StringBuilder buf = new StringBuilder();
private String page;
@Dynamic(Field.Property.LENGTH)
public int pageLength() {
return size() * 8;
}
@Field(offset = 0, format = "#textdump#")
public String page() {
return this.page;
}
@Override
protected void decodeHeader() {
this.buf.setLength(0);
super.getUTF8String(0, this.buf, size());
this.page = buf.toString();
}
}
and here is the output for one of the html packets:
Frame: Frame: number = 0 Frame: timestamp = 2004-11-19 17:29:14.191 Frame: wire length = 489 bytes Frame: captured length = 489 bytes Frame: Eth: ******* Ethernet - "Ethernet" - offset=0 (0x0) length=14 Eth: Eth: destination = 0:4:e2:22:5a:3 Eth: .... ..0. .... .... = [0] LG bit Eth: .... ...0 .... .... = [0] IG bit Eth: source = 0:c0:df:20:6c:df Eth: .... ..0. .... .... = [0] LG bit Eth: .... ...0 .... .... = [0] IG bit Eth: type = 0x800 (2048) [ip version 4] Eth: Ip: ******* Ip4 - "ip version 4" - offset=14 (0xE) length=20 Ip: Ip: version = 4 Ip: hlen = 5 [5 * 4 = 20 bytes, No Ip Options] Ip: diffserv = 0x0 (0) Ip: 0000 00.. = [0] code point: not set Ip: .... ..0. = [0] ECN bit: not set Ip: .... ...0 = [0] ECE bit: not set Ip: length = 475 Ip: id = 0xC139 (49465) Ip: flags = 0x2 (2) Ip: 0.. = [0] reserved Ip: .1. = [1] DF: do not fragment: set Ip: ..0 = [0] MF: more fragments: not set Ip: offset = 0 Ip: ttl = 64 [time to live] Ip: type = 6 [next: tcp] Ip: checksum = 0x617C (24956) Ip: source = 10.1.1.1 Ip: destination = 10.1.1.101 Ip: Tcp: ******* Tcp offset=34 (0x22) length=20 Tcp: Tcp: source = 80 Tcp: destination = 3177 Tcp: seq = 0x373B85FA (926647802) Tcp: ack = 0x349C065B (882640475) Tcp: hlen = 5 Tcp: reserved = 0 Tcp: flags = 0x18 (24) Tcp: 0... .... = [0] cwr: reduced (cwr) Tcp: .0.. .... = [0] ece: ECN echo flag Tcp: ..0. .... = [0] ack: urgent, out-of-band data Tcp: ...1 .... = [1] ack: acknowledgment Tcp: .... 1... = [1] ack: push current segment of data Tcp: .... .0.. = [0] ack: reset connection Tcp: .... ..0. = [0] ack: synchronize connection, startup Tcp: .... ...0 = [0] fin: closing down connection Tcp: window = 6432 Tcp: checksum = 0xAFEA (45034) Tcp: urgent = 0 Tcp: Http: ******* Http offset=54 (0x36) length=275 Http: Http: RequestVersion = HTTP/1.1 Http: ResponseCode = 200 Http: ResponseCodeMsg = OK Http: Date = Sat, 20 Nov 2004 10:21:06 GMT Http: Accept-Ranges = bytes Http: Content-Length = 160 Http: Connection = close Http: Content-Type = text/html; charset=ISO-8859-1 Http: Html: ******* Html offset=329 (0x149) length=160 Html: <html> <head> <title> Ronnie sahlbergs Websida </title> </head> <body> <a href="./Websidan/index.html">Familjen Sahlbergs Websida</a> </body> </html>