Merge lp:~zorba-coders/zorba/http-client-wrapper into lp:zorba
- http-client-wrapper
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 11567 |
Proposed branch: | lp:~zorba-coders/zorba/http-client-wrapper |
Merge into: | lp:zorba |
Diff against target: |
1563 lines (+787/-675) 3 files modified
modules/http-client/CMakeLists.txt (+4/-0) modules/http-client/conv/http-client-wrapper.xq (+772/-0) modules/http-client/xml/http-client.xq (+11/-675) |
To merge this branch: | bzr merge lp:~zorba-coders/zorba/http-client-wrapper |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cezar Andrei | Approve | ||
Chris Hillery | Approve | ||
Review via email: mp+176980@code.launchpad.net |
Commit message
HTTP client request/response conversion in a separate module
Description of the change
HTTP client request/response conversion in a separate module
Federico Cavalieri (fcavalieri) wrote : | # |
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue starting for the following merge proposals:
https:/
Progress dashboard at http://
Zorba Build Bot (zorba-buildbot) wrote : | # |
Voting criteria failed for the following merge proposals:
https:/
Votes: {'Pending': 2, 'Needs commit message': 1}
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue result for https:/
Stage "CommitZorba" failed.
Check console output at http://
Chris Hillery (ceejatec) : | # |
Cezar Andrei (cezar-andrei) : | # |
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue starting for the following merge proposals:
https:/
Progress dashboard at http://
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue result for https:/
Stage "AddTestSuitesU
Check console output at http://
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue succeeded - proposal merged!
Preview Diff
1 | === modified file 'modules/http-client/CMakeLists.txt' |
2 | --- modules/http-client/CMakeLists.txt 2013-07-25 09:30:55 +0000 |
3 | +++ modules/http-client/CMakeLists.txt 2013-07-25 15:45:37 +0000 |
4 | @@ -39,6 +39,10 @@ |
5 | DECLARE_ZORBA_MODULE(FILE json/http-client.xq VERSION 1.0 |
6 | URI "http://zorba.io/modules/http-client" |
7 | LINK_LIBRARIES ${CURL_LIBRARIES}) |
8 | + |
9 | + DECLARE_ZORBA_MODULE(FILE conv/http-client-wrapper.xq VERSION 1.0 |
10 | + URI "http://zorba.io/modules/http-client-wrapper" |
11 | + LINK_LIBRARIES ${CURL_LIBRARIES}) |
12 | |
13 | IF (WIN32) # Copy certificates for windows only |
14 | IF (MSVC_IDE) |
15 | |
16 | === added directory 'modules/http-client/conv' |
17 | === added file 'modules/http-client/conv/http-client-wrapper.xq' |
18 | --- modules/http-client/conv/http-client-wrapper.xq 1970-01-01 00:00:00 +0000 |
19 | +++ modules/http-client/conv/http-client-wrapper.xq 2013-07-25 15:45:37 +0000 |
20 | @@ -0,0 +1,772 @@ |
21 | +xquery version "3.0"; |
22 | + |
23 | +(: |
24 | + : Copyright 2006-2009 The FLWOR Foundation. |
25 | + : |
26 | + : Licensed under the Apache License, Version 2.0 (the "License"); |
27 | + : you may not use this file except in compliance with the License. |
28 | + : You may obtain a copy of the License at |
29 | + : |
30 | + : http://www.apache.org/licenses/LICENSE-2.0 |
31 | + : |
32 | + : Unless required by applicable law or agreed to in writing, software |
33 | + : distributed under the License is distributed on an "AS IS" BASIS, |
34 | + : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
35 | + : See the License for the specific language governing permissions and |
36 | + : limitations under the License. |
37 | +:) |
38 | + |
39 | + |
40 | +(:~ |
41 | + : <p>This module provides conversion functions between the |
42 | + : XML Expath http-client request and response formats and the |
43 | + : JSON http-client request and response formats used by the |
44 | + : <code>http://zorba.io/modules/http-client</code> module. |
45 | + : </p> |
46 | + : |
47 | + : <p>This module is reserved for internal use by the |
48 | + : <code>http://www.zorba-xquery.com/modules/http-client</code> and the |
49 | + : <code>http://expath.org/ns/http-client</code> modules. |
50 | + : This module may be removed at any time. Method signature and |
51 | + : semantics may change. |
52 | + : </p> |
53 | + : |
54 | + : @author Federico Cavalieri |
55 | + : @project Zorba/Input Output/HTTP Client |
56 | + :) |
57 | +module namespace http-wrapper = "http://zorba.io/modules/http-client-wrapper"; |
58 | + |
59 | +import module namespace error = "http://expath.org/ns/error"; |
60 | +import module namespace json-http = "http://zorba.io/modules/http-client"; |
61 | +import module namespace libjn = "http://jsoniq.org/function-library"; |
62 | + |
63 | +import schema namespace http-schema = "http://expath.org/ns/http-client"; |
64 | + |
65 | +declare namespace an = "http://www.zorba-xquery.com/annotations"; |
66 | +declare namespace ver = "http://www.zorba-xquery.com/options/versioning"; |
67 | +declare namespace err = "http://www.w3.org/2005/xqt-errors"; |
68 | +declare namespace ser = "http://www.w3.org/2010/xslt-xquery-serialization"; |
69 | +declare namespace jn = "http://jsoniq.org/functions"; |
70 | + |
71 | +declare option ver:module-version "1.0"; |
72 | + |
73 | +(:~ |
74 | + : <p>This function sends an HTTP request and returns the corresponding response. |
75 | + : This function is declared sequential and can be used to issue |
76 | + : requests which change the state of the server.</p> |
77 | + : |
78 | + : <p>Its inputs, outputs, and behavior are identical to the |
79 | + : <a href="http://expath.org/spec/http-client">EXPath http-client</a>'s |
80 | + : send-request() function (except that HTML responses are not tidied |
81 | + : into XML - see <a href="#expath_relation">the note above</a>). It |
82 | + : is provided here for use in Zorba installations that do not have |
83 | + : the EXPath module available. If you have the option of using the |
84 | + : EXPath module instead of this function, please do so, as it will |
85 | + : allow your application to be more interoperable between different |
86 | + : XQuery engines.</p> |
87 | + : |
88 | + : <p>Full documentation of the $request parameter can be found in |
89 | + : <a href="http://expath.org/spec/http-client#d2e183">the EXPath |
90 | + : specification</a>.</p> |
91 | + : |
92 | + : @param $request Contains the various parameters of the request (see above). |
93 | + : @param $href The URL to which the request will be made (see |
94 | + : <a href="#url_string">note</a> above). If this |
95 | + : parameter is specified, it will override the "href" attribute of |
96 | + : $request. |
97 | + : @param $bodies is the request body content, for HTTP methods that can |
98 | + : contain a body in the request (i.e. POST and PUT). It is an error if this |
99 | + : param is not the empty sequence for methods |
100 | + : @return <a href="#standard_return">standard http-client return type</a>. |
101 | + : |
102 | + : @error error:HC001 An HTTP error occurred. |
103 | + : @error error:HC002 Error parsing the response content as XML. |
104 | + : @error error:HC003 With a multipart response, the override-media-type must be either a multipart media type or application/octet-stream. |
105 | + : @error error:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type). |
106 | + : @error error:HC005 The input request element is not valid. |
107 | + : @error error:HC006 A timeout occurred waiting for the response. |
108 | + : @error error:HCV02 Trying to follow a redirect of a POST, PUT, or DELETE request |
109 | +~:) |
110 | +declare %an:sequential function http-wrapper:http-sequential-request( |
111 | + $request as element()?, |
112 | + $href as xs:string?, |
113 | + $bodies as item()*) as item()+ |
114 | +{ |
115 | + try |
116 | + { |
117 | + { |
118 | + variable $json-request := http-wrapper:json-request($request, $href, $bodies); |
119 | + variable $json-response := json-http:send-request($json-request); |
120 | + variable $xml-response := http-wrapper:xml-response($json-response, fn:data($request/@override-media-type)); |
121 | + $xml-response |
122 | + } |
123 | + } catch XPTY0004 { |
124 | + fn:error($error:HC005, "The input request element is not valid.") |
125 | + } catch json-http:HTTP { |
126 | + fn:error($error:HC001, "An HTTP error occurred.") |
127 | + } catch json-http:REQUEST { |
128 | + fn:error($error:HC005, "The input request element is not valid.") |
129 | + } catch json-http:TIMEOUT { |
130 | + fn:error($error:HC006, "A timeout occurred waiting for the response.") |
131 | + } catch json-http:FOLLOW { |
132 | + fn:error($error:HCV02, "Trying to follow a redirect of a POST, PUT, or DELETE request.") |
133 | + } catch json-http:CHARSET { |
134 | + fn:error($error:HC005, "The input request element is not valid: invalid charset specified.") |
135 | + } catch * { |
136 | + fn:error(fn:QName($error:errNS, fn:local-name-from-QName($err:code)),$err:description, $err:value) |
137 | + } |
138 | +}; |
139 | + |
140 | +(:~ |
141 | + : <p>This function sends an HTTP request and returns the corresponding response. |
142 | + : This function is declared non-deterministic and should only be used to issue |
143 | + : requests which do not change the state of the server.</p> |
144 | + : |
145 | + : <p>Its inputs, outputs, and behavior are identical to the |
146 | + : <a href="http://expath.org/spec/http-client">EXPath http-client</a>'s |
147 | + : send-request() function (except that HTML responses are not tidied |
148 | + : into XML - see <a href="#expath_relation">the note above</a>). It |
149 | + : is provided here for use in Zorba installations that do not have |
150 | + : the EXPath module available. If you have the option of using the |
151 | + : EXPath module instead of this function, please do so, as it will |
152 | + : allow your application to be more interoperable between different |
153 | + : XQuery engines.</p> |
154 | + : |
155 | + : <p>Full documentation of the $request parameter can be found in |
156 | + : <a href="http://expath.org/spec/http-client#d2e183">the EXPath |
157 | + : specification</a>.</p> |
158 | + : |
159 | + : @param $request Contains the various parameters of the request (see above). |
160 | + : @param $href The URL to which the request will be made (see |
161 | + : <a href="#url_string">note</a> above). If this |
162 | + : parameter is specified, it will override the "href" attribute of |
163 | + : $request. |
164 | + : @param $bodies is the request body content, for HTTP methods that can |
165 | + : contain a body in the request (i.e. POST and PUT). It is an error if this |
166 | + : param is not the empty sequence for methods |
167 | + : @return <a href="#standard_return">standard http-client return type</a>. |
168 | + : |
169 | + : @error error:HC001 An HTTP error occurred. |
170 | + : @error error:HC002 Error parsing the response content as XML. |
171 | + : @error error:HC003 With a multipart response, the override-media-type must be either a multipart media type or application/octet-stream. |
172 | + : @error error:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type). |
173 | + : @error error:HC005 The input request element is not valid. |
174 | + : @error error:HC006 A timeout occurred waiting for the response. |
175 | + : @error error:HCV02 Trying to follow a redirect of a POST, PUT, or DELETE request |
176 | +~:) |
177 | +declare %an:nondeterministic function http-wrapper:http-nondeterministic-request( |
178 | + $request as element()?, |
179 | + $href as xs:string?, |
180 | + $bodies as item()*) as item()+ |
181 | +{ |
182 | + try |
183 | + { |
184 | + { |
185 | + variable $json-request := http-wrapper:json-request($request, $href, $bodies); |
186 | + variable $json-response := json-http:send-nondeterministic-request($json-request); |
187 | + variable $xml-response := http-wrapper:xml-response($json-response, fn:data($request/@override-media-type)); |
188 | + $xml-response |
189 | + } |
190 | + } catch XPTY0004 { |
191 | + fn:error($error:HC005, "The input request element is not valid.") |
192 | + } catch json-http:HTTP { |
193 | + fn:error($error:HC001, "An HTTP error occurred.") |
194 | + } catch json-http:REQUEST { |
195 | + fn:error($error:HC005, "The input request element is not valid.") |
196 | + } catch json-http:TIMEOUT { |
197 | + fn:error($error:HC006, "A timeout occurred waiting for the response.") |
198 | + } catch json-http:FOLLOW { |
199 | + fn:error($error:HCV02, "Trying to follow a redirect of a POST, PUT, or DELETE request.") |
200 | + } catch json-http:CHARSET { |
201 | + fn:error($error:HC005, "The input request element is not valid: invalid charset specified.") |
202 | + } catch * { |
203 | + fn:error(fn:QName($error:errNS, fn:local-name-from-QName($err:code)),$err:description, $err:value) |
204 | + } |
205 | +}; |
206 | + |
207 | + |
208 | +(: |
209 | + : JSON Response to XML Response Conversion |
210 | + :) |
211 | + |
212 | +(:~ |
213 | + : Private function used internally by this module. |
214 | + : |
215 | + : This function accepts a JSON HTTP module response, as |
216 | + : used by the http://zorba.io/modules/http-client module |
217 | + : and returns its EXPath XML representation. |
218 | + : |
219 | + : @param $response a JSON response representation. |
220 | + : @param $override-media-type if specified, is used in place of all |
221 | + : body media-types in the response. |
222 | + : @return EXPath XML response representation. |
223 | + : @error error:HC002 Error parsing the response content as XML. |
224 | + :) |
225 | +declare %private function http-wrapper:xml-response($response as object(), $override-media-type as xs:string?) as item()+ |
226 | +{ |
227 | + validate |
228 | + { |
229 | + element http-schema:response |
230 | + { |
231 | + attribute message {$response("message")}, |
232 | + attribute status {$response("status")}, |
233 | + http-wrapper:xml-headers($response("headers")), |
234 | + http-wrapper:xml-body($response("body")), |
235 | + http-wrapper:xml-multipart($response("multipart")) |
236 | + } |
237 | + }, |
238 | + http-wrapper:get-bodies(libjn:descendant-objects($response)("body"), $override-media-type) |
239 | +}; |
240 | + |
241 | +(:~ |
242 | + : Private function used internally by this module. |
243 | + : |
244 | + : This function accepts a JSON HTTP module response, as |
245 | + : used by the http://zorba.io/modules/http-client module |
246 | + : and returns its EXPath XML representation. |
247 | + : |
248 | + : If the body media-type indicates that the response body |
249 | + : has an XML content, the response body is parsed as XML |
250 | + : before being returned. |
251 | + : |
252 | + : @param $bodies a sequence JSON bodies. |
253 | + : @param $override-media-type if specified, is used in place of all body media-types. |
254 | + : @return body contents. |
255 | + : @error error:HC002 Error parsing the response content as XML. |
256 | + :) |
257 | +declare %private function http-wrapper:get-bodies($bodies as object()*, $override-media-type as xs:string?) as item()* |
258 | +{ |
259 | + for $body in $bodies |
260 | + let $media-type := ($override-media-type, $body("media-type"))[1] |
261 | + let $mime-type := if (fn:contains($media-type,";")) |
262 | + then fn:substring-before($media-type,";") |
263 | + else $media-type |
264 | + return |
265 | + if ($mime-type eq "text/xml" or |
266 | + $mime-type eq "application/xml" or |
267 | + $mime-type eq "text/xml-external-parsed-entity" or |
268 | + $mime-type eq "application/xml-external-parsed-entity" or |
269 | + fn:ends-with($mime-type,"+xml")) |
270 | + then |
271 | + try { |
272 | + parse-xml($body("content"))} |
273 | + catch FODC0006 { |
274 | + fn:error($error:HC002, "Error parsing the response content as XML.")} |
275 | + else $body("content") |
276 | +}; |
277 | + |
278 | +(:~ |
279 | + : Private function used internally by this module. |
280 | + : |
281 | + : This function accepts the headers portion of a JSON HTTP module |
282 | + : response, as used by the http://zorba.io/modules/http-client module |
283 | + : and returns its EXPath XML representation. |
284 | + : |
285 | + : @param $headers JSON representation of an headers set. |
286 | + : @return XML representation of the given headers. |
287 | + :) |
288 | +declare %private function http-wrapper:xml-headers($headers as object()?) as element()* |
289 | +{ |
290 | + if (exists($headers)) |
291 | + then |
292 | + for $header-name in jn:keys($headers) |
293 | + return |
294 | + element http-schema:header |
295 | + { |
296 | + attribute name {$header-name}, |
297 | + attribute value {$headers($header-name)} |
298 | + } |
299 | + else () |
300 | +}; |
301 | + |
302 | + |
303 | +(:~ |
304 | + : Private function used internally by this module. |
305 | + : |
306 | + : This function accepts the body portion of a JSON HTTP module |
307 | + : response, as used by the http://zorba.io/modules/http-client module |
308 | + : and returns its EXPath XML representation. |
309 | + : |
310 | + : @param $body JSON representation of a body. |
311 | + : @return XML representation of the given body. |
312 | + :) |
313 | +declare %private function http-wrapper:xml-body($body as object()?) as element()? |
314 | +{ |
315 | + if(exists($body)) |
316 | + then |
317 | + element http-schema:body |
318 | + { |
319 | + attribute media-type {$body("media-type")} |
320 | + } |
321 | + else () |
322 | +}; |
323 | + |
324 | +(:~ |
325 | + : Private function used internally by this module. |
326 | + : |
327 | + : This function accepts the multipart portion of a JSON HTTP module |
328 | + : response, as used by the http://zorba.io/modules/http-client module |
329 | + : and returns its EXPath XML representation. |
330 | + : |
331 | + : @param $multipart JSON representation of a multipart. |
332 | + : @return XML representation of the given multipart. |
333 | + :) |
334 | +declare %private function http-wrapper:xml-multipart($multipart as object()?) as element()? |
335 | +{ |
336 | + if(exists($multipart)) |
337 | + then |
338 | + element http-schema:multipart |
339 | + { |
340 | + attribute media-type {$multipart("media-type")}, |
341 | + |
342 | + if ($multipart("boundary")) |
343 | + then attribute boundary {$multipart("boundary")} |
344 | + else (), |
345 | + |
346 | + for $part in jn:members($multipart("part")) |
347 | + return |
348 | + ( |
349 | + http-wrapper:xml-headers($part("headers")), |
350 | + http-wrapper:xml-body($part("body")) |
351 | + ) |
352 | + } |
353 | + else () |
354 | +}; |
355 | + |
356 | +(: |
357 | + : XML Request to JSON Request |
358 | + :) |
359 | +(:~ |
360 | + : Private function used internally by this module. |
361 | + : |
362 | + : This function accepts an XML EXPath HTTP request and returns its |
363 | + : JSON representation, as used by the http://zorba.io/modules/http-client |
364 | + : module. |
365 | + : |
366 | + : @param $request XML EXPath HTTP request. |
367 | + : @param $href is the HTTP or HTTPS URI to send the request to. If specified, |
368 | + : any href URI specified in the request element is ignored. |
369 | + : @param $bodies the request bodies content. |
370 | + : @return JSON HTTP request representation. |
371 | + : |
372 | + : @error error:HC005 The specified request object is not valid. |
373 | + :) |
374 | +declare %private function http-wrapper:json-request($request as element()?, $href as xs:string?, $bodies as item()*) as item() |
375 | +{ |
376 | + if (http-wrapper:check-params($request, $href, $bodies)) |
377 | + then |
378 | + { |
379 | + variable $req := if ($request) |
380 | + then try { |
381 | + validate { http-wrapper:set-content-type($request) }} |
382 | + catch XQDY0027 { |
383 | + fn:error($error:HC005, "The request element is not valid.")} |
384 | + else (); |
385 | + {| |
386 | + |
387 | + {"method": if ($req/@method) then $req/@method/string(.) else "GET"}, |
388 | + |
389 | + if ($href) |
390 | + then {"href": $href} |
391 | + else {"href": $req/@href/string(.)}, |
392 | + |
393 | + if ($request) |
394 | + then |
395 | + ( |
396 | + http-wrapper:json-authentication($req), |
397 | + http-wrapper:json-options($req), |
398 | + http-wrapper:json-headers($req/http-schema:header), |
399 | + http-wrapper:json-body($req/http-schema:body,$bodies), |
400 | + http-wrapper:json-multipart($req/http-schema:multipart,$bodies) |
401 | + ) |
402 | + else () |
403 | + |
404 | + |} |
405 | + |
406 | + } |
407 | + else () |
408 | + |
409 | +}; |
410 | + |
411 | +(:~ |
412 | + : Private function used internally by this module. |
413 | + : |
414 | + : This function accepts an XML EXPath HTTP request and returns the |
415 | + : JSON representation of its authentication options, as used by the |
416 | + : http://zorba.io/modules/http-client module. |
417 | + : |
418 | + : @param $request XML EXPath HTTP request. |
419 | + : @return JSON HTTP request authentication representation. |
420 | + :) |
421 | +declare %private function http-wrapper:json-authentication($request as element()) as object()? |
422 | +{ |
423 | + if (xs:boolean($request/@send-authorization/data(.))) |
424 | + then |
425 | + { |
426 | + "authentication" : |
427 | + { |
428 | + "username": $request/@username/string(.), |
429 | + "password": $request/@password/string(.), |
430 | + "auth-method": $request/@auth-method/string(.) |
431 | + } |
432 | + } |
433 | + else () |
434 | +}; |
435 | + |
436 | + |
437 | +(:~ |
438 | + : Private function used internally by this module. |
439 | + : |
440 | + : This function accepts an XML EXPath HTTP request and returns the |
441 | + : JSON representation of its options, as used by the |
442 | + : http://zorba.io/modules/http-client module. |
443 | + : |
444 | + : @param $request XML EXPath HTTP request. |
445 | + : @return JSON HTTP request options representation. |
446 | + :) |
447 | +declare %private function http-wrapper:json-options($request as element()) as object()? |
448 | +{ |
449 | + if ($request/@status-only || $request/@override-media-type || |
450 | + $request/@follow-redirect || $request/@timeout || $request/@user-agent) |
451 | + then |
452 | + { |
453 | + "options": |
454 | + { |
455 | + {| |
456 | + if ($request/@status-only) |
457 | + then {"status-only": xs:boolean($request/@status-only/data(.))} |
458 | + else (), |
459 | + |
460 | + if ($request/@override-media-type) |
461 | + then {"override-media-type": $request/@override-media-type/string(.)} |
462 | + else (), |
463 | + |
464 | + if ($request/@follow-redirect) |
465 | + then {"follow-redirect": xs:boolean($request/@follow-redirect/data(.))} |
466 | + else (), |
467 | + |
468 | + if ($request/@timeout) |
469 | + then {"timeout": $request/@timeout/data(.)} |
470 | + else (), |
471 | + |
472 | + if ($request/@user-agent) |
473 | + then {"user-agent": $request/@user-agent/string(.)} |
474 | + else () |
475 | + |} |
476 | + } |
477 | + } |
478 | + else () |
479 | +}; |
480 | + |
481 | + |
482 | +(:~ |
483 | + : Private function used internally by this module. |
484 | + : |
485 | + : This function accepts a sequence of headers in the XML EXPath HTTP request |
486 | + : format and returns their JSON representation, as used by the |
487 | + : http://zorba.io/modules/http-client module. |
488 | + : |
489 | + : @param $headers XML EXPath HTTP headers. |
490 | + : @return JSON HTTP request headers representation. |
491 | + :) |
492 | +declare %private function http-wrapper:json-headers($headers as element()*) as object()? |
493 | +{ |
494 | + if ($headers) |
495 | + then |
496 | + { |
497 | + "headers": |
498 | + {| |
499 | + for $header in $headers |
500 | + group by $name := $header/@name |
501 | + return {$name: string-join($header/@value,",")} |
502 | + |} |
503 | + } |
504 | + else () |
505 | +}; |
506 | + |
507 | + |
508 | +(:~ |
509 | + : Private function used internally by this module. |
510 | + : |
511 | + : This function accept a body element in the XML EXPath HTTP request |
512 | + : format and returns its JSON representation, as used by the |
513 | + : http://zorba.io/modules/http-client module. |
514 | + : |
515 | + : @param $body XML EXPath HTTP body element. |
516 | + : @param $content body content. |
517 | + : @return JSON HTTP request headers representation. |
518 | + :) |
519 | +declare %private function http-wrapper:json-body($body as element()?, $content as item()*) as object()? |
520 | +{ |
521 | + if ($body) |
522 | + then |
523 | + { |
524 | + "body": |
525 | + {| |
526 | + {"media-type": $body/@media-type/string(.)}, |
527 | + |
528 | + if ($body/@src) |
529 | + then {"src": $body/@src/string(.)} |
530 | + else {"content": http-wrapper:produce-content($body,$content)} |
531 | + |} |
532 | + } |
533 | + else () |
534 | +}; |
535 | + |
536 | +(:~ |
537 | + : Private function used internally by this module. |
538 | + : |
539 | + : This function serializes a request body. |
540 | + : |
541 | + : @param $body request contents. |
542 | + : @return serialized body. |
543 | + :) |
544 | +declare %private function http-wrapper:produce-content($body as element(), $content as item()*) as xs:string |
545 | +{ |
546 | + let $request-body := if ($body/node()) |
547 | + then $body/node() |
548 | + else $content |
549 | + return |
550 | + if ($body/@method eq "binary") |
551 | + then if ($request-body instance of xs:base64Binary or $request-body instance of xs:hexBinary) |
552 | + then $request-body |
553 | + else |
554 | + copy $serialization-parameters := http-wrapper:serialization-parameters($body) |
555 | + modify delete node $serialization-parameters/ser:method |
556 | + return fn:serialize($request-body,$serialization-parameters) |
557 | + else fn:serialize($request-body, http-wrapper:serialization-parameters($body)) |
558 | +}; |
559 | + |
560 | + |
561 | +(:~ |
562 | + : Private function used internally by this module. |
563 | + : |
564 | + : This function accept a body element in the XML EXPath HTTP request |
565 | + : format and returns the serializer parameters to be used to serialize |
566 | + : its content. |
567 | + : |
568 | + : @param $body XML EXPath HTTP body element. |
569 | + : @return serializer parameters. |
570 | + :) |
571 | +declare %private function http-wrapper:serialization-parameters($body as element()) as element() |
572 | +{ |
573 | + element ser:serialization-parameters |
574 | + { |
575 | + http-wrapper:default-serialization-parameters($body), |
576 | + for $option in $body/(@method | @byte-order-mark | @cdata-section-elements | |
577 | + @doctype-public | @doctype-system | @encoding | |
578 | + @escape-uri-attributes | @indent |@normalization-form | |
579 | + @omit-xml-declaration | @standalone | @suppress-indentation | |
580 | + @undeclare-prefixes | @version) |
581 | + return |
582 | + element {QName("http://www.w3.org/2010/xslt-xquery-serialization",local-name($option))} |
583 | + {attribute value {$option/string(.)}} |
584 | + } |
585 | +}; |
586 | + |
587 | +(:~ |
588 | + : Private function used internally by this module. |
589 | + : |
590 | + : This function return this module default serialization parameters. |
591 | + : |
592 | + : @param $body XML EXPath HTTP body element. |
593 | + : @return serializer parameters. |
594 | + :) |
595 | +declare %private function http-wrapper:default-serialization-parameters($body as element()) as element()* |
596 | +{ |
597 | + if ($body/@method/string(.) eq "xml") |
598 | + then |
599 | + ( |
600 | + if ($body/@omit-xml-declaration) |
601 | + then () |
602 | + else |
603 | + element {QName("http://www.w3.org/2010/xslt-xquery-serialization","omit-xml-declaration")} |
604 | + {attribute value {"no"}} |
605 | + ) |
606 | + else () |
607 | +}; |
608 | + |
609 | +(:~ |
610 | + : Private function used internally by this module. |
611 | + : |
612 | + : This function accept a multipart element in the XML EXPath HTTP request |
613 | + : format and returns its JSON representation, as used by the |
614 | + : http://zorba.io/modules/http-client module. |
615 | + : |
616 | + : @param $multipart XML EXPath HTTP multipart element. |
617 | + : @param $bodies multipart bodies content. |
618 | + : @return JSON HTTP request multipart representation. |
619 | + :) |
620 | +declare %private function http-wrapper:json-multipart($multipart as element()?, $bodies as item()*) as object()? |
621 | +{ |
622 | + if ($multipart) |
623 | + then |
624 | + { |
625 | + "multipart": |
626 | + {| |
627 | + {"media-type": $multipart/@media-type/string(.)}, |
628 | + |
629 | + if ($multipart/@boundary) |
630 | + then {"boundary": $multipart/@boundary/string(.)} |
631 | + else (), |
632 | + |
633 | + {"parts": |
634 | + [ |
635 | + let $requests:= $multipart/* |
636 | + for $part in $requests |
637 | + group by $bodies-before:= count($requests[local-name(.) eq "body" and . << $part]) |
638 | + return |
639 | + let $content := |
640 | + if ($part/self::http-schema:body/@src) |
641 | + then () (: The content will be downloaded from the "src" url :) |
642 | + else if ($part/self::http-schema:body/node()) |
643 | + then ($part/self::http-schema:body/node()) (: the content is made by the body children :) |
644 | + else (: the content is the 1+n-th body item, where n is the number of parts |
645 | + before the current one which body has no src attributes and no childrens :) |
646 | + ($bodies[1+count($requests[local-name(.) eq "body" and |
647 | + not(@content) and not(node()) and . << $part/self::http-schema:body])]) |
648 | + return http-wrapper:json-part($part/self::http-schema:header, $part/self::http-schema:body, $content) |
649 | + ]} |
650 | + |} |
651 | + } |
652 | + else () |
653 | +}; |
654 | + |
655 | +(:~ |
656 | + : Private function used internally by this module. |
657 | + : |
658 | + : This function accept a part headers, body and content in the XML |
659 | + : EXPath HTTP request format and returns its JSON representation, as |
660 | + : used by the http://zorba.io/modules/http-client module. |
661 | + : |
662 | + : @param $headers XML EXPath HTTP header elements. |
663 | + : @param $body XML EXPath HTTP body element. |
664 | + : @param $content XML EXPath HTTP body content. |
665 | + : @return JSON HTTP request part representation. |
666 | + :) |
667 | +declare %private function http-wrapper:json-part($headers as element()*, $body as element(), $content as item()*) as item() |
668 | +{ |
669 | + {| |
670 | + http-wrapper:json-headers($headers), |
671 | + http-wrapper:json-body($body,$content) |
672 | + |} |
673 | +}; |
674 | + |
675 | +(:~ |
676 | + : Private function used internally by this module. |
677 | + : |
678 | + : This function checks if the request, href, and bodies parameters |
679 | + : are consistent. |
680 | + : |
681 | + : @param $request The request which needs to be checked. |
682 | + : @param $href The href which needs to be checked. |
683 | + : @param $bodies The bodies element which needs to be checked. |
684 | + : @return true if the parameters are consistent. Otherwise, |
685 | + : this function raises an error. |
686 | + : |
687 | + : @error error:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type). |
688 | + : @error error:HC005 The specified request object is not valid. |
689 | + : |
690 | + :) |
691 | +declare %private function http-wrapper:check-params( |
692 | + $request as element(http-schema:request)?, |
693 | + $href as xs:string?, |
694 | + $bodies as item()*) as xs:boolean { |
695 | + let $multipart := $request/http-schema:multipart |
696 | + let $override := $request/@override-media-type/string(.) |
697 | + let $should-be-empty := |
698 | + for $x in $request//http-schema:body |
699 | + return |
700 | + if ($x/@src and fn:not((fn:count($x/@*) eq 2))) then 1 |
701 | + else () |
702 | + return |
703 | + if (fn:empty($href) and fn:empty($request)) then |
704 | + fn:error($error:HC005, "The request element is not valid.") |
705 | + else if ($href eq "") then |
706 | + fn:error($error:HC005, "The request element is not valid.") |
707 | + else if (not(count($request//http-schema:body[not(exists(node())) and not(exists(@src))]) eq count($bodies))) then |
708 | + fn:error($error:HC005, "The request element is not valid.") |
709 | + else if ($should-be-empty) then |
710 | + fn:error($error:HC004, "The src attribute on the body element is mutually exclusive with all other attributes (except the media-type).") |
711 | + else |
712 | + fn:true() |
713 | +}; |
714 | + |
715 | +(:~ |
716 | + : This adds a default method attribute to all body elements which |
717 | + : don't contain a method attribute. |
718 | + : |
719 | + : @param $request The request which need to be copied. |
720 | + : @return A copy of $request with all request//body/@method set. |
721 | + :) |
722 | +declare %private function http-wrapper:set-content-type( |
723 | + $request as element(http-schema:request)?) |
724 | + as element(http-schema:request)? { |
725 | + if ($request) then |
726 | + <http-schema:request>{$request/@*} |
727 | + { |
728 | + for $x in $request/node() |
729 | + return |
730 | + typeswitch($x) |
731 | + case element(http-schema:body) return http-wrapper:create-body($x) |
732 | + case element(http-schema:multipart) return http-wrapper:create-multipart($x) |
733 | + default return $x |
734 | + } |
735 | + </http-schema:request> |
736 | + else () |
737 | +}; |
738 | + |
739 | + |
740 | +(:~ |
741 | + : This function takes an http-schema:body element, copies it, and |
742 | + : adds a method attribute to the copy if there is none |
743 | + : in the original element. |
744 | + : |
745 | + : @param $body is the original http-schema:body element |
746 | + : @return a http-schema:body element with a corresponding <code>@method</code> |
747 | + : attribute |
748 | + :) |
749 | +declare %private function http-wrapper:create-body ( |
750 | + $body as element(http-schema:body)) |
751 | + as element(http-schema:body) { |
752 | + <http-schema:body>{$body/@*} |
753 | + { |
754 | + if ($body/@method) then |
755 | + () |
756 | + else |
757 | + attribute method { |
758 | + if ($body/@media-type eq "text/xml" or |
759 | + $body/@media-type eq "application/xml" or |
760 | + $body/@media-type eq "text/xml-external-parsed-entity" or |
761 | + $body/@media-type eq "application/xml-external-parsed-entity") then |
762 | + "xml" |
763 | + else if ($body/@media-type eq "text/html") then "html" |
764 | + else if (fn:starts-with($body/@media-type/data(.), "text/")) then "text" |
765 | + else "binary" |
766 | + } |
767 | + } |
768 | + {$body/node()} |
769 | + </http-schema:body> |
770 | +}; |
771 | + |
772 | +(:~ |
773 | + : This function takes an http-schema:multipart element, copies it and |
774 | + : adds a @method attribute to all body elements which don't have |
775 | + : one. |
776 | + : |
777 | + : @param $multipart the original http-schema:multipart |
778 | + : @return a copy of $multipart with all $multipart/body/@method set |
779 | + :) |
780 | +declare %private function http-wrapper:create-multipart ( |
781 | + $multipart as element(http-schema:multipart)) |
782 | + as element(http-schema:multipart) { |
783 | + <http-schema:multipart>{$multipart/@*} |
784 | + { |
785 | + for $x in $multipart/node() |
786 | + return |
787 | + typeswitch($x) |
788 | + case element(http-schema:body) return http-wrapper:create-body($x) |
789 | + default return $x |
790 | + } |
791 | + </http-schema:multipart> |
792 | +}; |
793 | |
794 | === modified file 'modules/http-client/xml/http-client.xq' |
795 | --- modules/http-client/xml/http-client.xq 2013-07-24 07:21:59 +0000 |
796 | +++ modules/http-client/xml/http-client.xq 2013-07-25 15:45:37 +0000 |
797 | @@ -251,6 +251,7 @@ |
798 | |
799 | import module namespace error = "http://expath.org/ns/error"; |
800 | import module namespace json-http = "http://zorba.io/modules/http-client"; |
801 | +import module namespace http-wrapper = "http://zorba.io/modules/http-client-wrapper"; |
802 | import module namespace libjn = "http://jsoniq.org/function-library"; |
803 | |
804 | import schema namespace http-schema = "http://expath.org/ns/http-client"; |
805 | @@ -304,25 +305,7 @@ |
806 | $href as xs:string?, |
807 | $bodies as item()*) as item()+ |
808 | { |
809 | - if (http:check-params($request, $href, $bodies)) |
810 | - then |
811 | - { |
812 | - variable $req := |
813 | - if ($request) |
814 | - then |
815 | - try |
816 | - { |
817 | - validate { http:set-content-type($request) } |
818 | - } |
819 | - catch XQDY0027 |
820 | - { |
821 | - fn:error($error:HC005, "The request element is not valid.") |
822 | - } |
823 | - else (); |
824 | - variable $result := http:http-sequential-impl($req, $href, $bodies); |
825 | - $result |
826 | - } |
827 | - else () |
828 | + http-wrapper:http-sequential-request($request, $href, $bodies) |
829 | }; |
830 | |
831 | |
832 | @@ -342,7 +325,7 @@ |
833 | :) |
834 | declare %an:nondeterministic function http:get($href as xs:string) as item()+ |
835 | { |
836 | - http:http-nondeterministic-impl(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true"/>}, (), ()) |
837 | + http-wrapper:http-nondeterministic-request(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true"/>}, (), ()) |
838 | }; |
839 | |
840 | (:~ |
841 | @@ -361,7 +344,7 @@ |
842 | :) |
843 | declare %an:nondeterministic function http:get-node($href as xs:string) as item()+ |
844 | { |
845 | - http:http-nondeterministic-impl(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="text/xml; charset=utf-8"/>}, (), ()) |
846 | + http-wrapper:http-nondeterministic-request(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="text/xml; charset=utf-8"/>}, (), ()) |
847 | }; |
848 | |
849 | (:~ |
850 | @@ -381,7 +364,7 @@ |
851 | :) |
852 | declare %an:nondeterministic function http:get-text($href as xs:string) as item()+ |
853 | { |
854 | - http:http-nondeterministic-impl(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="text/plain; charset=utf-8"/>}, (), ()) |
855 | + http-wrapper:http-nondeterministic-request(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="text/plain; charset=utf-8"/>}, (), ()) |
856 | }; |
857 | |
858 | (:~ |
859 | @@ -401,7 +384,7 @@ |
860 | :) |
861 | declare %an:nondeterministic function http:get-binary($href as xs:string) as item()+ |
862 | { |
863 | - http:http-nondeterministic-impl(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="binary"/>}, (), ()) |
864 | + http-wrapper:http-nondeterministic-request(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="binary"/>}, (), ()) |
865 | }; |
866 | |
867 | (:~ |
868 | @@ -418,7 +401,7 @@ |
869 | : @example test/rbkt/Queries/zorba/http-client/xml/head/head_status.xq |
870 | :) |
871 | declare %an:nondeterministic function http:head($href as xs:string) as item() { |
872 | - http:http-nondeterministic-impl( |
873 | + http-wrapper:http-nondeterministic-request( |
874 | validate { |
875 | <http-schema:request method="HEAD" href="{$href}"> |
876 | </http-schema:request> |
877 | @@ -438,7 +421,7 @@ |
878 | : @example test/rbkt/Queries/zorba/http-client/xml/options/options.xq |
879 | :) |
880 | declare %an:nondeterministic function http:options($href as xs:string) as xs:string* { |
881 | - let $resp := http:http-nondeterministic-impl( |
882 | + let $resp := http-wrapper:http-nondeterministic-request( |
883 | validate { |
884 | <http-schema:request method="OPTIONS" href="{$href}"> |
885 | </http-schema:request> |
886 | @@ -529,7 +512,7 @@ |
887 | case xs:base64Binary return "binary" |
888 | default return "text"; |
889 | |
890 | - variable $result := http:http-sequential-impl(validate { |
891 | + variable $result := http-wrapper:http-sequential-request(validate { |
892 | <http-schema:request href="{$href}" method="PUT"> |
893 | <http-schema:body media-type="{$content-type}" method="{$method}">{$body}</http-schema:body> |
894 | </http-schema:request>} |
895 | @@ -553,7 +536,7 @@ |
896 | :) |
897 | declare %an:sequential function http:delete($href as xs:string) as item()+ |
898 | { |
899 | - http:http-sequential-impl( |
900 | + http-wrapper:http-sequential-request( |
901 | validate { |
902 | <http-schema:request method="DELETE" href="{$href}"> |
903 | </http-schema:request> |
904 | @@ -642,7 +625,7 @@ |
905 | case xs:base64Binary return "binary" |
906 | default return "text"; |
907 | |
908 | - variable $result := http:http-sequential-impl(validate { |
909 | + variable $result := http-wrapper:http-sequential-request(validate { |
910 | <http-schema:request href="{$href}" method="POST"> |
911 | <http-schema:body media-type="{$content-type}" method="{$method}">{$body}</http-schema:body> |
912 | </http-schema:request>} |
913 | @@ -650,650 +633,3 @@ |
914 | |
915 | $result |
916 | }; |
917 | - |
918 | -(:~ |
919 | - : This function takes an http-schema:body element, copies it, and |
920 | - : adds a method attribute to the copy if there is none |
921 | - : in the original element. |
922 | - : |
923 | - : @param $body is the original http-schema:body element |
924 | - : @return a http-schema:body element with a corresponding <code>@method</code> |
925 | - : attribute |
926 | - :) |
927 | -declare %private function http:create-body ( |
928 | - $body as element(http-schema:body)) |
929 | - as element(http-schema:body) { |
930 | - <http-schema:body>{$body/@*} |
931 | - { |
932 | - if ($body/@method) then |
933 | - () |
934 | - else |
935 | - attribute method { |
936 | - if ($body/@media-type eq "text/xml" or |
937 | - $body/@media-type eq "application/xml" or |
938 | - $body/@media-type eq "text/xml-external-parsed-entity" or |
939 | - $body/@media-type eq "application/xml-external-parsed-entity") then |
940 | - "xml" |
941 | - else if ($body/@media-type eq "text/html") then "html" |
942 | - else if (fn:starts-with($body/@media-type/data(.), "text/")) then "text" |
943 | - else "binary" |
944 | - } |
945 | - } |
946 | - {$body/node()} |
947 | - </http-schema:body> |
948 | -}; |
949 | - |
950 | -(:~ |
951 | - : This function takes an http-schema:multipart element, copies it and |
952 | - : adds a @method attribute to all body elements which don't have |
953 | - : one. |
954 | - : |
955 | - : @param $multipart the original http-schema:multipart |
956 | - : @return a copy of $multipart with all $multipart/body/@method set |
957 | - :) |
958 | -declare %private function http:create-multipart ( |
959 | - $multipart as element(http-schema:multipart)) |
960 | - as element(http-schema:multipart) { |
961 | - <http-schema:multipart>{$multipart/@*} |
962 | - { |
963 | - for $x in $multipart/node() |
964 | - return |
965 | - typeswitch($x) |
966 | - case element(http-schema:body) return http:create-body($x) |
967 | - default return $x |
968 | - } |
969 | - </http-schema:multipart> |
970 | -}; |
971 | - |
972 | - |
973 | -(:~ |
974 | - : This adds a default method attribute to all body elements which |
975 | - : don't contain a method attribute. |
976 | - : |
977 | - : @param $request The request which need to be copied. |
978 | - : @return A copy of $request with all request//body/@method set. |
979 | - :) |
980 | -declare %private function http:set-content-type( |
981 | - $request as element(http-schema:request)?) |
982 | - as element(http-schema:request)? { |
983 | - if ($request) then |
984 | - <http-schema:request>{$request/@*} |
985 | - { |
986 | - for $x in $request/node() |
987 | - return |
988 | - typeswitch($x) |
989 | - case element(http-schema:body) return http:create-body($x) |
990 | - case element(http-schema:multipart) return http:create-multipart($x) |
991 | - default return $x |
992 | - } |
993 | - </http-schema:request> |
994 | - else () |
995 | -}; |
996 | - |
997 | -(:~ |
998 | - : Private function used internally by this module. |
999 | - : |
1000 | - : This function checks if the request, href, and bodies parameters |
1001 | - : are consistent. |
1002 | - : |
1003 | - : @param $request The request which needs to be checked. |
1004 | - : @param $href The href which needs to be checked. |
1005 | - : @param $bodies The bodies element which needs to be checked. |
1006 | - : @return true if the parameters are consistent. Otherwise, |
1007 | - : this function raises an error. |
1008 | - : |
1009 | - : @error error:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type). |
1010 | - : @error error:HC005 The specified request object is not valid. |
1011 | - : |
1012 | - :) |
1013 | -declare %private function http:check-params( |
1014 | - $request as element(http-schema:request)?, |
1015 | - $href as xs:string?, |
1016 | - $bodies as item()*) as xs:boolean { |
1017 | - let $multipart := $request/http-schema:multipart |
1018 | - let $override := $request/@override-media-type/string(.) |
1019 | - let $should-be-empty := |
1020 | - for $x in $request//http-schema:body |
1021 | - return |
1022 | - if ($x/@src and fn:not((fn:count($x/@*) eq 2))) then 1 |
1023 | - else () |
1024 | - return |
1025 | - if (fn:empty($href) and fn:empty($request)) then |
1026 | - fn:error($error:HC005, "The request element is not valid.") |
1027 | - else if ($href eq "") then |
1028 | - fn:error($error:HC005, "The request element is not valid.") |
1029 | - else if (not(count($request//http-schema:body[not(exists(node())) and not(exists(@src))]) eq count($bodies))) then |
1030 | - fn:error($error:HC005, "The request element is not valid.") |
1031 | - else if ($should-be-empty) then |
1032 | - fn:error($error:HC004, "The src attribute on the body element is mutually exclusive with all other attributes (except the media-type).") |
1033 | - else |
1034 | - fn:true() |
1035 | -}; |
1036 | - |
1037 | - |
1038 | -(: |
1039 | - : JSON Response to XML Response Conversion |
1040 | - :) |
1041 | - |
1042 | -(:~ |
1043 | - : Private function used internally by this module. |
1044 | - : |
1045 | - : This function accepts a JSON HTTP module response, as |
1046 | - : used by the http://zorba.io/modules/http-client module |
1047 | - : and returns its EXPath XML representation. |
1048 | - : |
1049 | - : @param $response a JSON response representation. |
1050 | - : @param $override-media-type if specified, is used in place of all |
1051 | - : body media-types in the response. |
1052 | - : @return EXPath XML response representation. |
1053 | - : @error error:HC002 Error parsing the response content as XML. |
1054 | - :) |
1055 | -declare %private function http:xml-response($response as object(), $override-media-type as xs:string?) as item()+ |
1056 | -{ |
1057 | - validate |
1058 | - { |
1059 | - element http-schema:response |
1060 | - { |
1061 | - attribute message {$response("message")}, |
1062 | - attribute status {$response("status")}, |
1063 | - http:xml-headers($response("headers")), |
1064 | - http:xml-body($response("body")), |
1065 | - http:xml-multipart($response("multipart")) |
1066 | - } |
1067 | - }, |
1068 | - http:get-bodies(libjn:descendant-objects($response)("body"), $override-media-type) |
1069 | -}; |
1070 | - |
1071 | -(:~ |
1072 | - : Private function used internally by this module. |
1073 | - : |
1074 | - : This function accepts a JSON HTTP module response, as |
1075 | - : used by the http://zorba.io/modules/http-client module |
1076 | - : and returns its EXPath XML representation. |
1077 | - : |
1078 | - : If the body media-type indicates that the response body |
1079 | - : has an XML content, the response body is parsed as XML |
1080 | - : before being returned. |
1081 | - : |
1082 | - : @param $bodies a sequence JSON bodies. |
1083 | - : @param $override-media-type if specified, is used in place of all body media-types. |
1084 | - : @return body contents. |
1085 | - : @error error:HC002 Error parsing the response content as XML. |
1086 | - :) |
1087 | -declare %private function http:get-bodies($bodies as object()*, $override-media-type as xs:string?) as item()* |
1088 | -{ |
1089 | - for $body in $bodies |
1090 | - let $media-type := ($override-media-type, $body("media-type"))[1] |
1091 | - let $mime-type := if (fn:contains($media-type,";")) |
1092 | - then fn:substring-before($media-type,";") |
1093 | - else $media-type |
1094 | - return |
1095 | - if ($mime-type eq "text/xml" or |
1096 | - $mime-type eq "application/xml" or |
1097 | - $mime-type eq "text/xml-external-parsed-entity" or |
1098 | - $mime-type eq "application/xml-external-parsed-entity" or |
1099 | - fn:ends-with($mime-type,"+xml")) |
1100 | - then |
1101 | - try { |
1102 | - parse-xml($body("content"))} |
1103 | - catch FODC0006 { |
1104 | - fn:error($error:HC002, "Error parsing the response content as XML.")} |
1105 | - else $body("content") |
1106 | -}; |
1107 | - |
1108 | -(:~ |
1109 | - : Private function used internally by this module. |
1110 | - : |
1111 | - : This function accepts the headers portion of a JSON HTTP module |
1112 | - : response, as used by the http://zorba.io/modules/http-client module |
1113 | - : and returns its EXPath XML representation. |
1114 | - : |
1115 | - : @param $headers JSON representation of an headers set. |
1116 | - : @return XML representation of the given headers. |
1117 | - :) |
1118 | -declare %private function http:xml-headers($headers as object()?) as element()* |
1119 | -{ |
1120 | - if (exists($headers)) |
1121 | - then |
1122 | - for $header-name in jn:keys($headers) |
1123 | - return |
1124 | - element http-schema:header |
1125 | - { |
1126 | - attribute name {$header-name}, |
1127 | - attribute value {$headers($header-name)} |
1128 | - } |
1129 | - else () |
1130 | -}; |
1131 | - |
1132 | - |
1133 | -(:~ |
1134 | - : Private function used internally by this module. |
1135 | - : |
1136 | - : This function accepts the body portion of a JSON HTTP module |
1137 | - : response, as used by the http://zorba.io/modules/http-client module |
1138 | - : and returns its EXPath XML representation. |
1139 | - : |
1140 | - : @param $body JSON representation of a body. |
1141 | - : @return XML representation of the given body. |
1142 | - :) |
1143 | -declare %private function http:xml-body($body as object()?) as element()? |
1144 | -{ |
1145 | - if(exists($body)) |
1146 | - then |
1147 | - element http-schema:body |
1148 | - { |
1149 | - attribute media-type {$body("media-type")} |
1150 | - } |
1151 | - else () |
1152 | -}; |
1153 | - |
1154 | -(:~ |
1155 | - : Private function used internally by this module. |
1156 | - : |
1157 | - : This function accepts the multipart portion of a JSON HTTP module |
1158 | - : response, as used by the http://zorba.io/modules/http-client module |
1159 | - : and returns its EXPath XML representation. |
1160 | - : |
1161 | - : @param $multipart JSON representation of a multipart. |
1162 | - : @return XML representation of the given multipart. |
1163 | - :) |
1164 | -declare %private function http:xml-multipart($multipart as object()?) as element()? |
1165 | -{ |
1166 | - if(exists($multipart)) |
1167 | - then |
1168 | - element http-schema:multipart |
1169 | - { |
1170 | - attribute media-type {$multipart("media-type")}, |
1171 | - |
1172 | - if ($multipart("boundary")) |
1173 | - then attribute boundary {$multipart("boundary")} |
1174 | - else (), |
1175 | - |
1176 | - for $part in jn:members($multipart("part")) |
1177 | - return |
1178 | - ( |
1179 | - http:xml-headers($part("headers")), |
1180 | - http:xml-body($part("body")) |
1181 | - ) |
1182 | - } |
1183 | - else () |
1184 | -}; |
1185 | - |
1186 | -(: |
1187 | - : XML Request to JSON Request |
1188 | - :) |
1189 | -(:~ |
1190 | - : Private function used internally by this module. |
1191 | - : |
1192 | - : This function accepts an XML EXPath HTTP request and returns its |
1193 | - : JSON representation, as used by the http://zorba.io/modules/http-client |
1194 | - : module. |
1195 | - : |
1196 | - : @param $request XML EXPath HTTP request. |
1197 | - : @param $href is the HTTP or HTTPS URI to send the request to. If specified, |
1198 | - : any href URI specified in the request element is ignored. |
1199 | - : @param $bodies the request bodies content. |
1200 | - : @return JSON HTTP request representation. |
1201 | - : |
1202 | - : @error error:HC005 The specified request object is not valid. |
1203 | - :) |
1204 | -declare %private function http:json-request($request as element()?, $href as xs:string?, $bodies as item()*) as item() |
1205 | -{ |
1206 | - if (http:check-params($request, $href, $bodies)) |
1207 | - then |
1208 | - { |
1209 | - variable $req := if ($request) |
1210 | - then try { |
1211 | - validate { http:set-content-type($request) }} |
1212 | - catch XQDY0027 { |
1213 | - fn:error($error:HC005, "The request element is not valid.")} |
1214 | - else (); |
1215 | - {| |
1216 | - |
1217 | - {"method": if ($req/@method) then $req/@method/string(.) else "GET"}, |
1218 | - |
1219 | - if ($href) |
1220 | - then {"href": $href} |
1221 | - else {"href": $req/@href/string(.)}, |
1222 | - |
1223 | - if ($request) |
1224 | - then |
1225 | - ( |
1226 | - http:json-authentication($request), |
1227 | - http:json-options($request), |
1228 | - http:json-headers($request/http-schema:header), |
1229 | - http:json-body($request/http-schema:body,$bodies), |
1230 | - http:json-multipart($request/http-schema:multipart,$bodies) |
1231 | - ) |
1232 | - else () |
1233 | - |
1234 | - |} |
1235 | - |
1236 | - } |
1237 | - else () |
1238 | - |
1239 | -}; |
1240 | - |
1241 | -(:~ |
1242 | - : Private function used internally by this module. |
1243 | - : |
1244 | - : This function accepts an XML EXPath HTTP request and returns the |
1245 | - : JSON representation of its authentication options, as used by the |
1246 | - : http://zorba.io/modules/http-client module. |
1247 | - : |
1248 | - : @param $request XML EXPath HTTP request. |
1249 | - : @return JSON HTTP request authentication representation. |
1250 | - :) |
1251 | -declare %private function http:json-authentication($request as element()) as object()? |
1252 | -{ |
1253 | - if (xs:boolean($request/@send-authorization/data(.))) |
1254 | - then |
1255 | - { |
1256 | - "authentication" : |
1257 | - { |
1258 | - "username": $request/@username/string(.), |
1259 | - "password": $request/@password/string(.), |
1260 | - "auth-method": $request/@auth-method/string(.) |
1261 | - } |
1262 | - } |
1263 | - else () |
1264 | -}; |
1265 | - |
1266 | - |
1267 | -(:~ |
1268 | - : Private function used internally by this module. |
1269 | - : |
1270 | - : This function accepts an XML EXPath HTTP request and returns the |
1271 | - : JSON representation of its options, as used by the |
1272 | - : http://zorba.io/modules/http-client module. |
1273 | - : |
1274 | - : @param $request XML EXPath HTTP request. |
1275 | - : @return JSON HTTP request options representation. |
1276 | - :) |
1277 | -declare %private function http:json-options($request as element()) as object()? |
1278 | -{ |
1279 | - if ($request/@status-only || $request/@override-media-type || |
1280 | - $request/@follow-redirect || $request/@timeout || $request/@user-agent) |
1281 | - then |
1282 | - { |
1283 | - "options": |
1284 | - { |
1285 | - {| |
1286 | - if ($request/@status-only) |
1287 | - then {"status-only": xs:boolean($request/@status-only/data(.))} |
1288 | - else (), |
1289 | - |
1290 | - if ($request/@override-media-type) |
1291 | - then {"override-media-type": $request/@override-media-type/string(.)} |
1292 | - else (), |
1293 | - |
1294 | - if ($request/@follow-redirect) |
1295 | - then {"follow-redirect": xs:boolean($request/@follow-redirect/data(.))} |
1296 | - else (), |
1297 | - |
1298 | - if ($request/@timeout) |
1299 | - then {"timeout": $request/@timeout/data(.)} |
1300 | - else (), |
1301 | - |
1302 | - if ($request/@user-agent) |
1303 | - then {"user-agent": $request/@user-agent/string(.)} |
1304 | - else () |
1305 | - |} |
1306 | - } |
1307 | - } |
1308 | - else () |
1309 | -}; |
1310 | - |
1311 | - |
1312 | -(:~ |
1313 | - : Private function used internally by this module. |
1314 | - : |
1315 | - : This function accepts a sequence of headers in the XML EXPath HTTP request |
1316 | - : format and returns their JSON representation, as used by the |
1317 | - : http://zorba.io/modules/http-client module. |
1318 | - : |
1319 | - : @param $headers XML EXPath HTTP headers. |
1320 | - : @return JSON HTTP request headers representation. |
1321 | - :) |
1322 | -declare %private function http:json-headers($headers as element()*) as object()? |
1323 | -{ |
1324 | - if ($headers) |
1325 | - then |
1326 | - { |
1327 | - "headers": |
1328 | - {| |
1329 | - for $header in $headers |
1330 | - group by $name := $header/@name |
1331 | - return {$name: string-join($header/@value,",")} |
1332 | - |} |
1333 | - } |
1334 | - else () |
1335 | -}; |
1336 | - |
1337 | - |
1338 | -(:~ |
1339 | - : Private function used internally by this module. |
1340 | - : |
1341 | - : This function accept a body element in the XML EXPath HTTP request |
1342 | - : format and returns its JSON representation, as used by the |
1343 | - : http://zorba.io/modules/http-client module. |
1344 | - : |
1345 | - : @param $body XML EXPath HTTP body element. |
1346 | - : @param $content body content. |
1347 | - : @return JSON HTTP request headers representation. |
1348 | - :) |
1349 | -declare %private function http:json-body($body as element()?, $content as item()*) as object()? |
1350 | -{ |
1351 | - if ($body) |
1352 | - then |
1353 | - { |
1354 | - "body": |
1355 | - {| |
1356 | - {"media-type": $body/@media-type/string(.)}, |
1357 | - |
1358 | - if ($body/@src) |
1359 | - then {"src": $body/@src/string(.)} |
1360 | - else {"content": http:produce-content($body,$content)} |
1361 | - |} |
1362 | - } |
1363 | - else () |
1364 | -}; |
1365 | - |
1366 | -(:~ |
1367 | - : Private function used internally by this module. |
1368 | - : |
1369 | - : This function serializes a request body. |
1370 | - : |
1371 | - : @param $body request contents. |
1372 | - : @return serialized body. |
1373 | - :) |
1374 | -declare %private function http:produce-content($body as element(), $content as item()*) as xs:string |
1375 | -{ |
1376 | - let $request-body := if ($body/node()) |
1377 | - then $body/node() |
1378 | - else $content |
1379 | - return |
1380 | - if ($body/@method eq "binary") |
1381 | - then if ($request-body instance of xs:base64Binary or $request-body instance of xs:hexBinary) |
1382 | - then $request-body |
1383 | - else |
1384 | - copy $serialization-parameters := http:serialization-parameters($body) |
1385 | - modify delete node $serialization-parameters/ser:method |
1386 | - return fn:serialize($request-body,$serialization-parameters) |
1387 | - else fn:serialize($request-body, http:serialization-parameters($body)) |
1388 | -}; |
1389 | - |
1390 | - |
1391 | -(:~ |
1392 | - : Private function used internally by this module. |
1393 | - : |
1394 | - : This function accept a body element in the XML EXPath HTTP request |
1395 | - : format and returns the serializer parameters to be used to serialize |
1396 | - : its content. |
1397 | - : |
1398 | - : @param $body XML EXPath HTTP body element. |
1399 | - : @return serializer parameters. |
1400 | - :) |
1401 | -declare %private function http:serialization-parameters($body as element()) as element() |
1402 | -{ |
1403 | - element ser:serialization-parameters |
1404 | - { |
1405 | - http:default-serialization-parameters($body), |
1406 | - for $option in $body/(@method | @byte-order-mark | @cdata-section-elements | |
1407 | - @doctype-public | @doctype-system | @encoding | |
1408 | - @escape-uri-attributes | @indent |@normalization-form | |
1409 | - @omit-xml-declaration | @standalone | @suppress-indentation | |
1410 | - @undeclare-prefixes | @version) |
1411 | - return |
1412 | - element {QName("http://www.w3.org/2010/xslt-xquery-serialization",local-name($option))} |
1413 | - {attribute value {$option/string(.)}} |
1414 | - } |
1415 | -}; |
1416 | - |
1417 | -(:~ |
1418 | - : Private function used internally by this module. |
1419 | - : |
1420 | - : This function return this module default serialization parameters. |
1421 | - : |
1422 | - : @param $body XML EXPath HTTP body element. |
1423 | - : @return serializer parameters. |
1424 | - :) |
1425 | -declare %private function http:default-serialization-parameters($body as element()) as element()* |
1426 | -{ |
1427 | - if ($body/@method/string(.) eq "xml") |
1428 | - then |
1429 | - ( |
1430 | - if ($body/@omit-xml-declaration) |
1431 | - then () |
1432 | - else |
1433 | - element {QName("http://www.w3.org/2010/xslt-xquery-serialization","omit-xml-declaration")} |
1434 | - {attribute value {"no"}} |
1435 | - ) |
1436 | - else () |
1437 | -}; |
1438 | - |
1439 | -(:~ |
1440 | - : Private function used internally by this module. |
1441 | - : |
1442 | - : This function accept a multipart element in the XML EXPath HTTP request |
1443 | - : format and returns its JSON representation, as used by the |
1444 | - : http://zorba.io/modules/http-client module. |
1445 | - : |
1446 | - : @param $multipart XML EXPath HTTP multipart element. |
1447 | - : @param $bodies multipart bodies content. |
1448 | - : @return JSON HTTP request multipart representation. |
1449 | - :) |
1450 | -declare %private function http:json-multipart($multipart as element()?, $bodies as item()*) as object()? |
1451 | -{ |
1452 | - if ($multipart) |
1453 | - then |
1454 | - { |
1455 | - "multipart": |
1456 | - {| |
1457 | - {"media-type": $multipart/@media-type/string(.)}, |
1458 | - |
1459 | - if ($multipart/@boundary) |
1460 | - then {"boundary": $multipart/@boundary/string(.)} |
1461 | - else (), |
1462 | - |
1463 | - {"parts": |
1464 | - [ |
1465 | - let $requests:= $multipart/* |
1466 | - for $part in $requests |
1467 | - group by $bodies-before:= count($requests[local-name(.) eq "body" and . << $part]) |
1468 | - return |
1469 | - let $content := |
1470 | - if ($part/self::http-schema:body/@src) |
1471 | - then () (: The content will be downloaded from the "src" url :) |
1472 | - else if ($part/self::http-schema:body/node()) |
1473 | - then ($part/self::http-schema:body/node()) (: the content is made by the body children :) |
1474 | - else (: the content is the 1+n-th body item, where n is the number of parts |
1475 | - before the current one which body has no src attributes and no childrens :) |
1476 | - ($bodies[1+count($requests[local-name(.) eq "body" and |
1477 | - not(@content) and not(node()) and . << $part/self::http-schema:body])]) |
1478 | - return http:json-part($part/self::http-schema:header, $part/self::http-schema:body, $content) |
1479 | - ]} |
1480 | - |} |
1481 | - } |
1482 | - else () |
1483 | -}; |
1484 | - |
1485 | -(:~ |
1486 | - : Private function used internally by this module. |
1487 | - : |
1488 | - : This function accept a part headers, body and content in the XML |
1489 | - : EXPath HTTP request format and returns its JSON representation, as |
1490 | - : used by the http://zorba.io/modules/http-client module. |
1491 | - : |
1492 | - : @param $headers XML EXPath HTTP header elements. |
1493 | - : @param $body XML EXPath HTTP body element. |
1494 | - : @param $content XML EXPath HTTP body content. |
1495 | - : @return JSON HTTP request part representation. |
1496 | - :) |
1497 | -declare %private function http:json-part($headers as element()*, $body as element(), $content as item()*) as item() |
1498 | -{ |
1499 | - {| |
1500 | - http:json-headers($headers), |
1501 | - http:json-body($body,$content) |
1502 | - |} |
1503 | -}; |
1504 | - |
1505 | -declare %private %an:sequential function http:http-sequential-impl( |
1506 | - $request as schema-element(http-schema:request)?, |
1507 | - $href as xs:string?, |
1508 | - $bodies as item()*) as item()+ |
1509 | -{ |
1510 | - try |
1511 | - { |
1512 | - { |
1513 | - variable $json-request := http:json-request($request, $href, $bodies); |
1514 | - variable $json-response := json-http:send-request($json-request); |
1515 | - variable $xml-response := http:xml-response($json-response, fn:data($request/@override-media-type)); |
1516 | - $xml-response |
1517 | - } |
1518 | - (:} catch XPTY0004 { |
1519 | - fn:error($error:HC005, "The input request element is not valid."):) |
1520 | - } catch json-http:HTTP { |
1521 | - fn:error($error:HC001, "An HTTP error occurred.") |
1522 | - } catch json-http:REQUEST { |
1523 | - fn:error($error:HC005, "The input request element is not valid.") |
1524 | - } catch json-http:TIMEOUT { |
1525 | - fn:error($error:HC006, "A timeout occurred waiting for the response.") |
1526 | - } catch json-http:FOLLOW { |
1527 | - fn:error($error:HCV02, "Trying to follow a redirect of a POST, PUT, or DELETE request.") |
1528 | - } catch json-http:CHARSET { |
1529 | - fn:error($error:HC005, "The input request element is not valid: invalid charset specified.") |
1530 | - } (:catch * { |
1531 | - fn:error(fn:QName($error:errNS, fn:local-name-from-QName($err:code)),$err:description, $err:value) |
1532 | - }:) |
1533 | -}; |
1534 | - |
1535 | -declare %private %an:nondeterministic function http:http-nondeterministic-impl( |
1536 | - $request as schema-element(http-schema:request)?, |
1537 | - $href as xs:string?, |
1538 | - $bodies as item()*) as item()+ |
1539 | -{ |
1540 | - try |
1541 | - { |
1542 | - { |
1543 | - variable $json-request := http:json-request($request, $href, $bodies); |
1544 | - variable $json-response := json-http:send-nondeterministic-request($json-request); |
1545 | - variable $xml-response := http:xml-response($json-response, fn:data($request/@override-media-type)); |
1546 | - $xml-response |
1547 | - } |
1548 | - } catch XPTY0004 { |
1549 | - fn:error($error:HC005, "The input request element is not valid.") |
1550 | - } catch json-http:HTTP { |
1551 | - fn:error($error:HC001, "An HTTP error occurred.") |
1552 | - } catch json-http:REQUEST { |
1553 | - fn:error($error:HC005, "The input request element is not valid.") |
1554 | - } catch json-http:TIMEOUT { |
1555 | - fn:error($error:HC006, "A timeout occurred waiting for the response.") |
1556 | - } catch json-http:FOLLOW { |
1557 | - fn:error($error:HCV02, "Trying to follow a redirect of a POST, PUT, or DELETE request.") |
1558 | - } catch json-http:CHARSET { |
1559 | - fn:error($error:HC005, "The input request element is not valid: invalid charset specified.") |
1560 | - } catch * { |
1561 | - fn:error(fn:QName($error:errNS, fn:local-name-from-QName($err:code)),$err:description, $err:value) |
1562 | - } |
1563 | -}; |
To avoid replicating conversion code (600-700 lines) between the core XML http client and the Expath http client as discussed in: https:/ /code.launchpad .net/~zorba- coders/ zorba/http- client- based-on- json-http- client/ +merge/ 169578 I introduced a wrapper module for doing all conversions.