Ricardo,
Y si pruebas de usar sesiones ?
Antes de lanzar curl pinemos una variable de sesion a .t. y cuando acabe a .f.
El sistema chequea cada vez la variable de sesion, si esta a .t. no deja pasar o se espera.
Como lo ves ?
Libcurl - multiple requests crashing Apache
- charly
- Mensajes: 145
- Registered for: 3 years 7 months
Salutacions, saludos, regards.
Charly
"...programar es fácil, hacer programas es difícil..."
https://httpd2.blogspot.com/
https://forum.modharbour.app
Charly
"...programar es fácil, hacer programas es difícil..."
https://httpd2.blogspot.com/
https://forum.modharbour.app
- ricardo arraes
- Mensajes: 87
- Registered for: 3 years 7 months
Got it, Charly. Setting a flag manually as true or false. I think it should work, I’ll try it...
Should I create this flag inside mercury TApp class, in order to use it everywhere in my application? What do you think?
Should I create this flag inside mercury TApp class, in order to use it everywhere in my application? What do you think?
The work always comes before the belief
- charly
- Mensajes: 145
- Registered for: 3 years 7 months
R,
>> Should I create this flag inside mercury TApp class, in order to use it everywhere in my application? What do you think?
No, because every time you execute a request , everything is reinitialized. You should use sessions, like usage in TWeb. This records sessions on disk. Each session is unique per user. If you want I can tell you which example tweb modules use this technique and what you should look at
twebsession.prg
You can see about it -> viewtopic.php?f=7&t=6
ant you can see examples: test_session.prg, test_session_end.prg, test_session_read.prg
C.
>> Should I create this flag inside mercury TApp class, in order to use it everywhere in my application? What do you think?
No, because every time you execute a request , everything is reinitialized. You should use sessions, like usage in TWeb. This records sessions on disk. Each session is unique per user. If you want I can tell you which example tweb modules use this technique and what you should look at
twebsession.prg
Código: Seleccionar todo
// ------------------------------------------------------------------------------
// Title......: Session
// Description: Módulo de sesiones
// Date.......: 16/06/2019
// Last Upd...: 21/10/2020
// ------------------------------------------------------------------------------
// InitSession() - Creacion de una Session. Una vez creada la session puedes
// almacenar/recuperar variables
//
// Session() - Setter/Getter . Almacena/recupera los valores de las variables
// Session( <NameVar>, [<uValue>] )
// Si no pasamos paràmetros devolvemos si existe session -> .t./.f.
//
// EndSession() - Eliminar una session del servidor
//
// ------------------------------------------------------------------------------
// Ejemplos por orden de ejecucion:
//
// test_session.prg - Crear session y salvar variables
// test_session_read.prg - Crear session y recuperar variables almacenadas
// test_session_end.prg - Crear session y eliminar session
// ------------------------------------------------------------------------------
#include 'hbclass.ch'
#include 'hboo.ch'
#define SESSION_NAME 'HRBSESSID'
#define SESSION_PREFIX 'sess_'
#define SESSION_EXPIRED 3600
function Redirect( cUrl )
DEFAULT cUrl TO ''
?? "<script>window.location.replace( '" + cUrl + "');</script>"
retu nil
function InitSession( cName, nExpired )
local o := TWebSession():New( cName, nExpired )
o:InitSession()
retu nil
function Session( cKey, uValue )
local o := TWebSession():New()
retu o:Session( cKey, uValue )
function Is_Session( cName )
local o := TWebSession():New( cName )
retu o:Is_Session()
function EndSession( cName )
local o := TWebSession():New( cName )
o:EndSession()
retu nil
CLASS TWebSession
CLASSDATA lInit INIT .F.
CLASSDATA cSessionName INIT SESSION_NAME
CLASSDATA hSession INIT NIL
CLASSDATA cSID INIT ''
CLASSDATA lIs_Session INIT .F.
CLASSDATA nExpired INIT SESSION_EXPIRED
CLASSDATA cDirTmp INIT ''
DATA cSeed INIT 'MySesSiOn'
METHOD New() CONSTRUCTOR
METHOD InitSession()
METHOD Session( cKey, uValue )
METHOD EndSession()
METHOD SaveSession()
METHOD Get_Session()
METHOD StrSession()
METHOD SetSession()
METHOD Is_Session() INLINE ::lIs_Session
METHOD Garbage()
METHOD Info()
ENDCLASS
METHOD New( cName, nExpired ) CLASS TWebSession
DEFAULT cName TO ''
DEFAULT nExpired TO SESSION_EXPIRED
::cDirTmp := TWebGlobal( 'session_path' ) + if( "Linux" $ OS(), '\', '/' )
::cSeed := if( !empty( TWebGlobal( 'session_key' ) ), TWebGlobal( 'session_key' ), ::cSeed )
::cSessionName := if( !empty( cName ), cName , SESSION_NAME )
::nExpired := nExpired
if !::lInit
::lInit := .T.
::Get_Session()
endif
retu Self
METHOD InitSession() CLASS TWebSession
local cSession, cFile
if ::lIs_Session
// Actualizamos tiempo de la sesion. Tambien esta a nivel cookie...
::hSession[ 'expired' ] := seconds() + SESSION_EXPIRED
else
// Si no existe una Session la iniciamos...
::SetSession()
::StrSession()
::lIs_Session := .T.
endif
// Renovamos la cookie, cada vez que ejecutamos con el tiempo renovado...
SetCookie( ::cSessionName, ::cSID, ::nExpired )
retu nil
// ------------------------------------------------------------------------------
METHOD Session( cKey, uValue ) CLASS TWebSession
if !::lIs_Session
retu ''
endif
if ValType( uValue ) <> 'U' // SETTER
if !empty( cKey )
::hSession[ 'data' ][ cKey ] := uValue
endif
else // GETTER
if ( hb_HHasKey( ::hSession[ 'data' ], cKey ) )
retu ::hSession[ 'data' ][ cKey ]
else
retu ''
endif
endif
retu nil
// ------------------------------------------------------------------------------
METHOD EndSession() CLASS TWebSession
local cFile
if !::lIs_Session
retu nil
endif
if ( Valtype( ::hSession ) == 'H' )
// Enviaremos la cookie con tiempo expirado. Esto la eliminara y no se volverá a enviar...
setcookie( ::cSessionName, ::cSID, -1 )
// Eliminamos Session de disco
cFile := ::cDirTmp + SESSION_PREFIX + ::cSID
fErase( cFile )
endif
// Eliminamos variable GLOBAL de Session
::hSession := NIL
::cSID := ''
::lIs_Session := .F.
retu nil
// ------------------------------------------------------------------------------
METHOD SaveSession() CLASS TWebSession
local cSession, cFile, lSave, cKey, cData
if !::lIs_Session
retu ''
endif
cSession := hb_jsonencode( ::hSession )
cKey := hb_blowfishKey( ::cSeed )
cData := hb_blowfishEncrypt( cKey, cSession )
// Podriem aqui encryptar la session (Pendent)
cFile := ::cDirTmp + SESSION_PREFIX + ::cSID
lSave := hb_memowrit( cFile, cData )
retu NIL
// ------------------------------------------------------------------------------
METHOD SetSession() CLASS TWebSession
::cSID := hb_MD5( DToS( Date() ) + Time() + Str( hb_Random(), 15, 12 ) )
retu nil
// ------------------------------------------------------------------------------
METHOD Get_Session() CLASS TWebSession
local hGet := AP_GetPairs()
local lCookie := .F.
local cFile, cSession, cData
::lIs_Session := .F.
::cSID := hb_HGetDef( hGet, ::cSessionName, '' )
if ! empty( ::cSID ) // GET
lCookie := .t.
else
::cSID := hb_HGetDef( getCookies(), ::cSessionName, '' )
lCookie := !empty( ::cSID )
endif
if lCookie
// Recuperar contenido del fichero de session...
cFile := ::cDirTmp + SESSION_PREFIX + ::cSID
if File( cFile )
cSession := hb_Memoread( cFile )
// Si hay contenido Deserializaremos...
if ( !empty( cSession ) )
cData := hb_blowfishDecrypt( hb_blowfishKey( ::cSeed ), cSession )
// Aui podriem desencryptar cSession... (pendent)
::hSession := hb_jsondecode( cData )
if Valtype( ::hSession ) == 'H'
// Validaremos estructura
if ( hb_HHasKey( ::hSession, 'ip' ) .and. ;
hb_HHasKey( ::hSession, 'sid' ) .and. ;
hb_HHasKey( ::hSession, 'expired' ) .and. ;
hb_HHasKey( ::hSession, 'data' ) )
if ::hSession[ 'expired' ] >= seconds() .and. ;
::hSession[ 'ip' ] == AP_USERIP()
::lIs_Session := .t.
endif
endif
endif
endif
endif
endif
retu ::lIs_Session
// ------------------------------------------------------------------------------
METHOD StrSession() CLASS TWebSession
::hSession := { => }
::hSession[ 'ip' ] := AP_USERIP() // La Ip no es fiable. Pueden usar proxy
::hSession[ 'sid' ] := ::cSID
::hSession[ 'expired'] := seconds() + ::nExpired
::hSession[ 'data' ] := { => }
retu nil
// ------------------------------------------------------------------------------
// Delete files <= dMaxDate. Default 1 day ago
METHOD Garbage( dMaxDate ) CLASS TWebSession
local aFiles := Directory( ::cDirTmp + '*.*' )
local nFiles := len( aFiles )
local nI
DEFAULT dMaxDate TO Date()-1
for nI := 1 to nFiles
if aFiles[nI][3] <= dMaxDate
fErase( ::cDirTmp + aFiles[nI][1] )
endif
next
retu nil
// ------------------------------------------------------------------------------
// Delete files <= dMaxDate. Default 1 day ago
METHOD Info() CLASS TWebSession
local aFiles := Directory( ::cDirTmp + '*.*' )
local nFiles := len( aFiles )
local nBytes := 0
local nI
local hInfo := {=>}
for nI := 1 to nFiles
nBytes += aFiles[nI][2]
next
hInfo[ 'files' ] := nFiles
hInfo[ 'bytes' ] := nBytes
retu hInfo
// ------------------------------------------------------------------------------
// Creamos Instancia TWebSession() y Salvamos si es que tenemos session abierta
EXIT PROCEDURE __ExitSession()
local o := TWebSession():New()
o:SaveSession()
retu
You can see about it -> viewtopic.php?f=7&t=6
ant you can see examples: test_session.prg, test_session_end.prg, test_session_read.prg
C.
Salutacions, saludos, regards.
Charly
"...programar es fácil, hacer programas es difícil..."
https://httpd2.blogspot.com/
https://forum.modharbour.app
Charly
"...programar es fácil, hacer programas es difícil..."
https://httpd2.blogspot.com/
https://forum.modharbour.app
- ricardo arraes
- Mensajes: 87
- Registered for: 3 years 7 months
Oh, now I got it!!
Thanks charly! Probably should work properly.
Yes, sure, tell me the example.
Thank you, my friend, Imma test it and post here if it worked
Thanks charly! Probably should work properly.
Yes, sure, tell me the example.
Thank you, my friend, Imma test it and post here if it worked
The work always comes before the belief
-
- Site Admin
- Mensajes: 315
- Registered for: 3 years 7 months
Creo que en todo esto hay algo que se me escapa
Explicármelo como si fuese para "dummies", gracias
No se podría cambiar el estilo al botón cuando es pulsado? ( seguramente con javascript ) y recuperar a su estilo normal cuando el proceso se ha terminado? ( seguro que no estoy entendiendo bien el problema )
Explicármelo como si fuese para "dummies", gracias
No se podría cambiar el estilo al botón cuando es pulsado? ( seguramente con javascript ) y recuperar a su estilo normal cuando el proceso se ha terminado? ( seguro que no estoy entendiendo bien el problema )
Código: Seleccionar todo
.disable{
cursor: not-allowed;
pointer-events: none;
}
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
- ricardo arraes
- Mensajes: 87
- Registered for: 3 years 7 months
Hi Cristobal! Gracias!
unfortunately this is not a solution because refreshing the browser/URL generates the same error... the problem is not the "multiclicking" itself, the problem is that libcurl is not managing these multiple requests efficiently and then it's crashing apache.
I'm trying to implement what Charly told me, let's see if it works!
unfortunately this is not a solution because refreshing the browser/URL generates the same error... the problem is not the "multiclicking" itself, the problem is that libcurl is not managing these multiple requests efficiently and then it's crashing apache.
I'm trying to implement what Charly told me, let's see if it works!
The work always comes before the belief
- ricardo arraes
- Mensajes: 87
- Registered for: 3 years 7 months
Hey everybody...
I found out that the solution is WAAAAAY simpler than we were discussing...
ridiculously simple...
First of all, let's go back to the libcurl documentation...
we can see right in the introduction that libcurl is THREAD-FREE.
*which means that libcurl has no problem with parallel requests
https://curl.se/libcurl/
So why is this problem happening???
well, here we can see that "are a few exceptions" for that thread-free behaviour.
https://curl.se/libcurl/features.html#thread
In this other page right here we can see that curl_global* methods are NOT thread-safe...
https://curl.se/libcurl/c/threadsafe.html
with that been said, we just found out the reason why this is happening...
we gotta take theses curl_global* methods off like that:
and now it works properly...
it's really hard to believe that it was THAT simple...
I found out that the solution is WAAAAAY simpler than we were discussing...
ridiculously simple...
First of all, let's go back to the libcurl documentation...
we can see right in the introduction that libcurl is THREAD-FREE.
*which means that libcurl has no problem with parallel requests
https://curl.se/libcurl/
So why is this problem happening???
well, here we can see that "are a few exceptions" for that thread-free behaviour.
https://curl.se/libcurl/features.html#thread
In this other page right here we can see that curl_global* methods are NOT thread-safe...
https://curl.se/libcurl/c/threadsafe.html
with that been said, we just found out the reason why this is happening...
we gotta take theses curl_global* methods off like that:
Código: Seleccionar todo
//curl_global_init(HB_CURL_GLOBAL_ALL)
if ! empty( hCurl := curl_easy_init() )
IF .NOT. Empty(cUrl)
IF cHeader # NIL .AND. .NOT. Empty(cHeader)
curl_easy_setopt( hCurl, HB_CURLOPT_HTTPHEADER, {"Authorization: "+cHeader} )
ENDIF
curl_easy_setopt( hCurl, HB_CURLOPT_URL, cUrl )
IF cHttp="POST"
IF lHash # NIL .AND. lHash
curl_easy_setopt( hCurl, HB_CURLOPT_POSTFIELDS, "content="+curl_easy_escape(hCurl,hData))
ENDIF
ENDIF
curl_easy_setopt( hCurl, HB_CURLOPT_DL_BUFF_SETUP )
IF (nret:=curl_easy_perform( hCurl )) == 0
uValue := curl_easy_dl_buff_get( hCurl )
ENDIF
ENDIF
ENDIF
// curl_global_cleanup()
curl_easy_cleanup(hCurl)
it's really hard to believe that it was THAT simple...
The work always comes before the belief
-
- Site Admin
- Mensajes: 315
- Registered for: 3 years 7 months
Muy bien Ricardo, sencillo y eficiente.
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
-
- Mensajes: 127
- Registered for: 3 years 7 months
Me perdi,
Cual fue el cambio en el CURL ?
Saludos
Osvaldo Ramirez
Cual fue el cambio en el CURL ?
Saludos
Osvaldo Ramirez
- ricardo arraes
- Mensajes: 87
- Registered for: 3 years 7 months
Hola Osvaldo, amigo!
Remove:
Curl_global_init()
Replace:
Curl_global_cleanup()
For:
Curl_easy_cleanup(hcurl)
Remove:
Curl_global_init()
Replace:
Curl_global_cleanup()
For:
Curl_easy_cleanup(hcurl)
The work always comes before the belief