@@ -3,7 +3,6 @@ package server
33import (
44 "context"
55 "encoding/json"
6- "fmt"
76 "io"
87 "log"
98 "net/http"
@@ -14,6 +13,14 @@ import (
1413 "github.com/lazypower/continuity/internal/engine"
1514)
1615
16+ // jsonError writes a JSON error response. All error responses should use this
17+ // to avoid JSON injection via string concatenation.
18+ func jsonError (w http.ResponseWriter , msg string , code int ) {
19+ w .Header ().Set ("Content-Type" , "application/json" )
20+ w .WriteHeader (code )
21+ json .NewEncoder (w ).Encode (map [string ]string {"error" : msg })
22+ }
23+
1724func (s * Server ) handleSessionInit (w http.ResponseWriter , r * http.Request ) {
1825 var req struct {
1926 SessionID string `json:"session_id"`
@@ -30,7 +37,8 @@ func (s *Server) handleSessionInit(w http.ResponseWriter, r *http.Request) {
3037
3138 sess , err := s .db .InitSession (req .SessionID , req .Project )
3239 if err != nil {
33- http .Error (w , `{"error":"` + err .Error ()+ `"}` , http .StatusInternalServerError )
40+ log .Printf ("init session: %v" , err )
41+ jsonError (w , "internal error" , http .StatusInternalServerError )
3442 return
3543 }
3644
@@ -61,7 +69,8 @@ func (s *Server) handleAddObservation(w http.ResponseWriter, r *http.Request) {
6169 }
6270
6371 if err := s .db .AddObservation (sessionID , req .ToolName , req .ToolInput , req .ToolResponse ); err != nil {
64- http .Error (w , `{"error":"` + err .Error ()+ `"}` , http .StatusInternalServerError )
72+ log .Printf ("add observation: %v" , err )
73+ jsonError (w , "internal error" , http .StatusInternalServerError )
6574 return
6675 }
6776
@@ -79,8 +88,9 @@ func (s *Server) handleCompleteSession(w http.ResponseWriter, r *http.Request) {
7988 if err := s .db .CompleteSession (sessionID ); err != nil {
8089 // Not finding an active session is not a server error — the session
8190 // may have already been completed or never existed. Log but return OK.
91+ log .Printf ("complete session: %v" , err )
8292 w .Header ().Set ("Content-Type" , "application/json" )
83- json .NewEncoder (w ).Encode (map [string ]string {"status" : "ok" , "note" : err . Error () })
93+ json .NewEncoder (w ).Encode (map [string ]string {"status" : "ok" })
8494 return
8595 }
8696
@@ -92,7 +102,8 @@ func (s *Server) handleEndSession(w http.ResponseWriter, r *http.Request) {
92102 sessionID := chi .URLParam (r , "sessionID" )
93103
94104 if err := s .db .EndSession (sessionID ); err != nil {
95- http .Error (w , `{"error":"` + err .Error ()+ `"}` , http .StatusInternalServerError )
105+ log .Printf ("end session: %v" , err )
106+ jsonError (w , "internal error" , http .StatusInternalServerError )
96107 return
97108 }
98109
@@ -180,9 +191,8 @@ func (s *Server) handleSignal(w http.ResponseWriter, r *http.Request) {
180191func (s * Server ) handleUnmarkEmptyExtractions (w http.ResponseWriter , r * http.Request ) {
181192 n , err := s .db .UnmarkEmptyExtractions ()
182193 if err != nil {
183- w .Header ().Set ("Content-Type" , "application/json" )
184- w .WriteHeader (http .StatusInternalServerError )
185- json .NewEncoder (w ).Encode (map [string ]string {"error" : err .Error ()})
194+ log .Printf ("unmark empty extractions: %v" , err )
195+ jsonError (w , "internal error" , http .StatusInternalServerError )
186196 return
187197 }
188198
@@ -204,15 +214,12 @@ func (s *Server) handleGetMemory(w http.ResponseWriter, r *http.Request) {
204214
205215 node , err := s .db .GetNodeByURI (uri )
206216 if err != nil {
207- w .Header ().Set ("Content-Type" , "application/json" )
208- w .WriteHeader (http .StatusInternalServerError )
209- json .NewEncoder (w ).Encode (map [string ]string {"error" : err .Error ()})
217+ log .Printf ("get memory: %v" , err )
218+ jsonError (w , "internal error" , http .StatusInternalServerError )
210219 return
211220 }
212221 if node == nil {
213- w .Header ().Set ("Content-Type" , "application/json" )
214- w .WriteHeader (http .StatusNotFound )
215- json .NewEncoder (w ).Encode (map [string ]string {"error" : "memory not found: " + uri })
222+ jsonError (w , "memory not found" , http .StatusNotFound )
216223 return
217224 }
218225
@@ -268,9 +275,8 @@ func (s *Server) handleRemember(w http.ResponseWriter, r *http.Request) {
268275 SessionID : req .SessionID ,
269276 })
270277 if err != nil {
271- w .Header ().Set ("Content-Type" , "application/json" )
272- w .WriteHeader (http .StatusBadRequest )
273- json .NewEncoder (w ).Encode (map [string ]string {"error" : err .Error ()})
278+ log .Printf ("remember: %v" , err )
279+ jsonError (w , "failed to store memory" , http .StatusBadRequest )
274280 return
275281 }
276282
@@ -304,6 +310,9 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
304310 limit = n
305311 }
306312 }
313+ if limit > 100 {
314+ limit = 100
315+ }
307316
308317 category := r .URL .Query ().Get ("category" )
309318
@@ -333,7 +342,8 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
333342 }
334343
335344 if err != nil {
336- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
345+ log .Printf ("search: %v" , err )
346+ jsonError (w , "internal error" , http .StatusInternalServerError )
337347 return
338348 }
339349
@@ -384,7 +394,8 @@ func (s *Server) handleTimeline(w http.ResponseWriter, r *http.Request) {
384394
385395 sessions , err := s .db .GetSessionsSince (sinceMs )
386396 if err != nil {
387- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
397+ log .Printf ("timeline: %v" , err )
398+ jsonError (w , "internal error" , http .StatusInternalServerError )
388399 return
389400 }
390401
@@ -415,7 +426,8 @@ func (s *Server) handleTimeline(w http.ResponseWriter, r *http.Request) {
415426func (s * Server ) handleProfile (w http.ResponseWriter , r * http.Request ) {
416427 relProfile , err := s .db .GetNodeByURI ("mem://user/profile/communication" )
417428 if err != nil {
418- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
429+ log .Printf ("profile: %v" , err )
430+ jsonError (w , "internal error" , http .StatusInternalServerError )
419431 return
420432 }
421433
@@ -476,7 +488,8 @@ func (s *Server) handleTree(w http.ResponseWriter, r *http.Request) {
476488 // List roots
477489 roots , err := s .db .ListRoots ()
478490 if err != nil {
479- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
491+ log .Printf ("tree roots: %v" , err )
492+ jsonError (w , "internal error" , http .StatusInternalServerError )
480493 return
481494 }
482495 for _ , r := range roots {
@@ -492,7 +505,8 @@ func (s *Server) handleTree(w http.ResponseWriter, r *http.Request) {
492505 // List children
493506 children , err := s .db .GetChildren (uri )
494507 if err != nil {
495- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
508+ log .Printf ("tree children: %v" , err )
509+ jsonError (w , "internal error" , http .StatusInternalServerError )
496510 return
497511 }
498512 for _ , c := range children {
0 commit comments