On Feb 13, 2014, at 7:37 AM, Emanuele Di Pascale <[email protected]> wrote:
> Hello,
> I'm trying to write a POX module to identify http GET requests to specific IP
> addresses and react based on the page requested, but I'm struggling with the
> http part. There doesn't seem to be a POX http packet class, so I assume I
> need to convert the raw bytes read from the wire into a string representation
> of the http message. However the couple of approaches I tried all failed
> miserably. Specifically, after retrieving the tcp packet in my PacketIn
> handler like this:
>
> tcp = event.parsed.find('tcp')
> if tcp is not None and tcp.parsed:
>
> any attempt to call tcp.payload() will result in a TypeError message (cannot
> call str).
Peter was right with this. .payload isn't a method/function you call. It's a
property, which means it's implemented like a function, but it acts like it's a
normal data attribute. Since TCP is the last parsed packet type, it just acts
like a bytes/string.
> Calling tcp.next.decode("utf-8") and trying to print that through log.debug
> will throw a "TypeError: not all arguments converted during string
> formatting" exception .
I don't think there are any usecases for using .next instead of .payload.
Always use .payload. tcp.payload.decode("utf-8") should have identical meaning.
If you got this TypeError, though, it seems likely that your call to
log.debug() was somehow faulty. You probably want something like:
log.debug("HTTP: %s", tcp.payload)
> And similarly I get an exception for
>
> dlen = len(tcp.next)
> (http) = struct.unpack('!'+str(dlen)+'s', tcp.next)
> log.debug("Http payload: " + http)
The problem here is that unpack() returns a tuple (in this case with a single
element). You can use destructuring assignment to extract the single field.
This looks like it's probably what you're trying to do here, *but* (http) isn't
a tuple. It's just http with parentheses around it (a trivial subexpression).
To make a length-one tuple, you need the comma: (http,). In this case, a more
straightforward way is probably just to use the index operator to extract the
one and only element:
http = struct.unpack('!'+str(dlen)+'s', tcp.next)[0]
But, of course, this should be almost a no-op. http = tcp.next (or, better
yet, http = tcp.payload) should be basically the same.
> I'm assuming the problem might be the CR+LF characters in the http message,
> but I have no way of knowing the length of the message as it depends on the
> page that's being requested. It could also be something else, as I'm new to
> Python and possibly missing something very obvious. Any hints?
>
> Thanks in advance!
>
> Emanuele Di Pascale