Visual Basic Foro

General => Códigos - Aportes - Recursos => Mensaje iniciado por: coco en Junio 29, 2013, 12:23:42 am

Título: clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r6)
Publicado por: coco en Junio 29, 2013, 12:23:42 am
Buenas a todos!

version: REVISION 6 (21/febrero/14)!!!!

El martes me surgio la idea de enviar un HTTP POST de forma asincronica, y no encontre nada piola.
Hablando con Cobein se me ocurrio el de utilizar un codigo que use el HttpCreateRequest y HttpSendRequest, pero que la llamada bloqueante (HttpSendRequest) se haga en un thread aparte.
Ahora, la magia reside en que la parte "heavy" se hace en VB, mientras que en el thread solo se hace la llamada a HttpSendRequest y a SendMessageTimeout (para avisarle al thread 'main' que ya termino la ejecucion).
El codigo del thread esta hecho 100% en assembly (ver asm.asm). En dicho archivo, se ven unos pushs y unos llamados a cualquier lugar (fuera de joda, lo hice aproposito). La gracia de eso, es que el codigo en VB va a parchear eso, con llamadas a direcciones validas (la del HttpSendRequest y SendMessageTimeout), como asi tambien, reemplazar las "constantes" del hWnd de la ventana, y el uMsg custom. (la clase crea una ventana oculta para recibir los mensajes del thread, y el mensaje es uno custom, creado con RegisterWindowMessage).

La logica es sencilla. Se llama a la funcion SendRequest o SendRequest_OptionalAsByte con todos los parametros, inclusive el "private key", que seria un string para identificar los eventos (la diferencia radica en que la primera, el parametro opcional lpOptional es interpretado en base a un string, y en la segunda, es un array de bytes y precisa que se le pase el tamaño del mismo).
Tambien hay un parametro de Timeout.

Los demas parametros conforman a los que uno usaria al llamar a InternetConnect y HttpCreateRequest.

Hay varias enums de flags y demas, para usar en esas llamadas, o en QueryInfoAsXXXXX (puede ser AsLong, AsDate, AsString).

QueryInfoAsXXXX consulta algun parametro dentro del header y lo devuelve, segun el formato elegido (leer el msdn para saber si usar Long, Date o String). La funcion acomoda el tamaño del string automaticamente.

Luego quedan las funciones DumpRequestToBuffer, DumpRequestToString y DumpRequestToFile (todas estas leen el resultado del Request, y lo devuelven de maneras distintas).

Tambien hay una funcion mas, CancelRequest, la cual se podria llamar para cancelar un Request que se esta ejecutando.

Eventos: RequestDone (cuando HttpSendRequest termina), RequestCancelled (cuando es cancelado por el usuario), RequestTimeout (cuando hay timeout)

En el ejemplo hay 3 botones.
1º Descarga el google a googlex.html
2º Descarga 10 veces el google a google_xx.html
3º Envia un POST a un php en un host mio, que solamente devuelve el parametro "q"




(el link siempre es el mismo para LA ULTIMA VERSION)
DESCARGAR rev6 (https://www.dropbox.com/s/hbp9co28a8ulpoq/httprequest.zip)

Cualquier cosa los escucho...
Saludos!!!
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica mediante threads!
Publicado por: LeandroA en Junio 29, 2013, 08:10:05 am
buena coco, hace rato que vengo buscando una clase asi pero nunca encontré nada, lo unico mas cercano fue usando createobject() y metiendo un timer para verificar si había terminado, u otras chanchadas como crear otro exe para hacer peticiones.

Saludos
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica mediante threads!
Publicado por: coco en Junio 29, 2013, 09:54:44 pm
Si, yo tambien estaba en la misma... Lo hice lo mas generico posible (un ejemplo es si queres enviar una String o un array de bytes). Tambien le hice pruebas "destructivas", y no vi nada raro. Lo unico que es ESPERABLE, es que si estas en el IDE y crashea, empieces a leakear memoria (tanto de las structs, como de la memoria donde esta el code en assembly), pero esto pasa hasta con el self subclass, y no habria que ni preocuparse (en el .EXE de 'produccion' no ocurre esto).

Cualquier problema, o feature request, comenten!!! Quiero saber si sirvio de algo ajjaja
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica mediante threads!
Publicado por: cobein en Julio 01, 2013, 09:29:05 am
Genial coco, la verdad quedo re solido :).
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica mediante threads!
Publicado por: coco en Julio 19, 2013, 04:06:05 am
Revision 1: (19/jul/13)

En vista de algunas inquietudes del pelado Cobein, cambie la forma en la que se agregan los Request, dejando el array con un tamaño fijo (se puede incrementar el maximo, pero me parece una locura usar mas de 200 request a la vez).
Tambien se me ocurrio de cambiar el PostMessage por algo mas solido, y ahora usa SendMessageTimeout, el cual hace que cada thread ESPERE a que el thread main "lea" el mensaje enviado.
Y por ultimo, encontre un par de forraditas que leakeaban memoria (me olvide de cerrar el request).
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r2)
Publicado por: coco en Julio 19, 2013, 04:48:18 pm
Revision 2: (19/jul/13)

Arreglado el leakeage de Handles, porque al enviar un mensaje desde el thread, no se podia matarlo, asi que es mas sencillo cerrar el handle y olvidarse.
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r2)
Publicado por: cobein en Julio 22, 2013, 10:10:11 am
Perfecto coco, lo probe y esta andando de 10 ahora. Cualquier cosa te aviso.
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r2)
Publicado por: E N T E R en Julio 22, 2013, 03:10:53 pm
Disculpen, baje y probé el proyecto pero para que mas o menos me serviría esto?

Saludos...
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r2)
Publicado por: cobein en Julio 23, 2013, 10:03:18 am
Para hacer HTTP requests, podes por ejemplo descargar una pagina/documento, subir informacion a traves de get/post o lo que quieras de manera asincronica (no bloquea) por ende podes como en el ejemplo, descargar 10 paginas a la vez sin bloquear la interfaz.
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r2)
Publicado por: coco en Julio 29, 2013, 01:31:04 am
Si, es como dice Cobein. Yo lo habia hecho para hacer una especie de widget sobre "cuando llega" (un servicio (http://www.etr.gov.ar/cuandollega.html) que te indica cuanto falta para que un colectivo/bus llegue a una parada).

Lo que vos podes hacer con esto, es muy similar a usar el objeto XMLHTTP:
Código: (VB) [Seleccionar]
        Set objXML = CreateObject("Microsoft.XMLHTTP")

        With objXML
                .open "GET", sURL, True
                .send

                If .readyState = 0 Then
                        Debug.Print "Error!"
                        Exit Sub
                End If
        End With

        tmrWait.Enabled = True

'// y esto iria en el sub del timer, para chequear el estado del Request
        If objXML.readyState = 4 Then
                tmrWait.Enabled = False
                '// leer la data
                '// ...
        End If

Que seguramente lo viste en varios proyectos de Leandro (inclusive, en el del Facebook, que creaba varios .exe para cada 'request'; de esa forma la interfaz no se bloquea nunca)

En resumen, vos podes enviar un GET o POST a algun sitio (en realidad es mas flexible, y soporta mas metodos), y esperar que el mismo te responda, y leer lo que devuelve.
Esto sirve para hacer procedimientos remotos a algun PHP, o CGI. Por ejemplo uno puede hacer una interfaz en VB de algun sitio que use AJAX, usando 'mas o menos' la misma logica que el Javascript, utilizando este clase como el XMLHTTP.

Saludos
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r2)
Publicado por: coco en Febrero 09, 2014, 11:54:53 pm
Nueva version! Se agrego la posibilidad de "esperar" a que terminen todos los threads. Esto haria que no haya problemas del tipo "Memory access violation", cuando uno borraba la clase y aun existian threads funcionando.

El codigo que espera a que terminen todos es muy rapido (ya que al cerrar un handle, el API del thread deberia retornar inmediatamente) y no tilda la aplicacion.
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r3)
Publicado por: cliv en Febrero 10, 2014, 05:58:23 am
I use Microsoft internet transfer control and my code ... and work
Código: [Seleccionar]
  Dim gbUrl As String
  Dim gbParam As String
  gbUrl = "http://localhost/termo/inetgb-CSV.php"
  gbParam = "insert=no&sql=" & txtSQL.Text
  InetGb.Execute gbUrl, "POST", gbParam, "Content-Type: application/x-www-form-urlencoded"

I use your class with this code ... and not work . What i'm doing wrong?
Código: [Seleccionar]
  Dim gbParam As String
  gbParam = "insert=no&sql=" & txtSQL.Text
  Call obj.SendRequest("http://localhost/termo", "/inetgb-CSV.php", "Date.csv", _
                        sAdditionalHeaders:="Content-Type: application/x-www-form-urlencoded", _
                        sOptionalData:=gbParam, sVerb:="POST")

Código: [Seleccionar]
txtSQL.Text="SELECT * FROM inetgb WHERE ID>3"
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r3)
Publicado por: coco en Febrero 10, 2014, 04:25:17 pm
@cliv, you're not passing correctly the aprameters.
The first one is just the "host", you don't have to add any URI in there.
For the second parameter, go ahead and add all the URI there.
Also, "Date.csv" is just a "key", it won't save any file. You just have to handle the event RequestDone and read the file with DumpRquestToString


I bet your code should be like this:
Código: (vb) [Seleccionar]
  Dim gbParam As String
  gbParam = "insert=no&sql=" & txtSQL.Text
  Call obj.SendRequest("localhost", "/termo/inetgb-CSV.php", "SomeKeyToIdentifyThisRequest", _
                        sAdditionalHeaders:="Content-Type: application/x-www-form-urlencoded", _
                        sOptionalData:=gbParam, sVerb:="POST")

And for the request reading:
Código: (vb) [Seleccionar]
Private Sub obj_RequestDone(ByVal sPrivateKey As String, ByVal lReturned As Long, ByVal lhRequest As Long)
    Dim sAA As String
    Call obj.DumpRequestToString(lhRequest, sAA)
    Debug.Print "Request '"; sPrivateKey; "', returned: "; sAA
End Sub

Tellme if that works.
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r3)
Publicado por: coco en Febrero 21, 2014, 06:39:09 pm
Revision 5 recien salida del horno!
Agrega SSL y Proxy, como asi tambien corrige un monton de errores que he encontrado.
Tambien agrega la posibilidad de saber porque no se completo un Request (GetLastError() del thread).

Saludos!
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r6)
Publicado por: coco en Marzo 23, 2014, 04:53:36 pm
Revision 6 con features:
Se metio la logica de InternetReadFile en el thread (ya que esa api bloquea), y se modificaron algunos eventos y propiedades para hacer parecer este objeto al control WinHTTP.
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r6)
Publicado por: ton en Abril 01, 2015, 09:43:19 pm
Hola coco y demas compañeros, muy interesante la clase...

Te comento lo siguiente, yo consumo un web service, y uso xmlhttrequest de la siguiente manera, ahora como podria yo, con ésta clase, enviarle al usuario un aviso (un form, un gif de esos tipo web "loading",) ó algo que me indique que se esta procesando la solicitud...?? pido mucho?? gracias!!

Dim oHttReq As XMLHTTPRequest
Set oHttReq = New XMLHTTPRequest

urlPOST = "https://test.consultauser.com.mx/wsconsultaiduser.asmx"

oHttReq.Open "POST", urlPOST, False 'Aqui tendria que poner a true

oHttReq.Send sXml 'al hacer esto aqui es donde se me congela por unos segundos el equipo.

'sXML es un String que contiene el XML con los datos de usuario y contraseña y ademas la informacion que envio al Ws.

If oHttReq.Status = 200 Then
    ' este será el texto recibido del servicio Web
    resultWs = procesarRespuesta(oHttReq.responseText)
Else
    MsgError = "Error Codigo de Estado Web Service Status: " & oHttReq.Status & ": " & oHttReq.statusText & "
   resultWs = False
End If

Set oHttReq = Nothing





Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r6)
Publicado por: coco en Abril 01, 2015, 10:15:07 pm
Fijate en los eventos de la clase... Te avisa cuando termina o hay un error.
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r6)
Publicado por: xxdoc en Abril 20, 2016, 01:02:55 am
Buenas a todos!

version: REVISION 6 (21/febrero/14)!!!!

El martes me surgio la idea de enviar un HTTP POST de forma asincronica, y no encontre nada piola.
Hablando con Cobein se me ocurrio el de utilizar un codigo que use el HttpCreateRequest y HttpSendRequest, pero que la llamada bloqueante (HttpSendRequest) se haga en un thread aparte.
Ahora, la magia reside en que la parte "heavy" se hace en VB, mientras que en el thread solo se hace la llamada a HttpSendRequest y a SendMessageTimeout (para avisarle al thread 'main' que ya termino la ejecucion).
El codigo del thread esta hecho 100% en assembly (ver asm.asm). En dicho archivo, se ven unos pushs y unos llamados a cualquier lugar (fuera de joda, lo hice aproposito). La gracia de eso, es que el codigo en VB va a parchear eso, con llamadas a direcciones validas (la del HttpSendRequest y SendMessageTimeout), como asi tambien, reemplazar las "constantes" del hWnd de la ventana, y el uMsg custom. (la clase crea una ventana oculta para recibir los mensajes del thread, y el mensaje es uno custom, creado con RegisterWindowMessage).

La logica es sencilla. Se llama a la funcion SendRequest o SendRequest_OptionalAsByte con todos los parametros, inclusive el "private key", que seria un string para identificar los eventos (la diferencia radica en que la primera, el parametro opcional lpOptional es interpretado en base a un string, y en la segunda, es un array de bytes y precisa que se le pase el tamaño del mismo).
Tambien hay un parametro de Timeout.

Los demas parametros conforman a los que uno usaria al llamar a InternetConnect y HttpCreateRequest.

Hay varias enums de flags y demas, para usar en esas llamadas, o en QueryInfoAsXXXXX (puede ser AsLong, AsDate, AsString).

QueryInfoAsXXXX consulta algun parametro dentro del header y lo devuelve, segun el formato elegido (leer el msdn para saber si usar Long, Date o String). La funcion acomoda el tamaño del string automaticamente.

Luego quedan las funciones DumpRequestToBuffer, DumpRequestToString y DumpRequestToFile (todas estas leen el resultado del Request, y lo devuelven de maneras distintas).

Tambien hay una funcion mas, CancelRequest, la cual se podria llamar para cancelar un Request que se esta ejecutando.

Eventos: RequestDone (cuando HttpSendRequest termina), RequestCancelled (cuando es cancelado por el usuario), RequestTimeout (cuando hay timeout)

En el ejemplo hay 3 botones.
1º Descarga el google a googlex.html
2º Descarga 10 veces el google a google_xx.html
3º Envia un POST a un php en un host mio, que solamente devuelve el parametro "q"



  • rev1: Ahora la cantidad maxima de request esta limitada (para prevenir arrays locks); Se volo a la mierda el PostMessage y se reemplazo por el
    SendMessageTimeout (espera hasta que el thread main le responda); Se corrigieron unos leaks de handles (faltaba cerrar el hRequest)
  • rev2: Se corrigio el leak de handles (no se cerraba el objeto thread)
  • rev3: Se agrego la opcion de "Esperar a que terminen todos los threads". Esto es importante, porque antes se deallocaba la memoria de los threads, y si estos aun estaban activos, iba a surgir un error de "Memory access violation". Ademas le agregue el evento del WM_TIMER, que me lo habia olvidado y no estaba funcionando la parte del timeout.
  • rev4: Se agrego el soporte para SSL y Proxy. Se removieron muchos parametros y ahora solo se pasa una URL. Ahora en los eventos aparece el LastError del thread, el cual indica porque fallo el API. El "esperar a que los threads terminen" es una propiedad que puede ser cambiada en runtime (en IDE es 100% necesario!!!).
  • rev5: Se arreglo DumpRequestToString y DumpRequestToBufer, el cual escribia en un pedazo de memoria que no correspondia.
  • rev6: Se modificaron algunos eventos y propiedades para que el control se parezca mas al WinHTTP. Se agregó toda la logica de InternetReadFile en el thread, de forma que el thread de VB no se bloquea mas (ya que InternetReadFile bloquea).

(el link siempre es el mismo para LA ULTIMA VERSION)
DESCARGAR rev6 (https://www.dropbox.com/s/hbp9co28a8ulpoq/httprequest.zip)

Cualquier cosa los escucho...
Saludos!!!

maybe,i want ask can used cookie?and management cookie?
Título: Re:clsHttpRequests: Clase que envia Requests de forma asincronica con threads (r6)
Publicado por: coco en Abril 20, 2016, 01:08:02 am
@xxdoc:
You can use Cookies, just set them as a header. To do that, add the extra headers in the send request, just like "Cookie name=value".
I don't know what it is a management cookie, but if it is the same as a cookie, then its possible