Created
January 5, 2023 03:51
-
-
Save arlandism/5b5a3019f4bd5a7ee460b033b88546b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"os" | |
"golang.org/x/sys/unix" | |
"strings" | |
) | |
type cache struct { | |
monitoredPrefixes []string | |
routeCache map[string][]byte | |
} | |
func NewCache() *cache { | |
return &cache{ | |
monitoredPrefixes: make([]string, 0), // list of prefixes to check | |
routeCache: make(map[string][]byte), | |
} | |
} | |
func (c *cache) AddPrefixToCache(prefix string) { | |
c.monitoredPrefixes = append(c.monitoredPrefixes, prefix) | |
} | |
func (c *cache) ShouldCache(requestedRoute string) bool { | |
for _, prefix := range c.monitoredPrefixes { | |
if strings.HasPrefix(requestedRoute, prefix) { | |
return true | |
} | |
} | |
return false | |
} | |
func (c *cache) Add(route string, data []byte) { | |
c.routeCache[route] = data | |
} | |
func (c *cache) Get(route string) ([]byte, bool) { | |
if data, ok := c.routeCache[route]; ok { | |
return data, true | |
} | |
return nil, false | |
} | |
const QueueLimit = 5 | |
const BackendServerPort = 64000 | |
const ProxyPort = 64001 | |
func handleErr(context string, err error) { | |
if err != nil { | |
fmt.Printf("%s: %s ", context, err) | |
os.Exit(1) | |
} | |
} | |
func parseHTTPPath(rawRequest []byte) string { | |
reqAsStr := string(rawRequest) | |
// get first line | |
// assume a GET request | |
methodIndex := strings.Index(reqAsStr, "GET") | |
if methodIndex == -1 { | |
return "" | |
} | |
suffixIndex := strings.Index(reqAsStr, "HTTP") | |
if suffixIndex == -1 { | |
return "" | |
} | |
route := reqAsStr[methodIndex+4:suffixIndex] | |
return strings.TrimSpace(route) | |
} | |
func initBackendConnection() (int, error) { | |
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) | |
handleErr("init backend client", err) | |
err = unix.Bind(fd, &unix.SockaddrInet4{}) | |
handleErr("binding backend client", err) | |
backendAddr := &unix.SockaddrInet4{ | |
Port: BackendServerPort, | |
} | |
return fd, unix.Connect(fd, backendAddr) | |
} | |
// initialize the proxy socket, bind it, and start listening for connections | |
func initProxy() (int, error) { | |
serverSock, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) | |
handleErr("init socket", err) | |
sa := &unix.SockaddrInet4{Port: ProxyPort} | |
err = unix.Bind(serverSock, sa) | |
handleErr("binding socket", err) | |
err = unix.Listen(serverSock, QueueLimit) | |
return serverSock, err | |
} | |
func main() { | |
c := NewCache() | |
c.AddPrefixToCache("website/") | |
// start connection to server | |
backendClient, err := initBackendConnection() | |
handleErr("connecting to backend", err) | |
server, err := initProxy() | |
handleErr("initializing proxy socket", err) | |
fmt.Println("server booted") | |
for { | |
fmt.Println("waiting for client request") | |
client, _, err := unix.Accept(server) | |
clientBuf := make([]byte, 1024) | |
handleErr("accepting connection", err) | |
fmt.Println("calling recv from") | |
bytesRead, _, err := unix.Recvfrom(client, clientBuf, 0) // WAIT_ALL is the wrong flag here -- why? | |
handleErr("reading from client", err) | |
if bytesRead > 0 { | |
err = unix.Send(backendClient, clientBuf, 0) | |
handleErr("sending client request to backend", err) | |
requestedPath := parseHTTPPath(clientBuf) | |
fmt.Println("requested path is ", requestedPath) | |
if data, ok := c.Get(requestedPath); ok { | |
fmt.Println("cache hit") | |
err = unix.Send(client, data, 0) | |
} else { | |
fmt.Println("cache miss") | |
serverBuf := make([]byte, 1024) | |
serverBytesRead, _, err := unix.Recvfrom(backendClient, serverBuf, 0) | |
if serverBytesRead > 0 { | |
if c.ShouldCache(requestedPath) { | |
c.Add(requestedPath, serverBuf) | |
fmt.Println("caching") | |
} | |
err = unix.Send(client, serverBuf, 0) | |
handleErr("sending backend response back to client", err) | |
} | |
} | |
} | |
err = unix.Close(client) | |
handleErr("closing client", err) | |
} | |
err = unix.Close(server) | |
handleErr("closing server socket", err) | |
fmt.Println("Shutting down server") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment