mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-08-10 12:53:37 +00:00
Fix gRPC crash, display gRPC as base64, display gRPC URL and status code (#27)
* Added Method (POST) and URL (emtpy) to gRPC requests. * Removed quickfix that skips writing HTTP/2 to HAR. * Use HTTP/2 body to fill out http.Request and htt.Response. * Make sure that in HARs request.postData.mimeType and response.content.mimeType are application/grpc in case of grpc. * Comment. * Add URL and status code for gRPC. * Don't assume http scheme. * Use http.Header.Set instead of manually acccessing the underlaying map.
This commit is contained in:
parent
377fc79315
commit
4d6528771a
@ -6,8 +6,11 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
@ -62,6 +65,7 @@ func (fbs *fragmentsByStream) pop(streamID uint32) ([]hpack.HeaderField, []byte)
|
||||
headers := (*fbs)[streamID].headers
|
||||
data := (*fbs)[streamID].data
|
||||
delete((*fbs), streamID)
|
||||
|
||||
return headers, data
|
||||
}
|
||||
|
||||
@ -100,9 +104,11 @@ func (ga *GrpcAssembler) readMessage() (uint32, interface{}, string, error) {
|
||||
|
||||
headers, data := ga.fragmentsByStream.pop(streamID)
|
||||
|
||||
// Note: header keys are converted by http.Header.Set to canonical names, e.g. content-type -> Content-Type.
|
||||
// By converting the keys we violate the HTTP/2 specification, which state that all headers must be lowercase.
|
||||
headersHTTP1 := make(http.Header)
|
||||
for _, header := range headers {
|
||||
headersHTTP1[header.Name] = []string{header.Value}
|
||||
headersHTTP1.Add(header.Name, header.Value)
|
||||
}
|
||||
dataString := base64.StdEncoding.EncodeToString(data)
|
||||
|
||||
@ -112,10 +118,14 @@ func (ga *GrpcAssembler) readMessage() (uint32, interface{}, string, error) {
|
||||
var messageHTTP1 interface{}
|
||||
if _, ok := headersHTTP1[":method"]; ok {
|
||||
messageHTTP1 = http.Request{
|
||||
URL: &url.URL{},
|
||||
Method: "POST",
|
||||
Header: headersHTTP1,
|
||||
Proto: protoHTTP2,
|
||||
ProtoMajor: protoMajorHTTP2,
|
||||
ProtoMinor: protoMinorHTTP2,
|
||||
Body: io.NopCloser(strings.NewReader(dataString)),
|
||||
ContentLength: int64(len(dataString)),
|
||||
}
|
||||
} else if _, ok := headersHTTP1[":status"]; ok {
|
||||
messageHTTP1 = http.Response{
|
||||
@ -123,6 +133,8 @@ func (ga *GrpcAssembler) readMessage() (uint32, interface{}, string, error) {
|
||||
Proto: protoHTTP2,
|
||||
ProtoMajor: protoMajorHTTP2,
|
||||
ProtoMinor: protoMinorHTTP2,
|
||||
Body: io.NopCloser(strings.NewReader(dataString)),
|
||||
ContentLength: int64(len(dataString)),
|
||||
}
|
||||
} else {
|
||||
return 0, nil, "", errors.New("Failed to assemble stream: neither a request nor a message")
|
||||
|
@ -7,6 +7,8 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/martian/har"
|
||||
@ -40,26 +42,41 @@ type HarFile struct {
|
||||
}
|
||||
|
||||
func NewEntry(request *http.Request, requestTime time.Time, response *http.Response, responseTime time.Time) (*har.Entry, error) {
|
||||
// TODO: quick fix until TRA-3212 is implemented
|
||||
if request.URL == nil || request.Method == "" {
|
||||
return nil, errors.New("Invalid request")
|
||||
}
|
||||
harRequest, err := har.NewRequest(request, true)
|
||||
if err != nil {
|
||||
SilentError("convert-request-to-har", "Failed converting request to HAR %s (%v,%+v)\n", err, err, err)
|
||||
return nil, errors.New("Failed converting request to HAR")
|
||||
}
|
||||
|
||||
// Martian copies http.Request.URL.String() to har.Request.URL.
|
||||
// According to the spec, the URL field needs to be the absolute URL.
|
||||
harRequest.URL = fmt.Sprintf("http://%s%s", request.Host, request.URL)
|
||||
|
||||
harResponse, err := har.NewResponse(response, true)
|
||||
if err != nil {
|
||||
SilentError("convert-response-to-har", "Failed converting response to HAR %s (%v,%+v)\n", err, err, err)
|
||||
return nil, errors.New("Failed converting response to HAR")
|
||||
}
|
||||
|
||||
if harRequest.PostData != nil && strings.HasPrefix(harRequest.PostData.MimeType, "application/grpc") {
|
||||
// Force HTTP/2 gRPC into HAR template
|
||||
|
||||
harRequest.URL = fmt.Sprintf("%s://%s%s", request.Header.Get(":scheme"), request.Header.Get(":authority"), request.Header.Get(":path"))
|
||||
|
||||
status, err := strconv.Atoi(response.Header.Get(":status"))
|
||||
if err != nil {
|
||||
SilentError("convert-response-status-for-har", "Failed converting status to int %s (%v,%+v)\n", err, err, err)
|
||||
return nil, errors.New("Failed converting response status to int for HAR")
|
||||
}
|
||||
harResponse.Status = status
|
||||
} else {
|
||||
// Martian copies http.Request.URL.String() to har.Request.URL, which usually contains the path.
|
||||
// However, according to the HAR spec, the URL field needs to be the absolute URL.
|
||||
var scheme string
|
||||
if request.URL.Scheme != "" {
|
||||
scheme = request.URL.Scheme
|
||||
} else {
|
||||
scheme = "http"
|
||||
}
|
||||
harRequest.URL = fmt.Sprintf("%s://%s%s", scheme, request.Host, request.URL)
|
||||
}
|
||||
|
||||
totalTime := responseTime.Sub(requestTime).Round(time.Millisecond).Milliseconds()
|
||||
if totalTime < 1 {
|
||||
totalTime = 1
|
||||
|
Loading…
Reference in New Issue
Block a user