¿ Existe alguna clase para el protocolo HTTP como existe para FTP, SMTP, etc ?
Yo he hecho una pero no se si es mejorable, o existe alguna que no conozco y poder utilizarla.
Si existe y alguien lo conoce, por favor decirmelo.
Si no existe y alguien la quiere puedo compartirla para mejorarla.
Un saludo
Andrés Romero
Clase para HTTP
-
- Posts: 988
- Joined: Thu Nov 24, 2005 3:01 pm
- Location: Madrid, España
Re: Clase para HTTP
Hola Andrés!
En las contribs de Harbour hay una clase muy interesante para usar del lado del servidor, hasta con multihilos. se llama hbhttpd.
¿En que estabas pensando, servidor o cliente?
En las contribs de Harbour hay una clase muy interesante para usar del lado del servidor, hasta con multihilos. se llama hbhttpd.
¿En que estabas pensando, servidor o cliente?
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
-
- Posts: 11
- Joined: Fri Nov 20, 2009 11:07 am
Re: Clase para HTTP
Hola Carlos, es para usar como cliente. En servidor tengo Apache con PHP y SQL
La ventaja de usar esta clase como cliente es que se puede establecer un "diálogo" entre el servidor y el cliente con cualquier cosa siempre que lo programes en ambas partes.
La clase que yo he hecho es muy sencilla, por eso me extraña que nadie lo tenga ya. Quizás es que no he sabido buscar bien.
Carlos, gracias por tu rápida respuesta.
La ventaja de usar esta clase como cliente es que se puede establecer un "diálogo" entre el servidor y el cliente con cualquier cosa siempre que lo programes en ambas partes.
La clase que yo he hecho es muy sencilla, por eso me extraña que nadie lo tenga ya. Quizás es que no he sabido buscar bien.
Carlos, gracias por tu rápida respuesta.
- Antonio Linares
- Site Admin
- Posts: 37481
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Contact:
Re: Clase para HTTP
Andrés,
FWH proporciona la Clase TWebClient y tienes un ejemplo de uso en samples\webclient.prg
Posiblemente entre la tuya y la nuestra, podamos mejorar ambas
FWH proporciona la Clase TWebClient y tienes un ejemplo de uso en samples\webclient.prg
Posiblemente entre la tuya y la nuestra, podamos mejorar ambas
-
- Posts: 11
- Joined: Fri Nov 20, 2009 11:07 am
Re: Clase para HTTP
Gracias Antonio,
He visto la clase TWebClient. Voy a tratar de hacer una clase con lo mejor de las dos. Cuando lo tenga hecho y probado os lo comento.
Un saludo
He visto la clase TWebClient. Voy a tratar de hacer una clase con lo mejor de las dos. Cuando lo tenga hecho y probado os lo comento.
Un saludo
-
- Posts: 988
- Joined: Thu Nov 24, 2005 3:01 pm
- Location: Madrid, España
Re: Clase para HTTP
Andrés,
échale una mirada a hb_curl. Es muy completa, y puedes hacer virtualmente cualquier cosa, incluyendo POST/GET, tambien es cliente FTP/POP. Maneja el tema de autenticación, puertos, etc.
La uso para hacer presentaciones en la Agencia Tributaria, y funciona como la seda.
Un saludo
échale una mirada a hb_curl. Es muy completa, y puedes hacer virtualmente cualquier cosa, incluyendo POST/GET, tambien es cliente FTP/POP. Maneja el tema de autenticación, puertos, etc.
La uso para hacer presentaciones en la Agencia Tributaria, y funciona como la seda.
Un saludo
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
-
- Posts: 11
- Joined: Fri Nov 20, 2009 11:07 am
Re: Clase para HTTP
Carlos, muchas gracias por tu interés. He bajado la clase o al menos lo que yo creo que es, y no la entiendo. Creo que una de dos:
a) yo soy muy simple (lo más probable).
b) la clase es muy complicada.
Si alguien esta interesado en mi modesta clase, pedirmelo a "andres.romero@puentelibros.com" para no ocupar este foro.
Antonio, si estas interesado dímelo. Podríamos decir que la clase es una extensión de la vuestra con GET, POST, parámetros, etc.
a) yo soy muy simple (lo más probable).
b) la clase es muy complicada.
Si alguien esta interesado en mi modesta clase, pedirmelo a "andres.romero@puentelibros.com" para no ocupar este foro.
Antonio, si estas interesado dímelo. Podríamos decir que la clase es una extensión de la vuestra con GET, POST, parámetros, etc.
- Antonio Linares
- Site Admin
- Posts: 37481
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Contact:
Re: Clase para HTTP
Andrés,
Si la copias aqui te lo agradecemos, asi queda disponible para quien pueda interesarle, gracias!
Si la copias aqui te lo agradecemos, asi queda disponible para quien pueda interesarle, gracias!
-
- Posts: 11
- Joined: Fri Nov 20, 2009 11:07 am
Re: Clase para HTTP
Es la primera vez que "intento" poner un prg, a ver como me sale
Bien, lo conseguí
Los que empeceís en programación, no ver mi forma de programar como un ejemplo. Los que sabeís mas que yo (casi todos) ser comprensivos y perdonarme.
Admito críticas
NOTA IMPORTANTE: Para los que quieran saber más sobre el tema del protocolo HTTP buscar en internet el documento RFC 2616. Es un documento de casi 200 páginas en inglés perfectamente ilegible
Code: Select all
* THTTP por Andrés Romero García (ARG) andres.romero@puentelibros.com
* Ver ejemplos al final del programa
* ==================================
#include "FiveWin.ch"
#include "romewin.inc" /* Se puede sustituir por:
#define CRLF chr(13)+chr(10)
#define SI .T.
#define NO .F.
El resto del include, no se utiliza en esta clase
*/
memvar oWnd
//----------------------------------------------------------------------------//
CLASS THTTP
// datos de la clase:
DATA oSocket // socket usado durante la sesion.
DATA lSocket // bandera de haberse creado o no el socket.
DATA nSocket // numero del socket.
DATA nPort // puerto de comunicación. Por defecto, el 80.
DATA cIPServer // IP del servidor.
DATA nDelay // demora intencionada en la recepción de los paquetes.
DATA nTiempo // tiempo empleado en recibir el recurso.
DATA lAvisa // bandera de avisar o no cuando hay timeout.
DATA lTimeOut // error por exceso de tiempo.
DATA lTrozos // respuesta en trozos.
DATA nTiempoMax // tiempo maximo de espera antes de dar error por TimeOut.
DATA cCabecera // cabecera de la respuesta del servidor.
DATA cDatos // datos en la respuesta del servidor.
DATA nLargo // longitud del recurso.
DATA lLargo // definido por longitud.
DATA cRecurso // recurso devuelto en la respuesta del servidor.
DATA lMeter // bandera de utilizar meter o no.
DATA cAgente // texto libre que se manda dentro de la peticion HTTP bajo el apartado "User-Agent".
// datos propios del protocolo HTTP. Son respuestas que se reciben del servidor cuando se hace una consulta:
DATA h_HTTP
DATA h_RESN // código de la respuesta en formato númerico, por ejemplo 200, 404, etc.
DATA h_RESC // código de la respuesta en formato texto, por ejemplo, OK, "Página no encontrada", etc. (Lo que importa es el número).
DATA h_DATE
DATA h_SERVER
DATA h_LOCATION
DATA h_LAST_MODIFIED
DATA h_ETAG
DATA h_ACCEPT_RANGES
DATA h_CONTENT_LENGTH
DATA h_CONTENT_TYPE
// metodos:
METHOD New( cIPServer, nPort ) CONSTRUCTOR // crea la clase y conecta por medio de un socket.
METHOD SendData( cComando ) // manda una solicitud HTTP al servidor. El texto del comando lo tenemos que componer fuera de la clase
METHOD GetData( cComando ) // manda una solicitud y recibe el recurso HTTP devuelto por el servidor.
METHOD End() // termina la clase y el socket asociado.
METHOD get(cDireccion,cRecurso) // envia una petición por el metodo GET. El comando se crea en el método. Más rápido pero menos flexible.
METHOD post(cDireccion,cRecurso,cPost) // envia una petición por el metodo POST. El comando se crea en el método. Más rápido pero menos flexible.
* Siempre que se pueda, usar post() mejor que get()
ENDCLASS
//----------------------------------------------------------------------------//
// la direccion puede ser por IP (84.124.52.140) o por dominio (argcon.net). El puerto por defecto será el 1234. No confundir con el puerto 80
METHOD New( cIPServer, nPort, abc ) CLASS THTTP
local cData
DEFAULT nPort to 1234 // puerto por el que salimos nosotros a internet. NO CONFUNDIR con el 80 que no tiene nada que ver.
::nPort := nPort
::oSocket := TSocket():New( ::nPort ) // hacer esto ANTES que GetHostByName()
::lSocket := ValType( ::oSocket ) == "O" .and. ::oSocket:nSocket > 0
::nSocket := ::oSocket:nSocket
::cIPServer := GetHostByName( cIPServer ) // para tener la IP desde el nombre, SIEMPRE tiene que crear socket antes.
::lTimeOut := NO
::nTiempoMax:= 5
::cCabecera := ''
::cRecurso := ''
::nDelay := 0.05
::nTiempo := 0
::lAvisa := SI
::lLargo := NO
::lTrozos := NO
::lMeter := NO
::cAgente := 'ARG-Consulting' // esto es libre, por ejemplo, los navegadores ponen aquí el tipo de navegador MSIE, o CROME, etc.
::h_HTTP := ''
::h_RESN := 0 // SOLO este dato es obligatorio. Del resto, algunos servidores mandan lo que quieren.
::h_RESC := ''
::h_DATE := ''
::h_SERVER := ''
::h_LOCATION := ''
::h_LAST_MODIFIED := ''
::h_ETAG := ''
::h_ACCEPT_RANGES := ''
::h_CONTENT_LENGTH := ''
::h_CONTENT_TYPE := ''
::oSocket:Connect( ::cIpServer, 80 ) // direccion y puerto por el que escucha el servidor de internet. (p.e. 84.124.52.140, 80 )
inkey(0.5)
cData := ::oSocket:GetData() // "limpia" el buffer de entrada para empezar de cero.
return self
//----------------------------------------------------------------------------//
METHOD SendData(cComando) CLASS THTTP
if !empty( cComando )
::oSocket:SendData( cComando )
endif
return NIL
//----------------------------------------------------------------------------//
METHOD GetData(cComando) CLASS THTTP
/*
Si el recurso se recibe en trozos ("chunked"), se van poniendo como elementos de un array.
Cuando llega el ultimo trozo, junta todos los elementos y forma el recurso que será entregado
Si no se pusiera en array y se quiere formar el recurso a medida que se recibe, el ordenador no
tiene tiempo y corta el recurso de mala manera.
// Esta línea se puede poner en cualquier parte del PRG para ayudarnos a hacer una pequeña depuración///////////////////
nCanal := fcreate('.\http'+str0s(++nConCanal,3)+'.txt') ; fwrite(nCanal,cData) ; fclose(nCanal) //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
local cData := ''
local nSegundos := seconds() + ::nTiempoMax
local cCabeMayu // cabecera recibida convertida a mayçusculas para que sea más fácil buscar
local nLineas
local nConta := 0
local nPun
local aRecurso := {} // array de los "trozos" del recurso recibido
local nI := 0
local nL := 0
local nLen := 0
local cLinea := ''
local cMayus := ''
local cFinal := CRLF+'0'+CRLF+CRLF
local nActual := 0
local oMeter
local nConCanal := 0 // contador para la grabación de paquetes
::nTiempo := seconds()
::lTimeOut := NO
::lLargo := NO
::lTrozos := NO
::cRecurso := ''
if !empty(cComando)
::oSocket:SendData( cComando ) // manda el comando de solicitud...
inkey(::nDelay) // espera x segundos para dar tiempo a no se que ¿?, pero si no lo pongo, no funciona
endif
if ::lMeter
@ 0.4, 15 METER oMeter VAR nActual TOTAL 100 of oWnd:oMsgBar SIZE oWnd:nWidth-600, 12 BarColor CLR_HRED, CLR_WHITE
oMeter:ctext := 'Recibiendo paquetes desde el servidor ...'
oMeter:lPercentage := NO
endif
do while seconds() < nSegundos
if ::lMeter
if ++nActual > 100
nActual := 0
endif
oMeter:Set( nActual )
if len(aRecurso) = 0
oMeter:ctext := 'Esperando recibir paquetes HTTP, desde el servidor ...'
else
oMeter:ctext := 'Recibidos '+allstr(len(aRecurso))+' paquetes HTTP, desde el servidor de ARG...'
endif
endif
cData := ::oSocket:GetData()
inkey(::nDelay) // espera 0.05 segundos para dar tiempo a no se que ¿?, pero si no lo pongo, no funciona
*nCanal := fcreate('.\http'+str0s(++nConCanal,3)+'.txt') ; fwrite(nCanal,cData) ; fclose(nCanal)
if len(cData) > 0 // NO poner "!empty(cData)" porque hay veces que todo el paquete son espacios en blanco
nSegundos := seconds() + ::nTiempoMax
if cData = 'HTTP' // si es el primer trozo...
nPun := at(CRLF+CRLF,cData) // ... mira si hay una linea en blanco
if nPun > 0 // si hay una linea en blanco, es que tiene una cabecera...
::cCabecera := left(cData,nPun-1) // ...en cuyo caso, de los datos, separa la cabecera.
nLineas := mlcount(::cCabecera,254) // de la cabecera...
for nL = 1 to nLineas // ... analiza todas las lineas de la cabecera
cLinea := alltrim(memoline(::cCabecera,254,nL)) // toma una linea concreta
cMayus := upper(cLinea) // pasa a mayusculas por comodidad de programacion
do case
case cMayus = 'HTTP/1' // si es la primera linea...
::h_HTTP := cLinea // linea completa
::h_RESN := val(substr(cLinea,10,3)) // respuesta numerica
::h_RESC := substr(cLinea,14) // respuesta en texto
case cMayus = 'DATE'
::h_DATE := cLinea
case cMayus = 'SERVER'
::h_SERVER := cLinea
case cMayus = 'LOCATION'
::h_LOCATION:= substr(cLinea,11)
case cMayus = 'LAST-MODIFIED'
::h_LAST_MODIFIED := cLinea
case cMayus = 'ETAG'
::h_ETAG := cLinea
case cMayus = 'ACCEPT-RANGES'
::h_ACCEPT_RANGES := cLinea
case cMayus = 'CONTENT-LENGTH'
::h_CONTENT_LENGTH := cLinea
::nLargo := substr(::h_CONTENT_LENGTH,16)
::nLargo := val(::nLargo) // la longitud esta en decimal
::lLargo := SI
case cMayus = 'TRANSFER-ENCODING'
if 'CHUNKED' $ cMayus // la respuesta esta en trozos
::lTrozos := SI
endif
case cMayus = 'CONTENT-TYPE'
::h_CONTENT_TYPE := cLinea
endcase
next
::cDatos := substr(cData,nPun+4) // del total de datos recibidos, separa el cuerpo
if ::h_RESN <> 200 // si NO es 200, algo raro pasa. Dentro del if, analizamos el que. Se pueden poner mas respuestas
if ::h_RESN = 301 .or. ::h_RESN = 302
return NO
endif
if ::lAvisa // si hay indicacion de avisar...
do case
case ::h_RESN = 404
arginfo('Página no encontrada','Error '+allstr(::h_RESN),'THTTP:228')
otherwise
arginfo(::h_RESC,'Error '+allstr(::h_RESN),'THTTP:211')
endcase
endif
return NO
endif
do case
case ::lTrozos // si viene en trozos ("chunked"), la primera linea es la longitud del recurso (no del paquete)
nPun := at(CRLF,::cDatos) // busca el primer CRLF
::nLargo := left(::cDatos,nPun-1) // la primera parte es la longitud en hexadecimal
::nLargo := nHex(::nLargo) // lo convertimos a decimal
::cDatos := substr(::cDatos,nPun+2) // el resto son los datos propiamente dichos
aadd(aRecurso,::cDatos) // pone el primer trozo en el array que formara el recurso recibido
// vuelve al bucle para seguir recibiendo...
case ::lLargo // si el recurso esta definido por longitud
::cRecurso := left(::cDatos,::nLargo)
::nTiempo := seconds()-::nTiempo
return SI
otherwise
::cRecurso := ::cDatos
::nTiempo := seconds()-::nTiempo
return SI
endcase
else // si NO hay linea en blanco separando la cabecera del recurso...
::cCabecera := cData // todo es cabecera
::cDatos := '' // y por lo tanto, NO hay datos
::cRecurso := '' // NI recurso
::nTiempo := seconds()-::nTiempo
return SI
endif
else // si NO empieza por HTTP, no es el primer trozo. Es el segundo, tercero, etc.
do case
case ::lTrozos // si viene en trozos...
if right(cData,7) = cFinal // si contiene el final, es que es el ultimo trozo
nLen := len(cData)
aadd(aRecurso, left(cData,nLen-7) ) // tomo los bytes
nLen := len(aRecurso)
for nI = 1 to nLen
::cRecurso += aRecurso[nI] // forma el recurso a partir del array de trozos recibidos
next
::nLargo := len(::cRecurso)
::nTiempo := seconds()-::nTiempo
if ::lMeter
fin( @oMeter )
endif
return SI
endif
aadd(aRecurso, cData ) // tomo los bytes
case ::lLargo
::cRecurso += cData
if len(::cRecurso) >= ::nLargo
return SI
endif
endcase
endif
endif
enddo
::lTimeOut := SI
if ::lAvisa
arginfo('Exceso de tiempo ('+allstr(::nTiempoMax)+' seg.) en la respuesta a un comando'+CRLF+CRLF+cComando,'THTTP:298, (solo en ARG)')
endif
return NO
//----------------------------------------------------------------------------//
METHOD End() CLASS THTTP
::oSocket:end()
::oSocket := NIL
return NIL
//----------------------------------------------------------------------------//
METHOD get(cDireccion,cRecurso) CLASS THTTP
local cComando
cComando := 'GET '+cRecurso+' HTTP/1.1' +CRLF+; // SOLO el recurso
'Host: '+cDireccion +CRLF+; // SOLO la direccion
'Referer: http://'+cDireccion+cRecurso +CRLF+; // la direccion y el recurso
'Accept: */*' +CRLF+;
'Accept-Language: es' +CRLF+;
'Content-Type: application/x-www-form-urlencoded' +CRLF+; // es necesario para que cPost sea procesado correctamente
'Content-Length: '+allstr(len(cPost)) +CRLF+; // len(cPost), es el string SOLO, no incluye el CRLF final
'Connection: close' +CRLF+; // cierra la conexión una vez recibido el recurso
'Cache-Control: no-cache' +CRLF+;
'User-Agent: '+::cAgente +CRLF+; // referencia libre.
::getData(cComando) // manda el comando y recibe la respuesta
return NIL
METHOD post(cDireccion,cRecurso,cPost) CLASS THTTP
local cComando
cComando := 'POST '+cRecurso+' HTTP/1.1' +CRLF+; // SOLO el recurso
'Host: '+cDireccion +CRLF+; // SOLO la direccion
'Referer: http://'+cDireccion+cRecurso +CRLF+; // la direccion y el recurso
'Accept: */*' +CRLF+;
'Accept-Language: es' +CRLF+;
'Content-Type: application/x-www-form-urlencoded' +CRLF+; // es necesario para que cPost sea procesado correctamente
'Content-Length: '+allstr(len(cPost)) +CRLF+; // len(cPost), es el string SOLO, no incluye el CRLF final
'Connection: close' +CRLF+; // cierra la conexión una vez recibido el recurso
'Cache-Control: no-cache' +CRLF+;
'User-Agent: '+::cAgente +CRLF+; // referencia libre.
'' +CRLF+; // linea en blanco separando la cabecera del mensaje
cPost +CRLF
::getData(cComando) // manda el comando y recibe la respuesta
return NIL
************************************************************************************************************************
************************************************************************************************************************
************************************************************************************************************************
/*
/--------------------------------------------------------------------------------------------------------------------\
| LA MEJOR FORMA DE NO PERDER UNA AYUDA ES INCLUIRLA DENTRO DEL PRG QUE USAMOS, AUNQUE ESTO SUPONGA PEOR ENMAQUETADO |
\--------------------------------------------------------------------------------------------------------------------/
El protocolo HTTP se puede utilizar para mantener un "diálogo" entre un cliente (nuestro programa) y un servidor, por
ejemplo Apache. La solicitud y posterior envio de páginas WEB es solo una parte de lo que se puede hacer, aunque es la
parte que más se utiliza. Nosotros con esta clase, pretendemos enlazar el cliente y el servidor para sacar todo el
provecho posible.
Nota:- La función arginfo() es una msginfo() modificada para centrar el dialogo dentro de la ventana padre. Puede ser
sustituida totalmente por msginfo( <parametros> )
El programa esta basado más en la experiencia que en la teoría. Seguro que es muy mejorable técnicamente, pero a mi
me funciona. Solo quiero compartir para mejorar. Espero contestaciones con preguntas e ideas para completar la clase.
EJEMPLOS:
========
Programa para pedir una actualización. Se indican los parámetros fijos y los variables según el cliente. El servidor
Apache-PHP-SQL comprueba el usuario, la clave, el programa, la versión, etc. y responde en consecuencia además de indicar
los datos FTP para la descarga [ evidentemente, los datos están trucados :-) ] :
cDireccion := 'www.la_del_servidor.com'
nPuerto := varget('internet.PUERTOSALI',1234) // varget() es una funcion utilizada en ARG,
cRecurso:= '/php/valikey.php'
// estos parámetros pasan como par variable-contenido, y son leidos como tales en el programa PHP del servidor
cPost := 'version=110118' +;
'&buzon='+cBuzon +;
'&clave='+cPin +;
'&programa='+cGESxxx+cVersion +;
'&diahora='+cDiaHora +;
'&accion=UPDATE' +;
'&clavewin='+cClaveWin +;
'&numepan='+cNumePan +;
''
oWnd:SetMsg('Esperando contestación de ARG. Espere, por favor.' )
oHTTP := Thttp():New( cDireccion, nPuerto ) // prepara los datos, y hace la conexión
if !oHTTP:lSocket // normalmente NO pasará por aquí.
arginfo('No se ha creado el socket en la dirección '+cDireccion)
return NO // variable del preprocesador que indica .F.
endif
oHTTP:nTiempoMax:= varget('internet.TIEMESPE10',10) // segundos que esperara antes de abandonar la conesión. Por defecto 10.
oHTTP:nDelay := varget('internet.INTERPACK',10)/100 // segundos/100 (centésimas de segundo) que espera entre paquetes.
oHTTP:lMeter := SI // bandera para sacar un meter en el pie del diálogo.
oHTTP:lAvisa := NO // bandera de avisar o no al operador del proceso y sus fallos si los hay. Se usa para depuración.
oHTTP:Post(cDireccion,cRecurso,cPost) // manda el comando por POST y recibe la respuesta en oHTTP:cRecurso.
// NO confundir cRecurso (lo que se pide) con oHTTP:cRecurso (lo que se recibe).
if oHTTP:h_RESN = 200 // si todo es correcto...
cRecurso := oHTTP:cRecurso // pasamos el recurso a una variable local.
cRecurso := strtran(cRecurso,'<br>',CRLF) // _ de línea (interlínea) vienen como <br> que es propio del protocolo HTTP/HTML.
arglogin(cRecurso) // graba un login con lo que se recibe del servidor, que puede estar bien (200) y NO ser lo que se pide.
memowrit( varget('cDirExe','.')+'\UPDATE.INI', cRecurso) // graba el fichero recibido como UPDATE.INI para que sirva de control al FTP.
lPasa := SI
else
arglogin(oHTTP:h_RESN+CRLF+oHTTP:cRecurso)
lPasa := NO
endif
oHTTP:end()
oWnd:SetMsg(varget('messageWnd',' ') )
if !lPasa
arginfo(cPost,'Respuesta HTTP: '+allstr(oHTTP:h_RESN)+' No se ha recibido el recurso por el socket '+allstr(oHTTP:nSocket ) )
return NO
endif
etc, etc.
Se pueden hacer peticiones GET, pero no merece la pena, es mejor hacerlo siempre POST. El ejemplo anterior quedaría así (OJO, no lo he probado)
cDireccion := 'www.la_del_servidor.com'
nPuerto := varget('internet.PUERTOSALI',1234) // varget() es una funcion utilizada en ARG,
cRecurso:= '/php/valikey.php'
// estos parametros pasan como par variable-contenido, y son leidos como tales en el programa PHP del servidor.
// Aquí cada uno pondría el "dialogo" que quiere mantener con el servidor. Luego hay que programar el servidor para
// leer las variables y su contenido, actuar en consecuencia y devolver el recurso pedido o el resultado programado.
cRecurso:= '?' +; // <-- OJO, esto ha cambiado de POST a GET
'version=110118' +;
'&buzon='+cBuzon +;
'&clave='+cPin +;
'&programa='+cGESxxx+cVersion +;
'&diahora='+cDiaHora +;
'&accion=UPDATE' +;
'&clavewin='+cClaveWin +;
'&numepan='+cNumePan +;
''
oWnd:SetMsg('Esperando contestación de ARG. Espere, por favor.' )
oHTTP := Thttp():New( cDireccion, nPuerto ) // prepara los datos, y hace la conexión
if !oHTTP:lSocket // normalmente NO pasará por aquí.
arginfo('No se ha creado el socket en la dirección '+cDireccion)
return NO // variable del preprocesador que indica .F.
endif
oHTTP:nTiempoMax:= varget('internet.TIEMESPE10',10) // segundos que esperara antes de abandonar la conesión, en segundos. Por defecto 10
oHTTP:nDelay := varget('internet.INTERPACK',10)/100 // segundos/100 (centesimas de segundo) que espera entre paquetes
oHTTP:lMeter := SI // bandera para sacar un meter en el pie del diálogo
oHTTP:lAvisa := NO // bandera de avisar o no al operador del proceso y sus fallos si los hay. Se usa para depuración
oHTTP:get(cDireccion,cRecurso) // <-- OJO // manda el comando por GET y recibe la respuesta en oHTTP:cRecurso
// NO confundir cRecurso (lo que se pide) con oHTTP:cRecurso (lo que se recibe)
if oHTTP:h_RESN = 200 // si todo es correcto...
cRecurso := oHTTP:cRecurso // pasamos el recurso a una variable local
cRecurso := strtran(cRecurso,'<br>',CRLF) // _ de linea vienen como <br> que es propio del protocolo HTTP/HTML
arglogin(cRecurso) // graba un login con lo que se recibe del servidor, que puede estar bien y NO ser lo que se pide
memowrit( varget('cDirExe','.')+'\UPDATE.INI', cRecurso) // graba el fichero recibido como UPDATE.INI para que sirva de control al FTP
lPasa := SI
else
arglogin(oHTTP:h_RESN+CRLF+oHTTP:cRecurso)
lPasa := NO
endif
oHTTP:end()
oWnd:SetMsg(varget('messageWnd',' ') )
if !lPasa
arginfo(cPost,'Respuesta HTTP: '+allstr(oHTTP:h_RESN)+' No se ha recibido el recurso por el socket '+allstr(oHTTP:nSocket ) )
return NO
endif
etc, etc.
Este es otro ejemplo, Aqui vemos como se hace una petición desde un programa clipper a un servidor de mensajes SMS para móviles:
El servidor, que no es de ARG, NECESITA que sea GET
cDireccion := '84.124.123.321' // dirección del servidor. Aqui es ficticia
cRecurso := '/pls/sms/sms.CGIEnviaSMS' // NO importa el orden de los siguientes parámetros
cRecurso += '?pusuario=' + cUsuario // fijarse en el signo "?" que hay que poner antes del primer parámetro
cRecurso += '&pclave=' + cClave
cRecurso += '&pdestino=34' + alltrim(aMovil[1])
cRecurso += '&ptexto=' + db2ht(alltrim(cTexto)) // db2ht() es una función que convierte una cadena clipper en una HTTP
cRecurso += '&porigen=' + db2ht(cOrigen)
cRecurso += '&psmsid=' + db2ht(time())
cRecurso += '&pflash=' + 'N'
if lConfirma
cRecurso += '&pacuse=' + cCorreo
endif
oHTTP := Thttp():New( cDireccion ) // prepara los datos, y hace la conexión
oHTTP:nTiempoMax:= varget('internet.TIEMESPE5',5) // segundos que esperara antes de abandonar la conesión
oHTTP:lAvisa := NO
oHTTP:get(cDireccion,cRecurso) // <-- OJO // manda el comando por GET y recibe la respuesta en oHTTP:cRecurso
cRes := oHTTP:h_RESC
nRes := oHTTP:h_RESN
cRecurso:= oHTTP:cRecurso
oHTTP:end()
msgwait('Enviado mensaje '+alltrim(aMovil[1]),'Envio SMS',1)
if cRecurso = 'OK'
arginfo(strtoken(cRecurso,2,'#')+'.' +CRLF+;
'Número: '+alltrim(aMovil[1]) +CRLF+;
'Referencia: '+strtoken(cRecurso,3,'#') +CRLF+;
'Créditos consumidos: '+strtoken(cRecurso,4,'#') +CRLF+;
'Créditos ACTUALES: ' +strtoken(cRecurso,5,'#') )
nSaldo := val(strtoken(cRecurso,5,'#'))
else
arginfo('Respuesta:'+allstr(nRes)+'.-'+cRes+CRLF+;
'Recurso: '+cRecurso)
nSaldo := -1
return NO
endif
Hay que tener en cuenta el conjunto de caracteres, que en HTTP NO se usa el juego de windows, pero eso es otro tema.
*/
Los que empeceís en programación, no ver mi forma de programar como un ejemplo. Los que sabeís mas que yo (casi todos) ser comprensivos y perdonarme.
Admito críticas
NOTA IMPORTANTE: Para los que quieran saber más sobre el tema del protocolo HTTP buscar en internet el documento RFC 2616. Es un documento de casi 200 páginas en inglés perfectamente ilegible