Sessions: Go 1.7: http.Request.Context rompe el uso de gorilla / context

Creado en 4 jun. 2016  ·  22Comentarios  ·  Fuente: gorilla/sessions

El nuevo http.Request.Context() en Go 1.7 crea una copia superficial de la solicitud original que requiere que la persona que llama la guarde en sentido ascendente. Esta copia tiene una dirección diferente y, por lo tanto, tiene una clave de mapa diferente en el mapa de contexto proporcionado por gorilla / context.

Para solucionar esto en gorilla / sesiones, necesitamos hacer un cambio importante para los usuarios de Go 1.7+:

- func GetRegistry(r *http.Request) *Registry {
+ func GetRegistry(r *http.Request) (*Registry, *http.Request)
- sessions.GetRegistry(r).Get(s, name)
+ var reg *sessions.Registry
+ reg, r = sessions.GetRegistry(r)
+ sess, err := reg.Get(store, name)

Eso debería ser todo. Desafortunadamente, esto es inevitable, pero es (afortunadamente) un cambio importante en tiempo de compilación que podemos documentar claramente.

Ref: https://github.com/gorilla/mux/issues/168

breaking change enhancement

Comentario más útil

k, bueno, explicaré lo que me confunde (por tonto que parezca), ya que podría arrojar algo de claridad sobre lo que otros experimentan. :sonrisa:

Cuando yo (usuario novato) leo los documentos de la sesión, parece razonablemente sencillo hasta este momento:

Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with
context.ClearHandler or else you will leak memory! An easy way to do this is to wrap
the top-level mux when calling http.ListenAndServe:

    http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))

The ClearHandler function is provided by the gorilla/context package.

Con la aplicación que estoy desarrollando, usa Go 1.8 y no usa gorilla / mux. Entonces, esa advertencia suena como algo que debemos hacer. La pérdida de memoria obviamente es mala. Por lo tanto:

  1. "Contexto" agregado inmediato a nuestras importaciones

    • No funcionó. Después de volver a leer el párrafo anterior, menciona un paquete gorilla/context . Entonces, ese debe ser el correcto para usar.

  2. Mira la página del gorila / contexto. Ese tiene esta advertencia en su lugar:
Note: gorilla/context, having been born well before context.Context existed, does not
play well with the shallow copying of the request that http.Request.WithContext
(added to net/http Go 1.7 onwards) performs. You should either use just gorilla/context,
or moving forward, the new http.Request.Context().

Lo que hace que suene bastante desaprobado. Sin embargo, nuestra base de código no tiene context de ningún tipo en ninguna de nuestras secciones de importaciones, así que ahora no sé qué camino tomar. por ejemplo, el paquete sessions dice importar context , pero el paquete context parece que está obsoleto

  1. Es hora de preguntar.

Has respondido amablemente:

If you are using Go 1.8 only and not importing gorilla/context (which includes
packages you are using), gorilla/mux defaults to the Go 1.7 http.Request.Context
implementation.

... pero eso realmente no aclara las cosas (para mí). En nuestro caso (novato), no estamos usando gorilla / mux. Queremos usar gorilla / sessions. Entonces, no asimilar cómo entra en juego el gorila / mux que incumple allí.

De todos modos, supongo que lo que quiero decir es que debe haber una declaración clara sobre esto. El actual no parece abordar las cosas para los usuarios novatos (99.9% que usarán Go 1.7+) que aún no están usando ningún paquete gorilla .

Ojalá no esté enturbiando las cosas. :sonrisa:

Todos 22 comentarios

FWIW, actualmente estoy usando la rama de @shawnps mientras

Sin darnos cuenta, encontramos este problema cuando actualizamos recientemente a Go 1.7.3. El efecto principal fue que nuestro montón usó toda la memoria disponible y nuestra aplicación se bloqueó. Probablemente sería una buena idea agregar una nota de advertencia al archivo README principal.

El siguiente diagrama es el espacio en uso después de ejecutar un punto de referencia de 30 segundos contra una de las rutas / controladores en nuestra aplicación que almacena varias variables de sesión en una cookie.

session-leak

cc @jawnsy

Gracias por la sugerencia, una solución alternativa es guardar la sesión en request.context() manualmente y aún así limpiar el contexto de gorialla al final de la solicitud.

Estoy confundido por los hallazgos de @jbrook anteriores , y en cuanto a si es seguro usar este paquete con Go 1.8.

Si uno sigue el consejo de envolver un http.Handler con context.ClearHandler , ¿estamos a salvo de acumular estas instancias sessions.Registry en la memoria?

El context.ClearHandler usa la solicitud para limpiar los datos relacionados y es posible que no funcione en algunos casos y filtre algunos datos (depende de cualquier copia de solicitud que pueda crearse). Pero hay un método en el paquete de contexto que puede ayudar:

// Purge removes request data stored for longer than maxAge, in seconds.
// It returns the amount of requests removed.
//
// If maxAge <= 0, all request data is removed.
//
// This is only used for sanity check: in case context cleaning was not
// properly set some request data can be kept forever, consuming an increasing
// amount of memory. In case this is detected, Purge() must be called
// periodically until the problem is fixed.
func Purge(maxAge int) int {

Simplemente cree un contextPurgeMiddleware que llame a context.Purge(-1) después de cada solicitud. Además, debe asegurarse de no depender de ningún gorilla.context ya que este middleware borrará los contextos de todas las solicitudes. Solo debes usar el contexto go que.

Según mi lectura de context.Purge , especialmente cuando se llama con un argumento no http.Request s para los que hemos almacenado una sesión. Eso significa que sessions.(* CookieStore).Get crea session.Registry s, pero cada vez que terminamos con una solicitud determinada, eliminamos _todos_ estos registros, algunos de los cuales podrían estar en uso en solicitudes que todavía estamos procesando al mismo tiempo. . Entonces estamos creando cachés de manera efectiva que tiramos indiscriminadamente, posiblemente antes de que podamos hacer uso de ellos.

¿No sería un consejo más sensato simplemente evitar todo uso de sessions.GetRegistry ? Resulta que no podemos, si alguna vez pretendemos llamar sessions.Save . Tenemos que eludir esa función y usar, digamos, sessions.(*CookieStore).Save directamente, lo cual es mucho menos práctico.

Que desastre. Tenemos un intento de optimización que resultó ser un problema aún mayor, como suele suceder con ocultar cosas en variables globales, y ahora tenemos problemas para reelaborarlo para que sea compatible con versiones anteriores. No tengo una aplicación anterior que use este paquete, así que estoy más interesado en cómo romperlo para solucionarlo.

La propuesta original aquí por @elithrar suena razonable, aunque no estoy seguro todavía de cómo las personas que llaman de GetRegistry en la que estoy interested- $ sessions.(* CookieStore).Get y sessions.Save , no tuvimos suerte tienen para cambiar también.

Es probable que el registro se reduzca si pasamos al contexto.
internamente. Actuaría como una "calza" muy fina para cuando acceda
session.Values ​​o llamada session.Save (que es mayormente lo que es ahora).

Los contextos asociados con una http.Request a través de Request.WithContext
automáticamente será GC'ed y por lo tanto no necesitamos un mecanismo de "purga".

El viernes 21 de julio de 2017 a las 7:12 p.m. Steven E. Harris [email protected]
escribió:

Por mi lectura de context.Purge, especialmente cuando se llama con un no positivo
argumento
https://sourcegraph.com/github.com/gorilla/context/-/blob/context.go#L119-123 ,
borra todos los datos asociados con todas las solicitudes http.
hemos almacenado una sesión. Eso significa que las sesiones. (* CookieStore) .Get
crea session.Registrys, pero cada vez que terminamos con una solicitud determinada,
eliminamos todos estos registros, algunos de los cuales podrían estar en uso en
solicitudes que todavía estamos procesando al mismo tiempo. Entonces estamos efectivamente
creando cachés que tiramos indiscriminadamente, posiblemente antes de que podamos
hacer uso de ellos.

¿No sería un consejo más sensato simplemente evitar todo uso de
sesiones.GetRegistry? Resulta que no podemos, si alguna vez pretendemos llamar
sesiones.
https://sourcegraph.com/github.com/gorilla/sessions/-/blob/sessions.go#L189-190 .
Tenemos que eludir esa función y usar, digamos, sesiones (* CookieStore).
directamente, lo que es mucho menos práctico.

Que desastre. Tenemos un intento de optimización que resultó ser un
un problema aún mayor, como suele suceder con ocultar cosas en variables globales,
y ahora tenemos problemas para reelaborarlo para estar al revés
compatible. No tengo una aplicación anterior que use este paquete, así que estoy más
interesado en cómo romperlo para arreglarlo.

La propuesta original aquí por @elithrar https://github.com/elithrar
suena razonable, aunque todavía no estoy seguro de cómo las personas que llaman a GetRegistry
en lo que estoy interesado: sesiones. (* CookieStore). Obtener y sesiones. Guardar:
también tengo que cambiar.

-
Recibes esto porque te mencionaron.

Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/gorilla/sessions/issues/80#issuecomment-317147378 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AABIcCHZxevsfN5aDaTCBTLIlyEVR9Ehks5sQVqigaJpZM4IuFUJ
.

Creo que veo una manera de evitar todo uso del tipo Registry con el paquete tal como está, pero hacerlo requiere un estudio cuidadoso y diligencia. Estoy de acuerdo en que usar http.Request.WithContext es el camino a seguir para almacenar en caché estas cosas, pero eso obliga a las personas que llaman a lidiar con los valores http.Request copiados.

La forma en que funciona http.Request.WithContext es una modificación extraña. Me gustaría encontrar la justificación del diseño que exige que el campo "ctx" de http.Request sea ​​inmutable. Supongo que cuando uno está usando http.Request en el contexto de un servidor, en lugar de preparar una solicitud como cliente, tiene sentido tratar la solicitud como algo fijo.

Este artículo (me disculpo por vincular a Medium) muestra un ejemplo de un controlador HTTP "externo" que prepara una contribución al contexto de una solicitud y pasa el resultado de http.Request.WithContext directamente al siguiente controlador "interno" delegado. Eso parece natural. El intento de uso de este paquete de él es incómodo, porque no hay ningún controlador o delegación en juego que establezca una extensión de contención y contenido para el cambio de contexto.

Nota: refactorizar esta biblioteca y romper la API es más fácil en un
nivel técnico que trabajar dentro de las limitaciones actuales.

Sin embargo, existe una cantidad significativa de inercia en los usuarios existentes que
no utilice herramientas de proveedores: este paquete les siguió + atrae a muchos que
son nuevos en Go. Esperaba que "dep" fuera v1 ahora para que al menos pudiéramos
guiar a los usuarios a una solución probada (proveedor de la etiqueta anterior) pero, por desgracia.
El sábado 22 de julio de 2017 a las 6:53 a.m. Steven E. Harris [email protected]
escribió:

Creo que veo una manera de evitar todo uso del tipo de Registro con el
paquete como está, pero hacerlo requiere un estudio cuidadoso y diligencia. estoy de acuerdo
que usar http.Request.WithContext es el camino a seguir para almacenar en caché estos
cosas, pero eso obliga a las personas que llaman a lidiar con http.Request copiado
valores.

La forma en que funciona http.Request.WithContext es una modificación extraña. Me gustaría
para encontrar la justificación del diseño que exigía que el "ctx" de http.Request
el campo sea inmutable. Supongo que cuando uno está usando http.Request en el
contexto de un servidor, en lugar de preparar una solicitud como cliente, hace
tiene sentido tratar la solicitud como algo fijo.

Este artículo
https://medium.com/@matryer/context-has-arrived-per-request-state-in-go-1-7-4d095be83bd8
(Pido disculpas por vincular a Medium) muestra un ejemplo de un HTTP "externo"
manejador preparando una contribución al contexto de una solicitud y pasando el
resultado de http.Request.WithContext directamente en el siguiente delegado
manejador "interno". Eso parece natural. El intento de uso de este paquete es
incómodo, porque no hay una envoltura de manejador o delegación en juego que
establece una extensión de contención y contenido para el cambio de contexto.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/gorilla/sessions/issues/80#issuecomment-317185062 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AABIcDCORtCLuB5h7xon9JTyZrie4ITlks5sQf7XgaJpZM4IuFUJ
.

Durante el fin de semana escribí esta biblioteca para ayudar con el uso de _gorilla / sessions_ sin tocar session.Registry . Necesita documentación y ejemplos, pero espero que pueda obtener la esencia de la documentación a nivel de función que está allí.

Hmmm, entonces, como un programador de Golang nuevo que busca usar gorilla / sessions por primera vez ... ¿esto afecta la base de código en la que estoy trabajando? (usando Go 1.8, y no usando ya ningún paquete de contexto explícito)

El documento README actual dice:

Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
with context.ClearHandler ...

Lo que resulta significar gorilla/context ( solo ). : wink: Mirando varios problemas aquí y el PR abierto sobre documentos de memoria, parece que entra en conflicto con el paquete Go 1.7+ context .

Hmmm, ese fragmento de documento necesita actualizarse para decir algo más como:

Important Note: If you are using gorilla/content, but aren't using gorilla/mux, you
need to wrap your handlers with context.ClearHandler ...

Es un cajero automático bastante confuso. :guiño:

Si solo está utilizando Go 1.8 y no está importando gorilla / context (que
incluye los paquetes que está utilizando), gorilla / mux predeterminado en Go 1.7
Implementación de http.Request.Context.

El miércoles 2 de agosto de 2017 a las 7:42 a.m. Justin Clift [email protected]
escribió:

Hmmm, entonces, como un programador de Golang nuevo que busca usar gorilla / sessions
por primera vez ... ¿afecta esto a la base de código en la que estoy trabajando? (utilizando
Vaya a 1.8 y no esté usando ningún paquete de contexto explícito)

El documento README actual dice:

Nota importante: si no está usando gorilla / mux, debe envolver sus controladores
con context.ClearHandler ...

Lo que resulta significar gorila / contexto ( solo ). 😉 Mirando varios
problemas aquí y las relaciones públicas abiertas sobre documentos de memoria, parece que hay conflictos
con el paquete de contexto Go 1.7+.

Hmmm, ese fragmento de documento necesita actualizarse para decir algo más como:

Nota importante: si está usando gorilla / content, pero no está usando gorilla / mux,
necesita envolver sus manejadores con context.ClearHandler ...

Es un cajero automático bastante confuso. 😉

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/gorilla/sessions/issues/80#issuecomment-319693852 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AABIcLwCza_i7Hm2BWqOC4EmNJKpHqOTks5sUIrdgaJpZM4IuFUJ
.

Frio. ¿Cuál es la forma correcta de comunicar eso a los nuevos desarrolladores de Go, para que sepan si o qué necesitarán cambiar? :sonrisa:

Para ser honesto: si hubiera sabido, ya lo habría hecho. Lo que no está claro sobre
la redacción actual, dado que también vincula el paquete gorilla / context?

(Este material también es denso, por lo que es difícil para los nuevos desarrolladores
entienden, no es su culpa, estamos lidiando con una deuda tecnológica)

El miércoles 2 de agosto de 2017 a las 8:45 a. M. Justin Clift [email protected]
escribió:

Frio. ¿Cuál es la forma correcta de comunicar eso a los nuevos desarrolladores de Go?
¿Saben si necesitarán cambiar / qué necesitarán cambiar? 😄

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/gorilla/sessions/issues/80#issuecomment-319712987 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AABIcHEAAbp0Q5-FGSbGzj3TgO7IJ42Qks5sUJmugaJpZM4IuFUJ
.

k, bueno, explicaré lo que me confunde (por tonto que parezca), ya que podría arrojar algo de claridad sobre lo que otros experimentan. :sonrisa:

Cuando yo (usuario novato) leo los documentos de la sesión, parece razonablemente sencillo hasta este momento:

Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with
context.ClearHandler or else you will leak memory! An easy way to do this is to wrap
the top-level mux when calling http.ListenAndServe:

    http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))

The ClearHandler function is provided by the gorilla/context package.

Con la aplicación que estoy desarrollando, usa Go 1.8 y no usa gorilla / mux. Entonces, esa advertencia suena como algo que debemos hacer. La pérdida de memoria obviamente es mala. Por lo tanto:

  1. "Contexto" agregado inmediato a nuestras importaciones

    • No funcionó. Después de volver a leer el párrafo anterior, menciona un paquete gorilla/context . Entonces, ese debe ser el correcto para usar.

  2. Mira la página del gorila / contexto. Ese tiene esta advertencia en su lugar:
Note: gorilla/context, having been born well before context.Context existed, does not
play well with the shallow copying of the request that http.Request.WithContext
(added to net/http Go 1.7 onwards) performs. You should either use just gorilla/context,
or moving forward, the new http.Request.Context().

Lo que hace que suene bastante desaprobado. Sin embargo, nuestra base de código no tiene context de ningún tipo en ninguna de nuestras secciones de importaciones, así que ahora no sé qué camino tomar. por ejemplo, el paquete sessions dice importar context , pero el paquete context parece que está obsoleto

  1. Es hora de preguntar.

Has respondido amablemente:

If you are using Go 1.8 only and not importing gorilla/context (which includes
packages you are using), gorilla/mux defaults to the Go 1.7 http.Request.Context
implementation.

... pero eso realmente no aclara las cosas (para mí). En nuestro caso (novato), no estamos usando gorilla / mux. Queremos usar gorilla / sessions. Entonces, no asimilar cómo entra en juego el gorila / mux que incumple allí.

De todos modos, supongo que lo que quiero decir es que debe haber una declaración clara sobre esto. El actual no parece abordar las cosas para los usuarios novatos (99.9% que usarán Go 1.7+) que aún no están usando ningún paquete gorilla .

Ojalá no esté enturbiando las cosas. :sonrisa:

¿Sería viable seguir adelante con los cambios de la versión 2 en una rama alternativa en este repositorio? Eso al menos permitiría a los usuarios de dep y herramientas similares avanzar seleccionando específicamente la rama / etiqueta alternativa, sin afectar a los usuarios de herramientas que no son proveedores.

Sí, eso es lo que planeamos hacer, pero esa es la parte fácil. La parte difícil es hacer todo el trabajo para escribir el código, nuevas pruebas, asegurarse de que la nueva API tenga tiempo de hornearse, etc. :)

¿Está cerrado por el reciente PR # 175?

Correcto.
El sábado 2 de marzo de 2019 a las 3:32 a.m., Wilk [email protected] escribió:

¿Está cerrado por el reciente PR # 175?
https://github.com/gorilla/sessions/pull/175 ?

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/gorilla/sessions/issues/80#issuecomment-468912351 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AABIcNJckK9bhN3R0GYa1XbQ4wkGGgtGks5vSmFngaJpZM4IuFUJ
.

Bien, ¿planeas hacer una versión menor con este cambio o aún saltar a la v2 para esto?

Cortaré una nueva versión menor para esto en breve.

El lunes 4 de marzo de 2019 a las 1:37 a.m., Wilk [email protected] escribió:

Bien, ¿planeas hacer un lanzamiento menor con este cambio o aún saltar?
a v2 para esto?

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/gorilla/sessions/issues/80#issuecomment-469183709 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AABIcKKWgsG7MP9P1N8ZvaEtwlQuT_ebks5vTOlbgaJpZM4IuFUJ
.

¿Fue útil esta página
0 / 5 - 0 calificaciones