├── .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
--------------------------------------------------------------------------------