From 2015f84fb4a11f83452117cfb607e47c1d0c251e Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Fri, 5 Sep 2025 07:10:02 -0500 Subject: [PATCH] add http headers to protobuf --- http.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++ patchset.config.go | 13 +++++++++++ patchset.proto | 15 ++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/http.go b/http.go index f983220..0e3a56b 100644 --- a/http.go +++ b/http.go @@ -5,8 +5,10 @@ package forgepb import ( "bytes" "io/ioutil" + "net" "net/http" "os/user" + "strings" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" @@ -92,3 +94,55 @@ func (f *Forge) UpdatePB(check *gitpb.Repos) (*gitpb.Repos, error) { return queryPB.SubmitReposPB(url) } + +// HTTPRequestToProto converts an *http.Request to our custom HttpRequest protobuf message. +func (pb *Patches) AddHttpToPB(r *http.Request) error { + if pb == nil { + return log.Errorf("AddHttpToPB() pb was nil") + } + // Convert the header map. http.Header is a map[string][]string. + // We'll just take the first value for each header for simplicity. + headers := make(map[string]string) + for name, values := range r.Header { + if len(values) > 0 { + headers[name] = strings.Join(values, "\n") + } + } + + pb.HttpRequest = &Patches_HttpRequest{ + Method: r.Method, + Url: r.URL.String(), + Proto: r.Proto, + Headers: headers, + RemoteAddr: getClientIP(r), + Host: r.Host, + Hostname: r.Header.Get("hostname"), + } + return nil +} + +func getIpSimple(r *http.Request) string { + host, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + log.Printf("could not split host port: %v", err) + return r.RemoteAddr // Fallback + } + return host +} + +// getClientIP inspects the request for common headers to find the true client IP. +func getClientIP(r *http.Request) string { + // Caddy sets the X-Forwarded-For header. + if forwardedFor := r.Header.Get("X-Forwarded-For"); forwardedFor != "" { + // The header can be a comma-separated list of IPs. The first one is the original client. + ips := strings.Split(forwardedFor, ",") + return strings.TrimSpace(ips[0]) + } + + // Fallback to RemoteAddr if the header is not present. + host, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + return r.RemoteAddr + } + return host +} diff --git a/patchset.config.go b/patchset.config.go index 4f8eedf..6627141 100644 --- a/patchset.config.go +++ b/patchset.config.go @@ -32,6 +32,19 @@ func (f *Forge) LoadPatchsets() error { return nil } +func (f *Forge) InitPatchsets() error { + if err := f.LoadPatchsets(); err == nil { + return nil + } else { + log.Info("LoadPatchsets() failed", err) + } + // TODO: check if Unmarshal failed here + f.Patchsets = NewPatchsets() + tmp := f.findAutoPatchset() // makes the default setting + f.Patchsets.Append(tmp) + return f.SavePatchsets() +} + func (f *Forge) SavePatchsets() error { filename := filepath.Join(f.patchDir, "all-patches.pb") regfile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) diff --git a/patchset.proto b/patchset.proto index 4c61127..edcd77d 100644 --- a/patchset.proto +++ b/patchset.proto @@ -60,11 +60,24 @@ message Patch { // this is a "PATCH: [1/x]" series message Patches { // `autogenpb:marshal` `autogenpb:gui:Patch` + message HttpRequest { // HttpRequest represents the essential fields of an incoming HTTP request. + string method = 1; // The request method, e.g., "GET", "POST". + string url = 2; // The full URL of the request, including scheme, host, path, and query string. + string route = 3; // just the route: "/add/" or "/find/" + string proto = 4; // The protocol version, e.g., "HTTP/1.1", "HTTP/2.0". + map headers = 5; // The map of request headers. Header names are case-insensitive, + string remoteAddr = 6; // The remote IP address of the client, after resolving proxies. + string host = 7; // The host on which the URL is sought (www.wit.com) + string hostname = 8; // The hostname of the client if passed from the client (mylaptop.fun.me) + bytes body = 9; // The request body as raw bytes. + string namespace = 10; // When the body is a pb (always!). This is the pb namespace ("go.wit.com/lib/protobuf/virtpb") + } string uuid = 1; // `autogenpb:uuid:2679065e-c81d-4a00-aca4-03c158a834fb` string version = 2; // `autogenpb:version:v2.0.0` repeated Patch Patches = 3; + HttpRequest httpRequest = 4; // who connected // rename httpRequest? This might make sense in our case + string Error = 5; // when passing these around, if there is an error, store it here } - message Patchset { // `autogenpb:marshal` Patches patches = 1; // string name = 2; // `autogenpb:sort`