Merge lp:~zorba-coders/zorba/http-client-wrapper into lp:zorba

Proposed by Federico Cavalieri
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
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

To post a comment you must log in.
Revision history for this message
Federico Cavalieri (fcavalieri) wrote :

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.

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/http-client-wrapper/+merge/176980

Progress dashboard at http://jenkins.lambda.nu/view/ValidationQueue

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Voting criteria failed for the following merge proposals:

https://code.launchpad.net/~zorba-coders/zorba/http-client-wrapper/+merge/176980 :
Votes: {'Pending': 2, 'Needs commit message': 1}

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/http-client-wrapper/+merge/176980

Stage "CommitZorba" failed.

Check console output at http://jenkins.lambda.nu/job/CommitZorba/57/console to view the results.

Revision history for this message
Chris Hillery (ceejatec) :
review: Approve
Revision history for this message
Cezar Andrei (cezar-andrei) :
review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/http-client-wrapper/+merge/176980

Progress dashboard at http://jenkins.lambda.nu/view/ValidationQueue

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/http-client-wrapper/+merge/176980

Stage "AddTestSuitesUbuntu" failed.

Check console output at http://jenkins.lambda.nu/job/AddTestSuitesUbuntu/126/console to view the results.

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue succeeded - proposal merged!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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-};

Subscribers

People subscribed via source and target branches