summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--handlePatches.go22
-rw-r--r--http.go29
-rw-r--r--main.go81
-rw-r--r--middleware.go77
5 files changed, 168 insertions, 47 deletions
diff --git a/Makefile b/Makefile
index d0b8b88..5a29ece 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,6 @@ BUILDTIME = $(shell date +%Y.%m.%d_%H%M)
all: build
./forged merge
- ./forged
build: goimports
GO111MODULE=off go build \
@@ -34,10 +33,9 @@ start:
systemctl start forged.service
stop:
- systemctl stop forged.service
+ -systemctl stop forged.service
-run: build
- systemctl stop forged.service
+run: build stop
./forged --daemon
# setcap 'cap_net_bind_service=+ep' forged # allow the binary to open ports below 1024
#
diff --git a/handlePatches.go b/handlePatches.go
index c9d7d38..3a0317c 100644
--- a/handlePatches.go
+++ b/handlePatches.go
@@ -1,7 +1,6 @@
package main
import (
- "io/ioutil"
"net/http"
"strings"
@@ -9,8 +8,8 @@ import (
"go.wit.com/log"
)
-func handlePatches(w http.ResponseWriter, r *http.Request) error {
- pb, err := marshalPatchesPB(r)
+func handlePatches(w http.ResponseWriter, r *http.Request, data []byte) error {
+ pb, err := marshalPatchesPB(r, data)
if err != nil {
return sendPatchesError(w, pb, err)
}
@@ -22,9 +21,10 @@ func handlePatches(w http.ResponseWriter, r *http.Request) error {
if route == "" {
route = "route was blank"
}
+ log.Info("GOT PATCHES ROUTE", route, "with # patches =", pb.Len())
if strings.HasPrefix(route, "/patches/old") {
- processPatchesPB(r, pb)
- } else if strings.HasPrefix(route, "/patches/old") {
+ processPatchesOldPB(r, pb)
+ } else if strings.HasPrefix(route, "/patches/new") {
log.Info("add new patches")
} else {
log.Info("unknown route", route)
@@ -38,18 +38,14 @@ func sendPatchesError(w http.ResponseWriter, r *forgepb.Patches, err error) erro
return nil
}
-func processPatchesPB(r *http.Request, pb *forgepb.Patches) error {
- log.Info("send error back to user")
+func processPatchesOldPB(r *http.Request, pb *forgepb.Patches) error {
+ log.Info("check out these patches")
+ pb.PrintTable()
return nil
}
-func marshalPatchesPB(r *http.Request) (*forgepb.Patches, error) {
+func marshalPatchesPB(r *http.Request, msg []byte) (*forgepb.Patches, error) {
pb := forgepb.NewPatches()
- msg, err := ioutil.ReadAll(r.Body) // Read the body as []byte
- defer r.Body.Close()
- if err != nil {
- return pb, err
- }
if err := pb.Unmarshal(msg); err != nil {
log.Info("proto.Unmarshal() failed on wire message len", len(msg), err)
diff --git a/http.go b/http.go
index 4d9a5d6..5d844e1 100644
--- a/http.go
+++ b/http.go
@@ -49,11 +49,10 @@ func whoSent(r *http.Request) string {
}
func okHandler(w http.ResponseWriter, r *http.Request) {
+ // something appears to be buggy. always get this first I guess
msg, err := ioutil.ReadAll(r.Body) // Read the body as []byte
- if err != nil {
- log.Info("ioutil.ReadAll() error =", err)
- return
- }
+ r.Body.Close()
+ log.Info("TRYING TO MARSHAL bytes:", len(msg), err)
who := whoSent(r)
@@ -76,7 +75,12 @@ func okHandler(w http.ResponseWriter, r *http.Request) {
return
}
- log.Warn("forged REQUEST URL =", requrl, "msg =", len(msg), "from =", who)
+ log.Warn("forged REQUEST URL =", requrl, "from =", who)
+
+ if strings.HasPrefix(route, "/patches/") {
+ handlePatches(w, r, msg)
+ return
+ }
if route == "/patchset" {
if err := savePatchset(w, msg); err != nil {
@@ -119,15 +123,9 @@ func okHandler(w http.ResponseWriter, r *http.Request) {
}
if route == "/GetPatchsets" {
- data, err := me.forge.Patchsets.Marshal()
- if err != nil {
- log.Info("patchsets.Marshal() to wire failed", err)
- return
- }
-
start := time.Now()
- log.Info("going to w.Write(data) with len", len(data))
- w.Write(data)
+ log.Info("going to w.Write(msg) with len", len(msg))
+ w.Write(msg)
age := shell.FormatDuration(time.Since(start))
log.Printf("Done with xfer in (%s). happy hacking!\n", age)
return
@@ -139,11 +137,6 @@ func okHandler(w http.ResponseWriter, r *http.Request) {
return
}
- if strings.HasPrefix(route, "/patches/") {
- handlePatches(w, r)
- return
- }
-
if route == "/goReference.svg" {
w.Header().Set("Content-Type", "image/svg+xml")
writeFile(w, "goReference.svg")
diff --git a/main.go b/main.go
index eb2f68f..62b4241 100644
--- a/main.go
+++ b/main.go
@@ -76,21 +76,78 @@ func main() {
}
if argv.Daemon == true {
- log.Info("Running in --daemon mode")
- http.HandleFunc("/", okHandler)
- // go https() // use caddy instead
+ mux := http.NewServeMux()
+ okHandlerFunc := http.HandlerFunc(okHandler)
+
+ // Set a limit of 50 kilobytes for requests to this handler.
+ // Adjust this value to your needs.
+ const maxUploadSize = 1025 * 1024 // 1 MB
+ mux.Handle("/", http.MaxBytesHandler(okHandlerFunc, maxUploadSize))
+
p := fmt.Sprintf(":%d", argv.Port)
- log.Println(argv.Version(), "HOSTNAME set to:", HOSTNAME)
- log.Println("Running on port", "http://localhost"+p)
- log.Println("Running on port", "http://localhost"+p+"/ipv6.png")
- err := http.ListenAndServe(p, nil)
- if err != nil {
- log.Println("Error starting server:", err)
+ log.Printf("Server starting on port %s...\n", p)
+ log.Printf("Test with: curl -d 'hello world' http://localhost:%s/\n", p)
+
+ server := &http.Server{
+ Addr: p,
+ Handler: mux,
+ ReadTimeout: 5 * time.Minute,
+ WriteTimeout: 10 * time.Second,
+ IdleTimeout: 120 * time.Second,
}
- } else {
- log.Info("--daemon was not set. Just list the patches.")
- doList()
+
+ log.Printf("Server starting on port %s with a 1 MB request body limit...\n", p)
+ if err := server.ListenAndServe(); err != nil {
+ log.Fatal("Could not start server: %s\n", err)
+ }
+ okExit("")
}
+
+ /*
+ // --- Best Practice: Create a custom http.Server ---
+ server := &http.Server{
+ Addr: p,
+ Handler: mux,
+
+ // ReadTimeout is the total time to read the entire request, including the body.
+ // Increase this to a value that can accommodate your largest expected uploads.
+ // For example, 5 minutes.
+ ReadTimeout: 5 * time.Minute,
+
+ // WriteTimeout is the maximum duration before timing out writes of the response.
+ WriteTimeout: 10 * time.Second,
+
+ // IdleTimeout is the maximum amount of time to wait for the
+ // next request when keep-alives are enabled.
+ IdleTimeout: 120 * time.Second,
+ }
+ */
+
+ /*
+ log.Println(argv.Version(), "HOSTNAME set to:", HOSTNAME)
+ log.Println("Running on port", "http://localhost"+p)
+ log.Println("Running on port", "http://localhost"+p+"/ipv6.png")
+ // if err := http.ListenAndServe(p, nil); err != nil {
+ if err := server.ListenAndServe(); err != nil {
+ log.Fatalf("Could not start server: %s\n", err)
+ }
+ /*
+ log.Info("Running in --daemon mode")
+ http.HandleFunc("/", okHandler)
+ // go https() // use caddy instead
+ p := fmt.Sprintf(":%d", argv.Port)
+ log.Println(argv.Version(), "HOSTNAME set to:", HOSTNAME)
+ log.Println("Running on port", "http://localhost"+p)
+ log.Println("Running on port", "http://localhost"+p+"/ipv6.png")
+ err := http.ListenAndServe(p, nil)
+ if err != nil {
+ log.Println("Error starting server:", err)
+ }
+ return
+ }
+ */
+ log.Info("--daemon was not set. Just list the patches.")
+ // doList()
}
func formatDuration(d time.Duration) string {
diff --git a/middleware.go b/middleware.go
new file mode 100644
index 0000000..803e162
--- /dev/null
+++ b/middleware.go
@@ -0,0 +1,77 @@
+package main
+
+import (
+ "bytes"
+ "context"
+ "io/ioutil"
+ "log"
+ "net/http"
+)
+
+// Define a key type to avoid context key collisions.
+type contextKey string
+
+const bufferedBodyKey = contextKey("bufferedBody")
+
+// bufferBodyMiddleware reads the request body and replaces it with a new reader,
+// allowing it to be read multiple times. The original body is stored in the request context.
+func bufferBodyMiddleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Only buffer if there's a body to read.
+ if r.Body == nil || r.ContentLength == 0 {
+ next.ServeHTTP(w, r)
+ return
+ }
+
+ bodyBytes, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ log.Printf("Error reading body in middleware: %v\n", err)
+ return
+ }
+ defer r.Body.Close()
+
+ // Store the buffered body in the context for downstream handlers.
+ ctx := context.WithValue(r.Context(), bufferedBodyKey, bodyBytes)
+
+ // Replace the original body with a new reader on the buffered bytes.
+ // This allows subsequent handlers to read the body again.
+ r.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
+
+ // Call the next handler in the chain with the modified request.
+ next.ServeHTTP(w, r.WithContext(ctx))
+ })
+}
+
+/*
+// okHandler is the final handler. It can now safely access the body from the context,
+// knowing that other middleware might have also read it.
+func okHandler(w http.ResponseWriter, r *http.Request) {
+ // For demonstration, we can try reading the body directly here too.
+ // The middleware ensures this is a fresh stream of the buffered data.
+ bodyFromStream, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ log.Printf("Error reading body in handler: %v", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ log.Printf("Handler read %d bytes from the request body stream.", len(bodyFromStream))
+
+ // We can also retrieve the body from the context if needed.
+ bodyFromContext, ok := r.Context().Value(bufferedBodyKey).([]byte)
+ if !ok {
+ log.Println("Could not retrieve buffered body from context.")
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ log.Printf("Handler retrieved %d bytes from context.", len(bodyFromContext))
+
+ // Prove they are the same.
+ if !bytes.Equal(bodyFromStream, bodyFromContext) {
+ log.Println("FATAL: Body from stream and context do not match!")
+ }
+
+ fmt.Fprintf(w, "Successfully read body of %d bytes.\n", len(bodyFromContext))
+}
+*/