Putting it all together

Printer-friendly

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>