TRA-4140 Fix HTTP/1.0 is recognized as HTTP/1.1 (#666)

This commit is contained in:
M. Mert Yıldıran 2022-01-20 11:02:21 +03:00 committed by GitHub
parent d5fd2ff1da
commit b31af7214b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 22 deletions

View File

@ -24,7 +24,7 @@ Think TCPDump and Wireshark re-invented for Kubernetes.
- Simple and powerful CLI - Simple and powerful CLI
- Monitoring network traffic in real-time. Supported protocols: - Monitoring network traffic in real-time. Supported protocols:
- [HTTP/1.1](https://datatracker.ietf.org/doc/html/rfc2616) (REST, etc.) - [HTTP/1.x](https://datatracker.ietf.org/doc/html/rfc2616) (REST, GraphQL, SOAP, etc.)
- [HTTP/2](https://datatracker.ietf.org/doc/html/rfc7540) (gRPC) - [HTTP/2](https://datatracker.ietf.org/doc/html/rfc7540) (gRPC)
- [AMQP](https://www.rabbitmq.com/amqp-0-9-1-reference.html) (RabbitMQ, Apache Qpid, etc.) - [AMQP](https://www.rabbitmq.com/amqp-0-9-1-reference.html) (RabbitMQ, Apache Qpid, etc.)
- [Apache Kafka](https://kafka.apache.org/protocol) - [Apache Kafka](https://kafka.apache.org/protocol)

View File

@ -66,7 +66,7 @@ func handleHTTP2Stream(http2Assembler *Http2Assembler, tcpID *api.TcpID, superTi
streamID, streamID,
"HTTP2", "HTTP2",
) )
item = reqResMatcher.registerRequest(ident, &messageHTTP1, superTimer.CaptureTime) item = reqResMatcher.registerRequest(ident, &messageHTTP1, superTimer.CaptureTime, messageHTTP1.ProtoMinor)
if item != nil { if item != nil {
item.ConnectionInfo = &api.ConnectionInfo{ item.ConnectionInfo = &api.ConnectionInfo{
ClientIP: tcpID.SrcIP, ClientIP: tcpID.SrcIP,
@ -86,7 +86,7 @@ func handleHTTP2Stream(http2Assembler *Http2Assembler, tcpID *api.TcpID, superTi
streamID, streamID,
"HTTP2", "HTTP2",
) )
item = reqResMatcher.registerResponse(ident, &messageHTTP1, superTimer.CaptureTime) item = reqResMatcher.registerResponse(ident, &messageHTTP1, superTimer.CaptureTime, messageHTTP1.ProtoMinor)
if item != nil { if item != nil {
item.ConnectionInfo = &api.ConnectionInfo{ item.ConnectionInfo = &api.ConnectionInfo{
ClientIP: tcpID.DstIP, ClientIP: tcpID.DstIP,
@ -135,7 +135,7 @@ func handleHTTP1ClientStream(b *bufio.Reader, tcpID *api.TcpID, counterPair *api
counterPair.Request, counterPair.Request,
"HTTP1", "HTTP1",
) )
item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime) item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime, req.ProtoMinor)
if item != nil { if item != nil {
item.ConnectionInfo = &api.ConnectionInfo{ item.ConnectionInfo = &api.ConnectionInfo{
ClientIP: tcpID.SrcIP, ClientIP: tcpID.SrcIP,
@ -175,7 +175,7 @@ func handleHTTP1ServerStream(b *bufio.Reader, tcpID *api.TcpID, counterPair *api
counterPair.Response, counterPair.Response,
"HTTP1", "HTTP1",
) )
item := reqResMatcher.registerResponse(ident, res, superTimer.CaptureTime) item := reqResMatcher.registerResponse(ident, res, superTimer.CaptureTime, res.ProtoMinor)
if item != nil { if item != nil {
item.ConnectionInfo = &api.ConnectionInfo{ item.ConnectionInfo = &api.ConnectionInfo{
ClientIP: tcpID.DstIP, ClientIP: tcpID.DstIP,

View File

@ -235,8 +235,8 @@ func checkIsHTTP2ServerStream(b *bufio.Reader) (bool, error) {
return false, err return false, err
} }
// If response starts with this text, it is HTTP/1.x // If response starts with HTTP/1. then it's not HTTP/2
if bytes.Compare(buf, []byte("HTTP/1.0 ")) == 0 || bytes.Compare(buf, []byte("HTTP/1.1 ")) == 0 { if bytes.HasPrefix(buf, []byte("HTTP/1.")) {
return false, nil return false, nil
} }

View File

@ -15,7 +15,21 @@ import (
"github.com/up9inc/mizu/tap/api" "github.com/up9inc/mizu/tap/api"
) )
var protocol api.Protocol = api.Protocol{ var http10protocol api.Protocol = api.Protocol{
Name: "http",
LongName: "Hypertext Transfer Protocol -- HTTP/1.0",
Abbreviation: "HTTP",
Macro: "http",
Version: "1.0",
BackgroundColor: "#205cf5",
ForegroundColor: "#ffffff",
FontSize: 12,
ReferenceLink: "https://datatracker.ietf.org/doc/html/rfc1945",
Ports: []string{"80", "443", "8080"},
Priority: 0,
}
var http11protocol api.Protocol = api.Protocol{
Name: "http", Name: "http",
LongName: "Hypertext Transfer Protocol -- HTTP/1.1", LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
Abbreviation: "HTTP", Abbreviation: "HTTP",
@ -69,12 +83,12 @@ func init() {
type dissecting string type dissecting string
func (d dissecting) Register(extension *api.Extension) { func (d dissecting) Register(extension *api.Extension) {
extension.Protocol = &protocol extension.Protocol = &http11protocol
extension.MatcherMap = reqResMatcher.openMessagesMap extension.MatcherMap = reqResMatcher.openMessagesMap
} }
func (d dissecting) Ping() { func (d dissecting) Ping() {
log.Printf("pong %s", protocol.Name) log.Printf("pong %s", http11protocol.Name)
} }
func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions) error { func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions) error {
@ -96,7 +110,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
http2Assembler = createHTTP2Assembler(b) http2Assembler = createHTTP2Assembler(b)
} }
if superIdentifier.Protocol != nil && superIdentifier.Protocol != &protocol { if superIdentifier.Protocol != nil && superIdentifier.Protocol != &http11protocol {
return errors.New("Identified by another protocol") return errors.New("Identified by another protocol")
} }
@ -128,7 +142,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
tcpID.DstPort, tcpID.DstPort,
"HTTP2", "HTTP2",
) )
item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime) item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime, req.ProtoMinor)
if item != nil { if item != nil {
item.ConnectionInfo = &api.ConnectionInfo{ item.ConnectionInfo = &api.ConnectionInfo{
ClientIP: tcpID.SrcIP, ClientIP: tcpID.SrcIP,
@ -154,7 +168,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
if !dissected { if !dissected {
return err return err
} }
superIdentifier.Protocol = &protocol superIdentifier.Protocol = &http11protocol
return nil return nil
} }
@ -442,9 +456,9 @@ func (d dissecting) Represent(request map[string]interface{}, response map[strin
func (d dissecting) Macros() map[string]string { func (d dissecting) Macros() map[string]string {
return map[string]string{ return map[string]string{
`http`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s"`, protocol.Name, protocol.Version), `http`: fmt.Sprintf(`proto.name == "%s" and proto.version.startsWith("%c")`, http11protocol.Name, http11protocol.Version[0]),
`http2`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s"`, protocol.Name, http2Protocol.Version), `http2`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s"`, http11protocol.Name, http2Protocol.Version),
`grpc`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s" and proto.macro == "%s"`, protocol.Name, grpcProtocol.Version, grpcProtocol.Macro), `grpc`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s" and proto.macro == "%s"`, http11protocol.Name, grpcProtocol.Version, grpcProtocol.Macro),
} }
} }

View File

@ -22,7 +22,7 @@ func createResponseRequestMatcher() requestResponseMatcher {
return *newMatcher return *newMatcher
} }
func (matcher *requestResponseMatcher) registerRequest(ident string, request *http.Request, captureTime time.Time) *api.OutputChannelItem { func (matcher *requestResponseMatcher) registerRequest(ident string, request *http.Request, captureTime time.Time, protoMinor int) *api.OutputChannelItem {
split := splitIdent(ident) split := splitIdent(ident)
key := genKey(split) key := genKey(split)
@ -41,14 +41,14 @@ func (matcher *requestResponseMatcher) registerRequest(ident string, request *ht
if responseHTTPMessage.IsRequest { if responseHTTPMessage.IsRequest {
return nil return nil
} }
return matcher.preparePair(&requestHTTPMessage, responseHTTPMessage) return matcher.preparePair(&requestHTTPMessage, responseHTTPMessage, protoMinor)
} }
matcher.openMessagesMap.Store(key, &requestHTTPMessage) matcher.openMessagesMap.Store(key, &requestHTTPMessage)
return nil return nil
} }
func (matcher *requestResponseMatcher) registerResponse(ident string, response *http.Response, captureTime time.Time) *api.OutputChannelItem { func (matcher *requestResponseMatcher) registerResponse(ident string, response *http.Response, captureTime time.Time, protoMinor int) *api.OutputChannelItem {
split := splitIdent(ident) split := splitIdent(ident)
key := genKey(split) key := genKey(split)
@ -67,14 +67,18 @@ func (matcher *requestResponseMatcher) registerResponse(ident string, response *
if !requestHTTPMessage.IsRequest { if !requestHTTPMessage.IsRequest {
return nil return nil
} }
return matcher.preparePair(requestHTTPMessage, &responseHTTPMessage) return matcher.preparePair(requestHTTPMessage, &responseHTTPMessage, protoMinor)
} }
matcher.openMessagesMap.Store(key, &responseHTTPMessage) matcher.openMessagesMap.Store(key, &responseHTTPMessage)
return nil return nil
} }
func (matcher *requestResponseMatcher) preparePair(requestHTTPMessage *api.GenericMessage, responseHTTPMessage *api.GenericMessage) *api.OutputChannelItem { func (matcher *requestResponseMatcher) preparePair(requestHTTPMessage *api.GenericMessage, responseHTTPMessage *api.GenericMessage, protoMinor int) *api.OutputChannelItem {
protocol := http11protocol
if protoMinor == 0 {
protocol = http10protocol
}
return &api.OutputChannelItem{ return &api.OutputChannelItem{
Protocol: protocol, Protocol: protocol,
Timestamp: requestHTTPMessage.CaptureTime.UnixNano() / int64(time.Millisecond), Timestamp: requestHTTPMessage.CaptureTime.UnixNano() / int64(time.Millisecond),

View File

@ -35,7 +35,7 @@ export function getClassification(statusCode: number): string {
let classification = StatusCodeClassification.NEUTRAL; let classification = StatusCodeClassification.NEUTRAL;
// 1 - 16 HTTP/2 (gRPC) status codes // 1 - 16 HTTP/2 (gRPC) status codes
// 2xx - 5xx HTTP/1.1 status codes // 2xx - 5xx HTTP/1.x status codes
if ((statusCode >= 200 && statusCode <= 399) || statusCode === 0) { if ((statusCode >= 200 && statusCode <= 399) || statusCode === 0) {
classification = StatusCodeClassification.SUCCESS; classification = StatusCodeClassification.SUCCESS;
} else if (statusCode >= 400 || (statusCode >= 1 && statusCode <= 16)) { } else if (statusCode >= 400 || (statusCode >= 1 && statusCode <= 16)) {