diff --git a/main.go b/main.go index 904902b..afdbf6d 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ // Maps HTTP methods to 9P file operations: // // GET /path - read file content or list directory entries -// PUT /path - write request body to file +// PUT /path - write request body to file (truncate) // POST /path - create file (name = last path element) // DELETE /path - remove file // HEAD /path - stat file (metadata in headers) @@ -210,7 +210,7 @@ func handler(w http.ResponseWriter, r *http.Request) { } // Read-only paths — only GET and HEAD allowed. switch first { - case "", "a", "m", "t", "sk": + case "", "sk": if r.Method != http.MethodGet && r.Method != http.MethodHead { writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "read-only"}) return @@ -241,6 +241,8 @@ func handler(w http.ResponseWriter, r *http.Request) { return } handleWrite(w, r, fsys, p) + case http.MethodPut: + handlePut(w, r, fsys, p) case http.MethodDelete: handleRemove(w, fsys, p) case http.MethodPatch: @@ -252,11 +254,12 @@ func handler(w http.ResponseWriter, r *http.Request) { } } -var allowedMethods = "GET, HEAD, POST, DELETE, PATCH, OPTIONS" +var allowedMethods = "GET, HEAD, PUT, POST, DELETE, PATCH, OPTIONS" var methodDescriptions = map[string]string{ "GET": "read file content or list directory entries", "HEAD": "stat file (metadata in response headers)", + "PUT": "write raw body to file (truncate)", "POST": "write to file or trigger action", "DELETE": "remove file or session", "PATCH": "rename via JSON {\"name\": \"newname\"}", @@ -421,6 +424,26 @@ func handleStat(w http.ResponseWriter, fsys *client.Fsys, p string) { w.Header().Set("Content-Type", "application/json") } +func handlePut(w http.ResponseWriter, r *http.Request, fsys *client.Fsys, p string) { + body, err := io.ReadAll(r.Body) + if err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) + return + } + fid, err := fsys.Open(p, plan9.OWRITE|plan9.OTRUNC) + if err != nil { + writeJSON(w, http.StatusNotFound, map[string]string{"error": err.Error()}) + return + } + n, err := fid.Write(body) + fid.Close() + if err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + writeJSON(w, http.StatusOK, map[string]int{"bytes_written": n}) +} + func handleWrite(w http.ResponseWriter, r *http.Request, fsys *client.Fsys, p string) { var m map[string]any if err := json.NewDecoder(r.Body).Decode(&m); err != nil {