From 51860e130cb25902e332fc6a992d04f96ebad312 Mon Sep 17 00:00:00 2001 From: Leonid Bugaev Date: Mon, 20 Jun 2016 19:32:13 +0300 Subject: [PATCH 1/8] Add support for known network layers Fix #310 Close #311 --- raw_socket_listener/listener.go | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/raw_socket_listener/listener.go b/raw_socket_listener/listener.go index fd4f2c5..59bbcf9 100644 --- a/raw_socket_listener/listener.go +++ b/raw_socket_listener/listener.go @@ -351,16 +351,30 @@ func (t *Listener) readPcap() { continue } - if decoder == layers.LinkTypeEthernet { - // Skip ethernet layer, 14 bytes - data = packet.Data()[14:] - } else if decoder == layers.LinkTypeNull || decoder == layers.LinkTypeLoop { - data = packet.Data()[4:] - } else { - log.Println("Unknown packet layer", packet) - break + // We should remove network layer before parsing TCP/IP data + var of int + switch decoder { + case layers.LinkTypeEthernet: + of = 14 + case layers.LinkTypePPP: + of = 1 + case layers.LinkTypeFDDI: + of = 13 + case layers.LinkTypeNull: + of = 4 + case layers.LinkTypeLoop: + of = 4 + case layers.LinkTypeRaw: + of = 0 + case layers.LinkTypeLinuxSLL: + of = 16 + default: + log.Println("Unknown packet layer", packet) + break } + data = packet.Data()[of:] + version := uint8(data[0]) >> 4 if version == 4 { From e50ff77ca63460f2d5ec2a1f83af238541e6c9d2 Mon Sep 17 00:00:00 2001 From: Leonid Bugaev Date: Mon, 20 Jun 2016 19:57:10 +0300 Subject: [PATCH 2/8] Update echo.sh --- examples/middleware/echo.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/middleware/echo.sh b/examples/middleware/echo.sh index ec946ee..f6f10e0 100755 --- a/examples/middleware/echo.sh +++ b/examples/middleware/echo.sh @@ -2,6 +2,10 @@ # # `xxd` utility included into vim-common package # It allow hex decoding/encoding +# +# This example may broke if you request contains `null` string, you may consider using pipes instead. +# See: https://github.com/buger/gor/issues/309 +# function log { # Logging to stderr, because stdout/stdin used for data transfer From da09b14c8b3a292618b728ff4d2a2ac854442722 Mon Sep 17 00:00:00 2001 From: Joseph Lawson Date: Mon, 20 Jun 2016 11:02:12 -0400 Subject: [PATCH 3/8] DRY 100-continue tests --- raw_socket_listener/listener_test.go | 97 +++++++++------------------- 1 file changed, 31 insertions(+), 66 deletions(-) diff --git a/raw_socket_listener/listener_test.go b/raw_socket_listener/listener_test.go index f5d7d49..8d2b610 100644 --- a/raw_socket_listener/listener_test.go +++ b/raw_socket_listener/listener_test.go @@ -108,9 +108,7 @@ func TestRawListenerResponse(t *testing.T) { } } -func TestRawListener100Continue(t *testing.T) { - var req, resp *TCPMessage - +func TestShort100Continue(t *testing.T) { listener := NewListener("", "0", EnginePcap, true, 10*time.Millisecond) defer listener.Close() @@ -124,12 +122,36 @@ func TestRawListener100Continue(t *testing.T) { // panic(int(uint32(len(reqPacket1.Data)) + uint32(len(reqPacket2.Data)) + uint32(len(reqPacket3.Data)))) respPacket2 := buildPacket(false, reqPacket3.Seq+1 /* len of data */, 2, []byte("HTTP/1.1 200 OK\r\n")) - listener.packetsChan <- reqPacket1.Dump() - listener.packetsChan <- reqPacket2.Dump() - listener.packetsChan <- reqPacket3.Dump() + result := []byte("POST / HTTP/1.1\r\nContent-Length: 2\r\n\r\nab") - listener.packetsChan <- respPacket1.Dump() - listener.packetsChan <- respPacket2.Dump() + testRawListener100Continue(t, listener, result, reqPacket1, reqPacket2, reqPacket3, respPacket1, respPacket2) +} + +// Response comes before Request +func Test100ContinueWrongOrder(t *testing.T) { + listener := NewListener("", "0", EnginePcap, true, 10*time.Millisecond) + defer listener.Close() + + reqPacket1 := buildPacket(true, 1, 1, []byte("POST / HTTP/1.1\r\nContent-Length: 2\r\nExpect: 100-continue\r\n\r\n")) + // Packet with data have different Seq + reqPacket2 := buildPacket(true, 2, reqPacket1.Seq+uint32(len(reqPacket1.Data)), []byte("a")) + reqPacket3 := buildPacket(true, 2, reqPacket2.Seq+1, []byte("b")) + + respPacket1 := buildPacket(false, 10, 3, []byte("HTTP/1.1 100 Continue\r\n")) + + // panic(int(uint32(len(reqPacket1.Data)) + uint32(len(reqPacket2.Data)) + uint32(len(reqPacket3.Data)))) + respPacket2 := buildPacket(false, reqPacket3.Seq+1 /* len of data */, 2, []byte("HTTP/1.1 200 OK\r\n")) + + result := []byte("POST / HTTP/1.1\r\nContent-Length: 2\r\n\r\nab") + + testRawListener100Continue(t, listener, result, respPacket1, respPacket2, reqPacket1, reqPacket2, reqPacket3) +} + +func testRawListener100Continue(t *testing.T, listener *Listener, result []byte, packets ...*TCPPacket) { + var req, resp *TCPMessage + for _, p := range packets { + listener.packetsChan <- p.Dump() + } select { case req = <-listener.messagesChan: @@ -139,64 +161,7 @@ func TestRawListener100Continue(t *testing.T) { return } - if !bytes.Equal(req.Bytes(), []byte("POST / HTTP/1.1\r\nContent-Length: 2\r\n\r\nab")) { - t.Error("Should receive full message", string(req.Bytes())) - } - - if !req.IsIncoming { - t.Error("Should be request") - } - - select { - case resp = <-listener.messagesChan: - break - case <-time.After(21 * time.Millisecond): - t.Error("Should return response after expire time") - return - } - - if resp.IsIncoming { - t.Error("Should be response") - } - - if !bytes.Equal(resp.UUID(), req.UUID()) { - t.Error("Resp and Req UUID should be equal") - } -} - -// Response comes before Request -func TestRawListener100ContinueWrongOrder(t *testing.T) { - var req, resp *TCPMessage - - listener := NewListener("", "0", EnginePcap, true, 10*time.Millisecond) - defer listener.Close() - - reqPacket1 := buildPacket(true, 1, 1, []byte("POST / HTTP/1.1\r\nContent-Length: 2\r\nExpect: 100-continue\r\n\r\n")) - // Packet with data have different Seq - reqPacket2 := buildPacket(true, 2, reqPacket1.Seq+uint32(len(reqPacket1.Data)), []byte("a")) - reqPacket3 := buildPacket(true, 2, reqPacket2.Seq+1, []byte("b")) - - respPacket1 := buildPacket(false, 10, 3, []byte("HTTP/1.1 100 Continue\r\n")) - - // panic(int(uint32(len(reqPacket1.Data)) + uint32(len(reqPacket2.Data)) + uint32(len(reqPacket3.Data)))) - respPacket2 := buildPacket(false, reqPacket3.Seq+1 /* len of data */, 2, []byte("HTTP/1.1 200 OK\r\n")) - - listener.packetsChan <- respPacket1.Dump() - listener.packetsChan <- respPacket2.Dump() - - listener.packetsChan <- reqPacket1.Dump() - listener.packetsChan <- reqPacket2.Dump() - listener.packetsChan <- reqPacket3.Dump() - - select { - case req = <-listener.messagesChan: - break - case <-time.After(11 * time.Millisecond): - t.Error("Should return response after expire time") - return - } - - if !bytes.Equal(req.Bytes(), []byte("POST / HTTP/1.1\r\nContent-Length: 2\r\n\r\nab")) { + if !bytes.Equal(req.Bytes(), result) { t.Error("Should receive full message", string(req.Bytes())) } From b0fff3c4029d9293cdfa33e9e39cefb018059d44 Mon Sep 17 00:00:00 2001 From: Joseph Lawson Date: Mon, 20 Jun 2016 11:59:00 -0400 Subject: [PATCH 4/8] Alternative 100 continue test --- raw_socket_listener/listener_test.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/raw_socket_listener/listener_test.go b/raw_socket_listener/listener_test.go index 8d2b610..3f3b250 100644 --- a/raw_socket_listener/listener_test.go +++ b/raw_socket_listener/listener_test.go @@ -147,6 +147,27 @@ func Test100ContinueWrongOrder(t *testing.T) { testRawListener100Continue(t, listener, result, respPacket1, respPacket2, reqPacket1, reqPacket2, reqPacket3) } +func TestAlt100ContinueHeaderOrder(t *testing.T) { + listener := NewListener("", "0", EnginePcap, true, 10*time.Millisecond) + defer listener.Close() + + reqPacket1 := buildPacket(true, 1, 1, []byte("POST / HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 2\r\n\r\n")) + // Packet with data have different Seq + reqPacket2 := buildPacket(true, 2, reqPacket1.Seq+uint32(len(reqPacket1.Data)), []byte("a")) + reqPacket3 := buildPacket(true, 2, reqPacket2.Seq+1, []byte("b")) + + respPacket1 := buildPacket(false, 10, 3, []byte("HTTP/1.1 100 Continue\r\n")) + + // panic(int(uint32(len(reqPacket1.Data)) + uint32(len(reqPacket2.Data)) + uint32(len(reqPacket3.Data)))) + respPacket2 := buildPacket(false, reqPacket3.Seq+1 /* len of data */, 2, []byte("HTTP/1.1 200 OK\r\n")) + + result := []byte("POST / HTTP/1.1\r\nContent-Length: 2\r\n\r\nab") + + testRawListener100Continue(t, listener, result, reqPacket1, reqPacket2, reqPacket3, respPacket1, respPacket2) +} + + + func testRawListener100Continue(t *testing.T, listener *Listener, result []byte, packets ...*TCPPacket) { var req, resp *TCPMessage for _, p := range packets { @@ -157,7 +178,7 @@ func testRawListener100Continue(t *testing.T, listener *Listener, result []byte, case req = <-listener.messagesChan: break case <-time.After(11 * time.Millisecond): - t.Error("Should return request after expire time") + t.Error("Should return response after expire time") return } From 5d2cc68fffac53b89b141ed6fbf1b7e992071d0c Mon Sep 17 00:00:00 2001 From: Joseph Lawson Date: Mon, 20 Jun 2016 16:14:54 -0400 Subject: [PATCH 5/8] Add proto.DelHeader Update proto.go to handle headers with whitespace after --- proto/proto.go | 50 ++++++++++++++++++++++++++++++++++----------- proto/proto_test.go | 28 ++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/proto/proto.go b/proto/proto.go index 0e74cc8..4e15a5a 100644 --- a/proto/proto.go +++ b/proto/proto.go @@ -123,7 +123,7 @@ func headerIndex(payload []byte, name []byte) int { // header return value and positions of header/value start/end. // If not found, value will be blank, and headerStart will be -1 // Do not support multi-line headers. -func header(payload []byte, name []byte) (value []byte, headerStart, valueStart, headerEnd int) { +func header(payload []byte, name []byte) (value []byte, headerStart, headerEnd, valueStart, valueEnd int) { headerStart = headerIndex(payload, name) if headerStart == -1 { @@ -131,24 +131,37 @@ func header(payload []byte, name []byte) (value []byte, headerStart, valueStart, } valueStart = headerStart + len(name) + 1 // Skip ":" after header name - if payload[valueStart] == ' ' { // Ignore empty space after ':' - valueStart++ - } - headerEnd = valueStart + bytes.IndexByte(payload[valueStart:], '\n') - if payload[headerEnd-1] == '\r' { - headerEnd -= 1 + for valueStart < headerEnd { // Ignore empty space after ':' + if payload[valueStart] == ' ' { + valueStart++ + } else { + break + } } - value = payload[valueStart:headerEnd] + valueEnd = valueStart + bytes.IndexByte(payload[valueStart:], '\n') + + if payload[headerEnd-1] == '\r' { + valueEnd -= 1 + } + + for valueStart < valueEnd { // ignore empty space at end of header value + if payload[valueEnd-1] == ' ' { + valueEnd -= 1 + } else { + break + } + } + value = payload[valueStart:valueEnd] return } // Header returns header value, if header not found, value will be blank func Header(payload, name []byte) []byte { - val, _, _, _ := header(payload, name) + val, _, _, _, _ := header(payload, name) return val } @@ -156,11 +169,11 @@ func Header(payload, name []byte) []byte { // SetHeader sets header value. If header not found it creates new one. // Returns modified request payload func SetHeader(payload, name, value []byte) []byte { - _, hs, vs, he := header(payload, name) + _, hs, _, vs, ve := header(payload, name) if hs != -1 { - // If header found we just repace its value - return byteutils.Replace(payload, vs, he, value) + // If header found we just replace its value + return byteutils.Replace(payload, vs, ve, value) } return AddHeader(payload, name, value) @@ -180,6 +193,19 @@ func AddHeader(payload, name, value []byte) []byte { return byteutils.Insert(payload, mimeStart, header) } +// DelHeader takes http payload and removes header name from headers section +// Returns modified request payload +func DelHeader(payload, name[]byte) []byte { + _, hs, he, _, _ := header(payload, name) + if hs != -1 { + newHeader := make([]byte, len(payload) - (he - hs) - 1) + copy(newHeader[:hs], payload[:hs]) + copy(newHeader[hs:], payload[he + 1:]) + return newHeader + } + return payload +} + // Body returns request/response body func Body(payload []byte) []byte { // 4 -> len(EMPTY_LINE) diff --git a/proto/proto_test.go b/proto/proto_test.go index a8d9179..2510237 100644 --- a/proto/proto_test.go +++ b/proto/proto_test.go @@ -16,6 +16,13 @@ func TestHeader(t *testing.T) { t.Error("Should find header value") } + // Value with space at end + payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 7 \r\nHost: www.w3.org\r\n\r\na=1&b=2") + + if val = Header(payload, []byte("Content-Length")); !bytes.Equal(val, []byte("7")) { + t.Error("Should find header value without space after 7") + } + // Value without space at start payload = []byte("POST /post HTTP/1.1\r\nContent-Length:7\r\nHost: www.w3.org\r\n\r\na=1&b=2") @@ -38,7 +45,7 @@ func TestHeader(t *testing.T) { } // Header not found - if _, headerStart, _, _ = header(payload, []byte("Not-Found")); headerStart != -1 { + if _, headerStart, _, _, _ = header(payload, []byte("Not-Found")); headerStart != -1 { t.Error("Should not found header") } @@ -97,6 +104,25 @@ func TestSetHeader(t *testing.T) { } } +func TestDelHeader(t *testing.T) { + var payload, payloadAfter []byte + + payload = []byte("POST /post HTTP/1.1\r\nUser-Agent: Gor\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2") + payloadAfter = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2") + + if payload = DelHeader(payload, []byte("User-Agent")); !bytes.Equal(payload, payloadAfter) { + t.Error("Should delete header if found", string(payload), string(payloadAfter)) + } + + //Whitespace at end of User-Agent + payload = []byte("POST /post HTTP/1.1\r\nUser-Agent: Gor \r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2") + payloadAfter = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2") + + if payload = DelHeader(payload, []byte("User-Agent")); !bytes.Equal(payload, payloadAfter) { + t.Error("Should delete header if found", string(payload), string(payloadAfter)) + } +} + func TestPath(t *testing.T) { var path, payload []byte From 0089892b26c21d5e0ccdf7d8c4ef89ad2c9f48bd Mon Sep 17 00:00:00 2001 From: Joseph Lawson Date: Mon, 20 Jun 2016 16:35:20 -0400 Subject: [PATCH 6/8] update 100-continue logic to support different header placement --- proto/proto.go | 4 +-- raw_socket_listener/listener.go | 52 ++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/proto/proto.go b/proto/proto.go index 4e15a5a..5376473 100644 --- a/proto/proto.go +++ b/proto/proto.go @@ -144,12 +144,12 @@ func header(payload []byte, name []byte) (value []byte, headerStart, headerEnd, valueEnd = valueStart + bytes.IndexByte(payload[valueStart:], '\n') if payload[headerEnd-1] == '\r' { - valueEnd -= 1 + valueEnd-- } for valueStart < valueEnd { // ignore empty space at end of header value if payload[valueEnd-1] == ' ' { - valueEnd -= 1 + valueEnd-- } else { break } diff --git a/raw_socket_listener/listener.go b/raw_socket_listener/listener.go index 59bbcf9..e1b0a29 100644 --- a/raw_socket_listener/listener.go +++ b/raw_socket_listener/listener.go @@ -28,6 +28,7 @@ import ( "strings" "sync" "time" + "github.com/buger/gor/proto" ) var _ = fmt.Println @@ -515,8 +516,10 @@ func (t *Listener) isValidPacket(buf []byte) bool { return false } -var bExpect100ContinueCheck = []byte("Expect: 100-continue") +var bExpectHeader = []byte("Expect:") +var bExpect100Value = []byte("100-continue") var bPOST = []byte("POST") +var bCRLFx2 = []byte("\r\n\r\n") // Trying to add packet to existing message or creating new message // @@ -590,33 +593,36 @@ func (t *Listener) processTCPPacket(packet *TCPPacket) { // Handling Expect: 100-continue requests if len(packet.Data) > 4 && bytes.Equal(packet.Data[0:4], bPOST) { - // reading last 20 bytes (not counting CRLF): last header value (if no body presented) - if bytes.Equal(packet.Data[len(packet.Data)-24:len(packet.Data)-4], bExpect100ContinueCheck) { - seq := packet.Seq + uint32(len(packet.Data)) - t.seqWithData[seq] = packet.Ack - message.DataSeq = seq + // reading last 8 bytes for double CRLF + if bytes.Equal(packet.Data[len(packet.Data)-4:], bCRLFx2) { + // look for an expect:100-continue header + if bytes.Equal(bExpect100Value, proto.Header(packet.Data, bExpectHeader)) { + seq := packet.Seq + uint32(len(packet.Data)) + t.seqWithData[seq] = packet.Ack + message.DataSeq = seq - // In case if sequence packet came first - for _, m := range t.messages { - if m.Seq == seq { - t.deleteMessage(m) - if m.AssocMessage != nil { - message.AssocMessage = m.AssocMessage - } - // log.Println("2: Adding ack alias:", m.Ack, packet.Ack) - t.ackAliases[m.Ack] = packet.Ack + // In case if sequence packet came first + for _, m := range t.messages { + if m.Seq == seq { + t.deleteMessage(m) + if m.AssocMessage != nil { + message.AssocMessage = m.AssocMessage + } + // log.Println("2: Adding ack alias:", m.Ack, packet.Ack) + t.ackAliases[m.Ack] = packet.Ack - for _, pkt := range m.packets { - pkt.UpdateAck(packet.Ack) - message.AddPacket(pkt) + for _, pkt := range m.packets { + pkt.UpdateAck(packet.Ack) + message.AddPacket(pkt) + } } } + + // Removing `Expect: 100-continue` header + packet.Data = proto.DelHeader(packet.Data, bExpectHeader) + + // log.Println(string(packet.Data)) } - - // Removing `Expect: 100-continue` header - packet.Data = append(packet.Data[:len(packet.Data)-24], packet.Data[len(packet.Data)-2:]...) - - // log.Println(string(packet.Data)) } } From aea32d93952c5ae4b3a3c1c36b4ee0252347c15a Mon Sep 17 00:00:00 2001 From: Leonid Bugaev Date: Tue, 21 Jun 2016 18:05:32 +0300 Subject: [PATCH 7/8] Rename DelHeader to DeleteHeader --- proto/proto.go | 5 +++-- proto/proto_test.go | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/proto/proto.go b/proto/proto.go index 5376473..40e59b1 100644 --- a/proto/proto.go +++ b/proto/proto.go @@ -147,7 +147,8 @@ func header(payload []byte, name []byte) (value []byte, headerStart, headerEnd, valueEnd-- } - for valueStart < valueEnd { // ignore empty space at end of header value + // ignore empty space at end of header value + for valueStart < valueEnd { if payload[valueEnd-1] == ' ' { valueEnd-- } else { @@ -195,7 +196,7 @@ func AddHeader(payload, name, value []byte) []byte { // DelHeader takes http payload and removes header name from headers section // Returns modified request payload -func DelHeader(payload, name[]byte) []byte { +func DeleteHeader(payload, name[]byte) []byte { _, hs, he, _, _ := header(payload, name) if hs != -1 { newHeader := make([]byte, len(payload) - (he - hs) - 1) diff --git a/proto/proto_test.go b/proto/proto_test.go index 2510237..897bc4f 100644 --- a/proto/proto_test.go +++ b/proto/proto_test.go @@ -104,13 +104,13 @@ func TestSetHeader(t *testing.T) { } } -func TestDelHeader(t *testing.T) { +func TestDeleteHeader(t *testing.T) { var payload, payloadAfter []byte payload = []byte("POST /post HTTP/1.1\r\nUser-Agent: Gor\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2") payloadAfter = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2") - if payload = DelHeader(payload, []byte("User-Agent")); !bytes.Equal(payload, payloadAfter) { + if payload = DeleteHeader(payload, []byte("User-Agent")); !bytes.Equal(payload, payloadAfter) { t.Error("Should delete header if found", string(payload), string(payloadAfter)) } @@ -118,7 +118,7 @@ func TestDelHeader(t *testing.T) { payload = []byte("POST /post HTTP/1.1\r\nUser-Agent: Gor \r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2") payloadAfter = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2") - if payload = DelHeader(payload, []byte("User-Agent")); !bytes.Equal(payload, payloadAfter) { + if payload = DeleteHeader(payload, []byte("User-Agent")); !bytes.Equal(payload, payloadAfter) { t.Error("Should delete header if found", string(payload), string(payloadAfter)) } } From 48fdc02d2f6d84e0d9cd3d1b459313f67735fe31 Mon Sep 17 00:00:00 2001 From: Leonid Bugaev Date: Tue, 21 Jun 2016 18:32:07 +0300 Subject: [PATCH 8/8] Fix tests + refactoring --- raw_socket_listener/listener.go | 51 +++++++++++------------------- raw_socket_listener/tcp_message.go | 29 +++++++++++++++++ 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/raw_socket_listener/listener.go b/raw_socket_listener/listener.go index e1b0a29..3cd5e70 100644 --- a/raw_socket_listener/listener.go +++ b/raw_socket_listener/listener.go @@ -516,11 +516,6 @@ func (t *Listener) isValidPacket(buf []byte) bool { return false } -var bExpectHeader = []byte("Expect:") -var bExpect100Value = []byte("100-continue") -var bPOST = []byte("POST") -var bCRLFx2 = []byte("\r\n\r\n") - // Trying to add packet to existing message or creating new message // // For TCP message unique id is Acknowledgment number (see tcp_packet.go) @@ -592,38 +587,30 @@ func (t *Listener) processTCPPacket(packet *TCPPacket) { message.AddPacket(packet) // Handling Expect: 100-continue requests - if len(packet.Data) > 4 && bytes.Equal(packet.Data[0:4], bPOST) { - // reading last 8 bytes for double CRLF - if bytes.Equal(packet.Data[len(packet.Data)-4:], bCRLFx2) { - // look for an expect:100-continue header - if bytes.Equal(bExpect100Value, proto.Header(packet.Data, bExpectHeader)) { - seq := packet.Seq + uint32(len(packet.Data)) - t.seqWithData[seq] = packet.Ack - message.DataSeq = seq + if message.Is100Continue() { + seq := packet.Seq + uint32(len(packet.Data)) + t.seqWithData[seq] = packet.Ack + message.DataSeq = seq - // In case if sequence packet came first - for _, m := range t.messages { - if m.Seq == seq { - t.deleteMessage(m) - if m.AssocMessage != nil { - message.AssocMessage = m.AssocMessage - } - // log.Println("2: Adding ack alias:", m.Ack, packet.Ack) - t.ackAliases[m.Ack] = packet.Ack - - for _, pkt := range m.packets { - pkt.UpdateAck(packet.Ack) - message.AddPacket(pkt) - } - } + // In case if sequence packet came first + for _, m := range t.messages { + if m.Seq == seq { + t.deleteMessage(m) + if m.AssocMessage != nil { + message.AssocMessage = m.AssocMessage } + // log.Println("2: Adding ack alias:", m.Ack, packet.Ack) + t.ackAliases[m.Ack] = packet.Ack - // Removing `Expect: 100-continue` header - packet.Data = proto.DelHeader(packet.Data, bExpectHeader) - - // log.Println(string(packet.Data)) + for _, pkt := range m.packets { + pkt.UpdateAck(packet.Ack) + message.AddPacket(pkt) + } } } + + // Removing `Expect: 100-continue` header + packet.Data = proto.DeleteHeader(packet.Data, bExpectHeader) } // log.Println("Received message:", string(message.Bytes()), message.ID(), t.messages) diff --git a/raw_socket_listener/tcp_message.go b/raw_socket_listener/tcp_message.go index f533ad6..5045f4d 100644 --- a/raw_socket_listener/tcp_message.go +++ b/raw_socket_listener/tcp_message.go @@ -227,6 +227,35 @@ func (t *TCPMessage) IsFinished() bool { return false } +var bExpectHeader = []byte("Expect:") +var bExpect100Value = []byte("100-continue") +var bPOST = []byte("POST") +var bCRLFx2 = []byte("\r\n\r\n") + +func (t *TCPMessage) Is100Continue() bool { + d := t.packets[0].Data + + if len(d) < 25 { + return false + } + + if !bytes.Equal(d[0:4], bPOST) { + return false + } + + // reading last 4 bytes for double CRLF + if !bytes.Equal(d[len(d)-4:], bCRLFx2) { + return false + } + + // look for an expect:100-continue header + if !bytes.Equal(bExpect100Value, proto.Header(d, bExpectHeader)) { + return false + } + + return true +} + func (t *TCPMessage) UUID() []byte { var key []byte