├── .gitignore ├── README.md ├── Tests ├── FXUPersist.XML ├── FXUPersistGetTemplate.XML ├── FXUResults.FPT └── test_ajaxRest.prg ├── socktoaster.json └── src └── ajaxRest.prg /.gitignore: -------------------------------------------------------------------------------- 1 | ########## Visual Foxpro ########## 2 | # Created by socktoaster-ui 3 | # 4 | # Author: raul.jrz@gmail.com 5 | # Url: http://socktoaster.io 6 | ################################## 7 | 8 | # Links 9 | vfp9.lnk 10 | *.lnk 11 | 12 | # Archivos temporales de Fox 13 | *.bak 14 | *.fxp 15 | *.err 16 | *.tmp 17 | *.log 18 | 19 | *.cdx 20 | *.dbf 21 | *.ftp 22 | *.pjt 23 | *.pjx 24 | 25 | # Archivos ejecutables 26 | *.exe 27 | *.dll 28 | *.com 29 | *.app 30 | 31 | 32 | # Archivos comprimidos 33 | *.rar 34 | *.zip 35 | *.7z 36 | 37 | # Archivos imagenes 38 | *.jpg 39 | *.jpeg 40 | *.gif 41 | 42 | # Carpetas que no deben controlarse 43 | /result_test/ 44 | /download/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ajaxRest 2 | 3 | Esta es una clase de VFP que permite la conexión a traves de HTTP, lo que habilita para consumir servicios Restful o SOAP XML. 4 | 5 | **HTTP** define un conjunto de métodos de petición para indicar la acción que se desea realizar para un recurso determinado. Aunque estos también pueden ser sustantivos, estos métodos de solicitud a veces son llamados _HTTP verbs_. Cada uno de ellos implementan una semántica diferente, pero algunas características similares son compartidas por un grupo de ellos: ej. un request method puede ser safe, idempotent, o cacheable. 6 | 7 | **GET**: Solicita una representación de un recurso específico. Las peticiones que usan el método GET sólo deben recuperar datos. 8 | 9 | **HEAD**: Pide una respuesta idéntica a la de una petición GET, pero sin el cuerpo de la respuesta. 10 | 11 | **POST**: Se utiliza para enviar una entidad a un recurso en específico, causando a menudo un cambio en el estado o efectos secundarios en el servidor. 12 | 13 | **PUT**: Reemplaza todas las representaciones actuales del recurso de destino con la carga útil de la petición. 14 | 15 | **DELETE**: Borra un recurso en específico. 16 | 17 | **CONNECT**: Establece un túnel hacia el servidor identificado por el recurso. 18 | 19 | **OPTIONS**: Es utilizado para describir las opciones de comunicación para el recurso de destino. 20 | 21 | **TRACE**: Realiza una prueba de bucle de retorno de mensaje a lo largo de la ruta al recurso de destino. 22 | 23 | **PATCH**: Es utilizado para aplicar modificaciones parciales a un recurso. 24 | 25 | * support: raul.jrz@gmail.com 26 | * url: [http://rauljrz.github.io/](http://rauljrz.github.io) 27 | 28 | 29 | ## Dependencies 30 | https://github.com/raulvfp/catchException 31 | Para el control de las excepciones. 32 | 33 | ## Installation 34 | ``` 35 | git clone https://github.com/raulvfp/ajaxRest.git ajaxRest 36 | ``` 37 | 38 | ## Usage 39 | **Properties:** 40 | - method: Valores posibles POST, GET, PUT, DELETE, etc 41 | - urlRequest: Es la url a consultar. 42 | - body: El cuerpo del mensaje. 43 | - pathDownload: Path en donde se descargaran los archivos. Por defecto el CURDIR() 44 | - pathUpload: Path en donde reciden los archivos a subir. 45 | - isVerbose: Si hay eco o no en la pantalla de las acciones. Por defecto es .F. 46 | - isLogger: Indica si lleva un log con los registros de los sucesos. Por defecto es .F. 47 | - pathLog: Path en donde se guarda los log, si es que esta activo el log. 48 | - nameLog: Es el nombre del log del proceso, si es que esta activo el log. Por defecto es 'ajaxRest.log'. 49 | 50 | **Methods:** 51 | - addHeader(cKey, cValue) : Agrega una clave al HEADER 52 | + cKey: Clave del HEADER 53 | + cValue: Valor de la Clave del HEADER 54 | + Retorna: null 55 | ``` 56 | .addHeader('Content-Type','text/plain') 57 | ``` 58 | - addParameter(cKey, cValue) : Agrega un Parametro a la peticion. 59 | + cKey: Clave del Parametro 60 | + cValue: Valor de la Clave del Parametro 61 | + Retorna: null 62 | ``` 63 | .addParameter('results_per_page','1') 64 | ``` 65 | - send() : Envia la peticion. 66 | + Retorna: El Value Response de la conexion. 67 | - getResponse() : Devuelve el Response de la conexion. 68 | - saveFile(cNameFile) : Si lo que se recibe es un archivo, lo guarda en el folder indicado en THIS.pathDownload. 69 | + cNameFile: Es el nombre del archivo de salida. Si es empty, el nombre será el resultado de la funcion: SYS(3)+'.tmp' 70 | 71 | 72 | 73 | ## Example: 74 | ``` 75 | loHTTP = CREATEOBJECT('ajaxRest') 76 | WITH loHTTP 77 | .method = 'GET' 78 | .urlRequest = 'http://thecatapi.com/api/images/get' 79 | .addParameter('format' ,'src') 80 | .addParameter('results_per_page','1') 81 | .addHeader ("Content-Type" , 'text/plain') 82 | 83 | .SEND() 84 | IF .status=200 THEN 85 | .saveFile('thecat.jpg') 86 | ENDIF 87 | ENDWITH 88 | 89 | ``` 90 | -------------------------------------------------------------------------------- /Tests/FXUPersist.XML: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Admin 34 | THIS.Top = 63 35 | 36 | 37 | Admin 38 | THIS.Left = 0 39 | 40 | 41 | Admin 42 | THIS.Height = IIF(VERSION(5)>=900,649,480) 43 | 44 | 45 | Admin 46 | THIS.Width = IIF(VERSION(5)>=900,880,803) 47 | 48 | 49 | Admin 50 | THIS.inZoomTop = .F. 51 | 52 | 53 | Admin 54 | THIS.inZoomLeft = .F. 55 | 56 | 57 | Admin 58 | THIS.inZoomHeight = .F. 59 | 60 | 61 | Admin 62 | THIS.inZoomWidth = .F. 63 | 64 | 65 | Admin 66 | THIS.inZoomWindowState = 0 67 | 68 | 69 | Admin 70 | THIS.pgfDetails.ActivePage = 1 71 | 72 | 73 | Admin 74 | THIS.grdTests.FontName = "Tahoma" 75 | 76 | 77 | Admin 78 | THIS.grdTests.FontSize = 9 79 | 80 | 81 | Admin 82 | THIS.grdTests.FontBold = .F. 83 | 84 | 85 | Admin 86 | THIS.grdTests.FontItalic = .F. 87 | 88 | 89 | Admin 90 | THIS.pgfDetails.pgFailuresAndErrors.FontName = "Arial" 91 | 92 | 93 | Admin 94 | THIS.pgfDetails.pgFailuresAndErrors.FontSize = 9 95 | 96 | 97 | Admin 98 | THIS.pgfDetails.pgFailuresAndErrors.FontBold = .T. 99 | 100 | 101 | Admin 102 | THIS.pgfDetails.pgFailuresAndErrors.FontItalic = .F. 103 | 104 | 105 | Admin 106 | THIS.pgfDetails.pgFailuresAndErrors.edtFailuresAndErrors.FontName = "Courier New" 107 | 108 | 109 | Admin 110 | THIS.pgfDetails.pgFailuresAndErrors.edtFailuresAndErrors.FontSize = 9 111 | 112 | 113 | Admin 114 | THIS.pgfDetails.pgFailuresAndErrors.edtFailuresAndErrors.FontBold = .F. 115 | 116 | 117 | Admin 118 | THIS.pgfDetails.pgFailuresAndErrors.edtFailuresAndErrors.FontItalic = .F. 119 | 120 | 121 | Admin 122 | THIS.pgfDetails.pgMessages.FontName = "Arial" 123 | 124 | 125 | Admin 126 | THIS.pgfDetails.pgMessages.FontSize = 9 127 | 128 | 129 | Admin 130 | THIS.pgfDetails.pgMessages.FontBold = .T. 131 | 132 | 133 | Admin 134 | THIS.pgfDetails.pgMessages.FontItalic = .F. 135 | 136 | 137 | Admin 138 | THIS.pgfDetails.pgMessages.edtMessages.FontName = "Courier New" 139 | 140 | 141 | Admin 142 | THIS.pgfDetails.pgMessages.edtMessages.FontSize = 9 143 | 144 | 145 | Admin 146 | THIS.pgfDetails.pgMessages.edtMessages.FontBold = .F. 147 | 148 | 149 | Admin 150 | THIS.pgfDetails.pgMessages.edtMessages.FontItalic = .F. 151 | 152 | 153 | Admin 154 | THIS.ilLargeGrid=.F. 155 | 156 | 157 | Admin 158 | THIS.grdTests.COLUMN1.Width = 208 159 | 160 | 161 | Admin 162 | THIS.grdTests.COLUMN2.Width = 623 163 | 164 | 165 | Admin 166 | SET ORDER TO TAG TCLOC IN (THIS.icGridRS) 167 | 168 | 169 | Admin 170 | =SEEK("TEST_AJAXREST TESTPOST_DROPBOX_UPLOADFILE ",THIS.icGridRS,"TCLName") 171 | 172 | 173 | Admin 174 | THIS.ilAllowDebug = .F. 175 | 176 | 177 | Admin 178 | THIS.ShowTips = .T. 179 | 180 | 181 | Admin 182 | THIS.ilHonorTestPrefix = .F. 183 | 184 | 185 | Admin 186 | THIS.ilReloadTestsOnRun = .F. 187 | 188 | 189 | Admin 190 | THIS.ilCloseDebuggerAtEndOfTestsRun = .F. 191 | 192 | 193 | Admin 194 | THIS.nSplitterPosition = 252 195 | 196 | 197 | -------------------------------------------------------------------------------- /Tests/FXUPersistGetTemplate.XML: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Admin 34 | THIS.Top = 13 35 | 36 | 37 | Admin 38 | THIS.Left = 56 39 | 40 | 41 | Admin 42 | THIS.Height = IIF(VERSION(5)>=900,431,431) 43 | 44 | 45 | Admin 46 | THIS.Width = IIF(VERSION(5)>=900,638,638) 47 | 48 | 49 | Admin 50 | THIS.chkProcedure.Value = .F. 51 | 52 | 53 | Admin 54 | THIS.chkTab.Value = .T. 55 | 56 | 57 | Admin 58 | THIS.lstTemplates.Value = 3 59 | 60 | 61 | -------------------------------------------------------------------------------- /Tests/FXUResults.FPT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulvfp/ajaxRest/266e9fe6e6180f456276a5d6e34ea7067c28e8a4/Tests/FXUResults.FPT -------------------------------------------------------------------------------- /Tests/test_ajaxRest.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulvfp/ajaxRest/266e9fe6e6180f456276a5d6e34ea7067c28e8a4/Tests/test_ajaxRest.prg -------------------------------------------------------------------------------- /socktoaster.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "raulvfp/ajaxRest", 3 | "description": "Permite la conexion a WebServices mediante los HTTP verbs. Servicios XML/jSon/txt etc", 4 | "authors": [ 5 | { 6 | "name": "Raúl Juárez", 7 | "email": "raul.jrz@gmail.com", 8 | "homepage": "http://rauljrz.github.io/", 9 | "role": "Developer" 10 | } 11 | ], 12 | "version": "1.0.0", 13 | "require": { 14 | "vfp": "^9.00", 15 | "raulvfp/catchException": "1.0.*" 16 | }, 17 | "repositories": [ 18 | { 19 | "type": "socktoaster", 20 | "url": "http://www.socktoaster.com" 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /src/ajaxRest.prg: -------------------------------------------------------------------------------- 1 | * 2 | *|-------------------------------------------------------------------------- 3 | *| ajaxRest 4 | *|-------------------------------------------------------------------------- 5 | *| 6 | *| Archivo principal del sistema 7 | *| Author......: Raúl Jrz (raul.jrz@gmail.com) 8 | *| Created.....: 19.05.2018 17:19 9 | *| Purpose.....: realizar conexiones ajax usando MSXML2.ServerXMLHTTP 10 | *| 11 | *| Revisions...: v1.00 12 | *| 13 | */ 14 | *-----------------------------------------------------------------------------------* 15 | DEFINE CLASS ajaxRest AS CUSTOM 16 | * 17 | *-----------------------------------------------------------------------------------* 18 | bRelanzarThrow = .T. &&Relanza la excepcion al nivel superior, usado por catchException 19 | 20 | PROTECTED loHeader, loParameter 21 | loHeader = '' &&Objeto que contiene las cabeceras de la conexion 22 | loParameter = '' &&Objeto que contiene los parametros que se pasara a la url 23 | 24 | urlRequest = '' 25 | method = '' &&Posibles valores: POST,GET,PUT,DELETE,HEAD,CONNECT,OPTIONS,TRACE,PATCH 26 | Body = '' 27 | pathDownload = '' &&Path en donde se descargaran los archivos 28 | pathUpload = '' &&Path en donde recide los archivos a subir 29 | pathLog = '' &&Path en donde se guarda los log, si es que esta activo el log. 30 | nameLog = 'ajaxRest.log' &&Es el log de los procesos 31 | isVerbose = .F. &&Si hay eco o no en la pantalla de las acciones. 32 | isLogger = .F. &&indica si lleva un log con los registros de los sucesos. 33 | 34 | 35 | *-- repuesta del servidor 36 | PROTECTED responseValue 37 | readystate = '' 38 | responsebody = '' 39 | responseValue = '' 40 | status = 0 41 | ResponseHeader = '' 42 | ResponseCnType = '' &&Es el valor de Content-Type por el webservice, que identifica si es un archivo o no 43 | ResponseCnLeng = '' &&Si es una archivo, aqui viene la longitud en byte. Ojo, es un nro en CARACTER 44 | 45 | *-- Estados 46 | *-- 100-Continue 101-Switching protocols 200-OK 47 | *-- 201-Created 202-Accepted 203-Non-Authoritative Information 48 | *-- 204-No Content 205-Reset Content 206-Partial Content 49 | *-- 300-Multiple Choices 301-Moved Permanently 302-Found 50 | *-- 303-See Other 304-Not Modified 305-Use Proxy 51 | *-- 307-Temporary Redirect 400-Bad Request 401-Unauthorized 52 | *-- 402-Payment Required 403-Forbidden 404-Not Found 53 | *-- 405-Method Not Allowed 406-Not Acceptable 407-Proxy Authentication Required 54 | *-- 408-Request Timeout 409-Conflict 410-Gone 55 | *-- 411-Length Required 412-Precondition Failed 413-Request Entity Too Large 56 | *-- 414-Request-URI Too Long 415-Unsupported Media Type 416-Requested Range Not Suitable 57 | *-- 417-Expectation Failed 500-Internal Server Error 501-Not Implemented 58 | *-- 502-Bad Gateway 503-Service Unavailable 504-Gateway Timeout 59 | *-- 505-HTTP Version Not Supported 60 | statustext = '' 61 | 62 | *----------------------------------------------------------------------------* 63 | FUNCTION INIT 64 | * Inicio el objeto creando dos Objetos EMTPY uno para los HEADER y otro para los 65 | * PARAMETERS. 66 | * Ademas defino Headers por default, pero que luego el programador puede cambiar 67 | *----------------------------------------------------------------------------* 68 | THIS.loParameter= CREATEOBJECT('empty') 69 | THIS.loHeader = CREATEOBJECT('empty') 70 | 71 | *-- Valores por default --* 72 | THIS.addHeader("Content-Type" ,'application/x-www-form-urlencoded') 73 | THIS.addHeader("HttpVersion" ,'1.1') 74 | THIS.addHeader("UserAgent" ,'FoxPro/9.0') 75 | *THIS.TypeNotArchive = 'application/json,text/plain,application/octet-stream' 76 | 77 | TEXT TO loTiposdeMime NOSHOW 78 | *-- Tipos de Content-Type --* 79 | *-- https://developer.mozilla.org/es/docs/Web/HTTP/Basics_of_HTTP/MIME_types 80 | Type Description Example of typical subtypes 81 | ---- ------------------------------ -------- 82 | text Represents any document that contains text and is theoretically human readable text/plain, text/html, 83 | text/css, text/javascript 84 | image Represents any kind of images. image/gif, image/png, 85 | image/jpeg, image/bmp 86 | audio Represents any kind of audio files audio/midi, audio/mpeg, 87 | audio/webm, audio/ogg 88 | video Represents any kind of video files video/webm, video/ogg 89 | application Represents any kind of binary data. application/octet-stream, 90 | application/pkcs12, 91 | application/vnd.mspowerpoint 92 | *-- 93 | Extensión Tipo de documento Tipo de MIME 94 | --------- ----------------- ------------ 95 | .aac AAC audio file audio/aac 96 | .abw AbiWord document application/x-abiword 97 | .arc Archive document (multiple files embedded) application/octet-stream 98 | .avi AVI: Audio Video Interleave video/x-msvideo 99 | .azw Amazon Kindle eBook format application/vnd.amazon.ebook 100 | .bin Any kind of binary data application/octet-stream 101 | .bz BZip archive application/x-bzip 102 | .bz2 BZip2 archive application/x-bzip2 103 | .csh C-Shell script application/x-csh 104 | .css Cascading Style Sheets (CSS) text/css 105 | .csv Comma-separated values (CSV) text/csv 106 | .doc Microsoft Word application/msword 107 | .epub Electronic publication (EPUB) application/epub+zip 108 | .gif Graphics Interchange Format (GIF) image/gif 109 | .htm HyperText Markup Language (HTML) text/html 110 | .html HyperText Markup Language (HTML) text/html 111 | .ico Icon format image/x-icon 112 | .ics iCalendar format text/calendar 113 | .jar Java Archive (JAR) application/java-archive 114 | .jpeg JPEG images image/jpeg 115 | .jpg JPEG images image/jpeg 116 | .js JavaScript (ECMAScript) application/javascript 117 | .json JSON format application/json 118 | .mid Musical Instrument Digital Interface (MIDI) audio/midi 119 | .mpeg MPEG Video video/mpeg 120 | .mpkg Apple Installer Package application/vnd.apple.installer+xml 121 | .odp OpenDocuemnt presentation document application/vnd.oasis.opendocument.presentation 122 | .ods OpenDocuemnt spreadsheet document application/vnd.oasis.opendocument.spreadsheet 123 | .odt OpenDocument text document application/vnd.oasis.opendocument.text 124 | .oga OGG audio audio/ogg 125 | .ogv OGG video video/ogg 126 | .ogx OGG application/ogg 127 | .pdf Adobe Portable Document Format (PDF) application/pdf 128 | .ppt Microsoft PowerPoint application/vnd.ms-powerpoint 129 | .rar RAR archive application/x-rar-compressed 130 | .rtf Rich Text Format (RTF) application/rtf 131 | .sh Bourne shell script application/x-sh 132 | .svg Scalable Vector Graphics (SVG) image/svg+xml 133 | .swf Adobe Flash document application/x-shockwave-flash 134 | .tar Tape Archive (TAR) application/x-tar 135 | .tif Tagged Image File Format (TIFF) image/tiff 136 | .ttf TrueType Font font/ttf 137 | .vsd Microsft Visio application/vnd.visio 138 | .wav Waveform Audio Format audio/x-wav 139 | .weba WEBM audio audio/webm 140 | .webm WEBM video video/webm 141 | .webp WEBP image image/webp 142 | .woff Web Open Font Format (WOFF) font/woff 143 | .woff2 Web Open Font Format (WOFF) font/woff2 144 | .xhtml XHTML application/xhtml+xml 145 | .xls Microsoft Excel application/vnd.ms-excel 146 | .xml XML application/xml 147 | .xul XUL application/vnd.mozilla.xul+xml 148 | .zip ZIP archive application/zip 149 | .3gp 3GPP audio/video container video/3gpp 150 | .3gp 3GPP audio container audio/3gpp 151 | .3g2 3GPP2 audio/video container video/3gpp2 152 | .3g2 3GPP2 audio container audio/3gpp2 153 | .7z 7-zip archive application/x-7z-compressed 154 | ENDTEXT 155 | ENDFUNC 156 | 157 | *----------------------------------------------------------------------------* 158 | FUNCTION method_Assign(teValue) 159 | * Este metodo ASSIGN me permite validar lo que el verbo HTTP que se usara 160 | * para comunicarse con el servidor REST 161 | *----------------------------------------------------------------------------* 162 | LOCAL lcListMethod, lcMessage 163 | lcMessage = 'Error, el verbo no es el correcto' 164 | TRY 165 | lcListMethod = 'POST,GET,PUT,DELETE,HEAD,CONNECT,OPTIONS,TRACE,PATCH' 166 | IF !(teValue $ lcListMethod) THEN 167 | IF THIS.isVerbose THEN 168 | WAIT WINDOWS lcMessage 169 | ENDIF 170 | THROW lcMessage 171 | ENDIF 172 | THIS.method = teValue 173 | CATCH TO loEx 174 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 175 | ENDTRY 176 | ENDFUNC 177 | 178 | *----------------------------------------------------------------------------* 179 | FUNCTION urlRequest_Assign(teValue) 180 | * Este metodo ASSIGN me permite validar la URL ingresada 181 | *----------------------------------------------------------------------------* 182 | LOCAL lcListMethod 183 | TRY 184 | THIS.urlRequest = STRTRAN(teValue,'\/',"/") 185 | CATCH TO loEx 186 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 187 | ENDTRY 188 | ENDFUNC 189 | 190 | *----------------------------------------------------------------------------* 191 | FUNCTION addHeader(tcKey, tcValue) 192 | * Agrega un elemento al header 193 | *----------------------------------------------------------------------------* 194 | LOCAL lcKey 195 | TRY 196 | && lo combierto a Hexadecimal para evitar conflictos con caracteres 197 | && en la definicion de propiedades del objeto VFP. 198 | lcKey = '_'+STRCONV(tcKey,15) 199 | IF PEMSTATUS(THIS.loHeader, lcKey, 5) THEN 200 | THIS.loHeader.&lcKey = tcValue 201 | ELSE 202 | ADDPROPERTY(THIS.loHeader, lcKey, tcValue) 203 | ENDIF 204 | CATCH TO loEx 205 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 206 | ENDTRY 207 | ENDFUNC 208 | 209 | *----------------------------------------------------------------------------* 210 | FUNCTION addParameter(tcKey, tcValue) 211 | * Agrega un elemento a los parametros 212 | *----------------------------------------------------------------------------* 213 | LOCAL lcKey 214 | TRY 215 | && lo combierto a Hexadecimal para evitar conflictos con caracteres 216 | && en la definicion de propiedades del objeto VFP. 217 | lcKey = '_'+STRCONV(tcKey,15) 218 | IF PEMSTATUS(THIS.loHeader, lcKey, 5) THEN 219 | THIS.loParameter.&lcKey = tcValue 220 | ELSE 221 | ADDPROPERTY(THIS.loParameter, lcKey, tcValue) 222 | ENDIF 223 | CATCH TO loEx 224 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 225 | ENDTRY 226 | ENDFUNC 227 | 228 | *----------------------------------------------------------------------------* 229 | FUNCTION createConnection 230 | * Test with all XML Versions 231 | * Can also apply the info from http://support.microsoft.com/kb/278674/en-us 232 | * to determine what version of MSXML is installed in the machine 233 | *----------------------------------------------------------------------------* 234 | LOCAL loConnection 235 | THIS.initResponse() 236 | TRY 237 | loConnection = CREATEOBJECT("MSXML2.ServerXMLHTTP.4.0") 238 | CATCH 239 | TRY 240 | loConnection = CREATEOBJECT("MSXML2.ServerXMLHTTP.3.0") 241 | CATCH 242 | TRY 243 | loConnection = CREATEOBJECT("MSXML2.ServerXMLHTTP.5.0") 244 | CATCH 245 | TRY 246 | loConnection = CREATEOBJECT("MSXML2.ServerXMLHTTP.6.0") 247 | CATCH 248 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 249 | ENDTRY 250 | ENDTRY 251 | ENDTRY 252 | ENDTRY 253 | RETURN loConnection 254 | ENDFUNC 255 | 256 | *----------------------------------------------------------------------------* 257 | PROTECTED FUNCTION initResponse 258 | * Inicializo todas las propiedades que maneja el response 259 | *----------------------------------------------------------------------------* 260 | THIS.readystate = '' 261 | THIS.responsebody = '' 262 | THIS.responseValue = '' 263 | THIS.status = 0 264 | THIS.ResponseHeader = '' 265 | THIS.ResponseCnType = '' &&Es el valor de Content-Type por el webservice, que identifica si es un archivo o no 266 | THIS.ResponseCnLeng = '' &&Si es una archivo, aqui viene la longitud en byte. Ojo, es un nro en CARACTER 267 | ENDFUNC 268 | 269 | *----------------------------------------------------------------------------* 270 | FUNCTION SEND 271 | * Realiza la conexion con el servidor. 272 | *----------------------------------------------------------------------------* 273 | LOCAL loXMLHTTP, lcMessage,; 274 | lcKey, lnCnt, lnInd 275 | lcMessage = '' 276 | 277 | THIS.logger('=====[request]=====') 278 | loXMLHTTP = THIS.createConnection() 279 | TRY 280 | WITH loXMLHTTP AS MSXML2.XMLHTT 281 | *--- Cargo los Parametros de la peticion --- * 282 | lnCnt = AMEMBERS(laProperties, THIS.loParameter, 0) 283 | lcParameter='' 284 | FOR lnInd = 1 TO lnCnt 285 | lcKey = laProperties[lnInd] 286 | lcParameter = lcParameter + STRCONV(lcKey, 16) +'='+THIS.loParameter.&lcKey + "&" 287 | ENDFOR 288 | lcParameter = SUBSTR(lcParameter,1,LEN(lcParameter)-1) &&le quito el ultomo "&" 289 | IF !EMPTY(lcParameter) THEN 290 | lcParameter = "?"+lcParameter &&Le agrego antes de los parametros el '?' 291 | ENDIF 292 | THIS.logger('Parameters: '+lcParameter) 293 | 294 | *--- Abro la conexion, enviando los parametros ---* 295 | .OPEN(THIS.method, THIS.urlRequest+lcParameter, .F.) 296 | *--- Cargo el Header de la peticion --- * 297 | lnCnt = AMEMBERS(laProperties, THIS.loHeader, 0) 298 | FOR lnInd = 1 TO lnCnt 299 | lcKey = laProperties[lnInd] 300 | .setRequestHeader(STRCONV(lcKey, 16), THIS.loHeader.&lcKey) 301 | THIS.logger('Header: '+STRCONV(lcKey, 16)+" "+THIS.loHeader.&lcKey) 302 | ENDFOR 303 | 304 | THIS.logger('Body: '+CHR(13)+CHR(10)+THIS.Body) 305 | .SEND(THIS.Body) 306 | 307 | *--- Determino que tipo de repuesta recibi ---* 308 | THIS.ResponseHeader = .getAllResponseHeaders 309 | THIS.ResponseCnType = THIS.getOneHeader('Content-Type:') 310 | THIS.ResponseCnLeng = THIS.getOneHeader('Content-Length:') &&Si es distinto de "" es un archivo. 311 | 312 | TRY 313 | IF VAL(THIS.ResponseCnLeng)=0 OR; 314 | LEN(.ResponseText)=VAL(THIS.ResponseCnLeng) 315 | lcMessage = .ResponseText 316 | ELSE 317 | lcMessage = .ResponseBody 318 | ENDIF 319 | CATCH TO loExAux 320 | lcMessage = .ResponseBody 321 | ENDTRY 322 | 323 | THIS.logger('=====[response]=====') 324 | THIS.logger(THIS.ResponseHeader) 325 | THIS.logger(lcMessage) 326 | ENDWITH 327 | 328 | CATCH TO loEx 329 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 330 | FINALLY 331 | THIS.readyState =loXMLHTTP.readyState 332 | THIS.responseBody =loXMLHTTP.responseBody 333 | THIS.responseValue=lcMessage 334 | THIS.status =loXMLHTTP.status 335 | THIS.statusText =loXMLHTTP.statusText 336 | 337 | IF VARTYPE(loEx)='O' THEN &&Si se produjo una excepcion, busco mostrar el status en el nivel superior 338 | STRTOFILE(loXMLHTTP.getAllResponseHeaders, 'loghttp.log', 1) 339 | loEx.userValue = '{"status": ' + TRANSFORM(THIS.status) ; 340 | +', "statusText": "'+THIS.statusText+'"'; 341 | +'}' 342 | ENDIF 343 | 344 | loXMLHTTP = NULL 345 | ENDTRY 346 | RETURN lcMessage 347 | ENDFUNC 348 | 349 | *----------------------------------------------------------------------------* 350 | FUNCTION saveFile(tcNameFile) 351 | * Si lo que se recibe es un archivo, lo guarda en el THIS.pathDownload 352 | *----------------------------------------------------------------------------* 353 | LOCAL lnReturn, lcNameFile 354 | lnReturn = -1 355 | TRY 356 | *-- Verifico si existe el directorio, de lo contrario lo creo. 357 | THIS.pathDownload = THIS.isFolderExist(THIS.pathDownload) 358 | 359 | *-- Verifico el nombre del archivo, si no tengo genero uno con extension tmp. 360 | lcNameFile = IIF(PCOUNT()=1, ALLTRIM(tcNameFile), SYS(3)+'.tmp') 361 | lnReturn = STRTOFILE(THIS.getResponse(), ADDBS(THIS.pathDownload)+lcNameFile, .F.) 362 | CATCH TO loEx 363 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 364 | ENDTRY 365 | RETURN lnReturn 366 | ENDFUNC 367 | 368 | *----------------------------------------------------------------------------* 369 | PROTECTED FUNCTION isFolderExist(tcFolder) 370 | * Verifica que exista la carpeta. 371 | *----------------------------------------------------------------------------* 372 | LOCAL lcFolder 373 | TRY 374 | lcFolder = ALLTRIM(tcFolder) 375 | IF !EMPTY(lcFolder) THEN 376 | IF RIGHT(lcFolder,1) = '\' THEN 377 | lcFolder = SUBSTR(lcFolder,1,LEN(lcFolder)-1) 378 | ENDIF 379 | 380 | IF !DIRECTORY(lcFolder) THEN 381 | MKDIR (lcFolder) 382 | ENDIF 383 | ENDIF 384 | CATCH TO loEx 385 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 386 | ENDTRY 387 | RETURN lcFolder 388 | ENDFUNC 389 | 390 | *----------------------------------------------------------------------------* 391 | PROTECTED FUNCTION logger(tcMessageLog) 392 | * Guarda una log del proceso en un archivo. 393 | *----------------------------------------------------------------------------* 394 | TRY 395 | IF THIS.isLogger THEN 396 | THIS.pathLog = THIS.isFolderExist(THIS.pathLog) 397 | THIS.nameLog = IIF(EMPTY(THIS.nameLog),'ajaxrest.log',ALLTRIM(THIS.nameLog)) 398 | STRTOFILE(tcMessageLog+CHR(13)+CHR(10), ADDBS(THIS.pathLog)+THIS.nameLog,.T.) 399 | ENDIF 400 | 401 | CATCH TO loEx 402 | oTmp = CREATEOBJECT('catchException',THIS.bRelanzarThrow) 403 | ENDTRY 404 | ENDFUNC 405 | 406 | *----------------------------------------------------------------------------* 407 | FUNCTION getResponse() 408 | * Devuelve el response de la comunicacion. 409 | *----------------------------------------------------------------------------* 410 | RETURN THIS.responseValue 411 | ENDFUNC 412 | 413 | *----------------------------------------------------------------------------* 414 | FUNCTION getOneHeader(tcFindHeader) 415 | * Busca una de las propiedades recibidas por getAllResponseHeaders() 416 | *----------------------------------------------------------------------------* 417 | LOCAL lcOneHeader, lcAux1 418 | lcOneHeader = '' 419 | lnPos = AT(tcFindHeader,THIS.ResponseHeader) &&Si es 0, no existe en la recepcion 420 | IF lnPos>0 THEN 421 | lcAux1 = ALLTRIM(SUBSTR(THIS.ResponseHeader,lnPos+LEN(tcFindHeader))) 422 | lcOneHeader = SUBSTR(lcAux1,1,AT(CHR(13),lcAux1)-1) 423 | ENDIF 424 | RETURN lcOneHeader 425 | ENDFUNC 426 | 427 | ENDDEFINE --------------------------------------------------------------------------------