Skip to content

Commit

Permalink
handler: Implement request body analysis
Browse files Browse the repository at this point in the history
Analyze request body to determine what command and data git is
sending to the upstream remote.  This should help us determine
how the future cache key would look like.
  • Loading branch information
Son Luong Ngoc authored and sluongng committed Jul 15, 2021
1 parent 749cf04 commit 02eca50
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 2 deletions.
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/sluongng/git-cache

go 1.16

require github.com/matryer/is v1.4.0 // indirect
require (
github.com/google/gitprotocolio v0.0.0-20210704173409-b5a56823ae52
github.com/matryer/is v1.4.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
github.com/google/gitprotocolio v0.0.0-20210704173409-b5a56823ae52 h1:/a887PZoXM9aLYwXS2ufq+Gnr5KUg5gm8gBoxKjnQuo=
github.com/google/gitprotocolio v0.0.0-20210704173409-b5a56823ae52/go.mod h1:O2KL6wjnwAu7+dPSZhhrjp35gFdyoHlP/f6dhc9YupY=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
78 changes: 77 additions & 1 deletion handler.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package main

import (
"bytes"
"compress/gzip"
"encoding/json"
"io"
"log"
"net/http"
"net/http/httputil"
"net/url"

"github.com/google/gitprotocolio"
)

const (
Expand Down Expand Up @@ -38,7 +44,77 @@ func (s *server) ReceivePackHandler() http.HandlerFunc {
// - git-archive
func (s *server) UploadPackHandler() http.HandlerFunc {
log.Println("UploadPackHandler")
return s.proxyHandler()
return func(w http.ResponseWriter, r *http.Request) {
proxyHandler := s.proxyHandler()

// Middleware layer analyzes the request body to determine the command
// and body chunk to determine:
//
// - Should the response be cached?
// - What would be the caching key?
// - Does a valid cache entry exists in the store?
//
// For now this is accomplished by consuming the entire request body
// into memory. In the future, we should be smart about when to stop
// and/or be more selective on which requests to analyze the body.

// Read from request Body
b, err := io.ReadAll(r.Body)
if err != nil {
log.Fatalln("Unable to read body: %w", err)
}

// Handle compression
var bodyReader io.Reader
if r.Header.Get("Content-Encoding") == "gzip" {
gzipReader, err := gzip.NewReader(bytes.NewReader(b))
if err != nil {
log.Fatalln("Unable to read body: %w", err)
}

bodyReader = gzipReader
} else {
bodyReader = bytes.NewReader(b)
}

// Parse and handle git protocol command and content
scanner := gitprotocolio.NewProtocolV2Request(bodyReader)
for {
if ok := scanner.Scan(); !ok {
if scanner.Err() != nil {
log.Printf("Unable to scan request: %s\n", scanner.Err())
}

break
}

c := scanner.Chunk()

// Skipping chunks without command for now as they are noisy
// TODO: find use for these extra chunks
if c.Command == "" {
continue
}

data, err := json.MarshalIndent(c, "", " ")
if err != nil {
log.Fatalln("Unable to unmarshal chunk: %w", err)
}
log.Printf("chunk: %s", string(data))

if c.EndRequest {
break
}
}

// Rewrite the read bytes into the body to upstream request
// this is needed as the request body buffer was closed after
// previous read.
r.Body = io.NopCloser(bytes.NewReader(b))

// Pass the original request to proxy to upstream
proxyHandler(w, r)
}
}

func (s *server) proxyHandler() http.HandlerFunc {
Expand Down

0 comments on commit 02eca50

Please sign in to comment.