@@ -368,43 +368,61 @@ type HttpClient struct {
368
368
client * http.Client
369
369
}
370
370
371
+ // Get recupera la clave <in.Group>/<in.Key> desde el peer remoto y
372
+ // coloca el resultado en 'out'. Se asegura de que el buffer que
373
+ // viene del sync.Pool NO quede referenciado por la caché.
371
374
func (h * HttpClient ) Get (ctx context.Context , in * pb.GetRequest , out * pb.GetResponse ) error {
375
+ // ---------- 1. lanzar la petición --------------------------
372
376
var res http.Response
373
377
if err := h .makeRequest (ctx , http .MethodGet , in , nil , & res ); err != nil {
374
378
return err
375
379
}
376
380
defer res .Body .Close ()
381
+
382
+ // ---------- 2. gestionar códigos de error ------------------
377
383
if res .StatusCode != http .StatusOK {
378
- // Limit reading the error body to max 1 MiB
384
+ // leemos (máx. 1 MiB) el cuerpo de error para incluirlo en el msg
379
385
msg , _ := io .ReadAll (io .LimitReader (res .Body , 1024 * 1024 ))
380
386
381
- if res .StatusCode == http .StatusNotFound {
387
+ switch res .StatusCode {
388
+ case http .StatusNotFound :
382
389
return & ErrNotFound {Msg : strings .Trim (string (msg ), "\n " )}
383
- }
384
-
385
- if res .StatusCode == http .StatusServiceUnavailable {
390
+ case http .StatusServiceUnavailable :
386
391
return & ErrRemoteCall {Msg : strings .Trim (string (msg ), "\n " )}
392
+ default :
393
+ return fmt .Errorf ("server returned: %v, %v" , res .Status , string (msg ))
387
394
}
388
-
389
- return fmt .Errorf ("server returned: %v, %v" , res .Status , string (msg ))
390
395
}
391
396
397
+ // ---------- 3. leer la respuesta en un *bytes.Buffer -------
392
398
b := bufferPool .Get ().(* bytes.Buffer )
393
399
b .Reset ()
394
400
defer func () {
401
+ // devolvemos el buffer al pool SOLO si no es gigante
395
402
if b .Cap () <= maxBufferSize {
396
- bufferPool .Put (b ) // único Put
403
+ bufferPool .Put (b )
397
404
}
398
405
}()
399
406
400
- _ , err := io .Copy (b , res .Body )
401
- if err != nil {
407
+ if _ , err := io .Copy (b , res .Body ); err != nil {
402
408
return fmt .Errorf ("reading response body: %v" , err )
403
409
}
404
- err = proto .Unmarshal (b .Bytes (), out )
405
- if err != nil {
410
+
411
+ // ---------- 4. des-serializar el proto ---------------------
412
+ if err := proto .Unmarshal (b .Bytes (), out ); err != nil {
406
413
return fmt .Errorf ("decoding response body: %v" , err )
407
414
}
415
+
416
+ // ---------- 5. copia defensiva para romper la referencia ---
417
+ // out.Value apunta al array interno de 'b'. Copiamos para
418
+ // que la caché no retenga ese array y el buffer pueda
419
+ // reutilizarse / ser liberado por el GC.
420
+ if out .Value != nil {
421
+ val := make ([]byte , len (out .Value ))
422
+ copy (val , out .Value )
423
+ out .Value = val
424
+ }
425
+
408
426
return nil
409
427
}
410
428
0 commit comments